package Mojolicious::Plugin::StaticShare; use Mojo::Base 'Mojolicious::Plugin'; use Mojo::File qw(path); use Mojolicious::Types; use Mojo::Path; use Mojo::Util qw(encode); our $VERSION = '0.055'; my $PKG = __PACKAGE__; has [qw(app config)]; has root_url => sub { Mojo::Path->new(encode('UTF-8', shift->config->{root_url}))->leading_slash(1)->trailing_slash(1) }; has root_dir => sub { Mojo::Path->new(shift->config->{root_dir} // '.')->trailing_slash(1) }; has admin_pass => sub { shift->config->{admin_pass} }; has public_uploads => sub { !! shift->config->{public_uploads} }; has render_dir => sub { shift->config->{render_dir} }; has dir_index => sub { shift->config->{dir_index} // [qw(README.md INDEX.md README.pod INDEX.pod)] }; has render_pod => sub { shift->config->{render_pod} }; has render_markdown => sub { shift->config->{render_markdown} }; has markdown_pkg => sub { shift->config->{markdown_pkg} // 'Text::Markdown::Hoedown' }; has markdown => sub {# parser object __internal__::Markdown->new(shift->markdown_pkg); }; has is_markdown => sub { qr{[.]m(?:d(?:own)?|kdn?|arkdown)$}i }; has is_pod => sub { qr{[.]p(?:od|m|l)$} }; has mime => sub { Mojolicious::Types->new }; sub register { my ($self, $app, $args) = @_; $self->config($args); $self->app($app); require Mojolicious::Plugin::StaticShare::Templates and push @{$app->renderer->classes}, "$PKG\::Templates" and push @{$app->static->paths}, path(__FILE__)->sibling('StaticShare')->child('static') unless ($self->render_dir // '') eq 0 && ($self->render_markdown // '') eq 0; my $route = $self->root_url->clone->merge('*pth');#"$args->{root_url}/*pth"; my $r = $app->routes; $r->get($self->root_url->to_route)->to(namespace=>$PKG, controller=>"Controller", action=>'get', pth=>'', plugin=>$self)->name("$PKG ROOT"); $r->post($self->root_url->to_route)->to(namespace=>$PKG, controller=>"Controller", action=>'post', pth=>'', plugin=>$self)->name("$PKG ROOT POST"); $r->get($route->to_route)->to(namespace=>$PKG, controller=>"Controller", action=>'get', plugin=>$self )->name("$PKG GET"); $r->post($route->to_route)->to(namespace=>$PKG, controller=>"Controller", action=>'post', plugin=>$self )->name("$PKG POST"); $app->helper(i18n => sub { &i18n(@_) }); #POD $self->app->plugin(PODRenderer => {no_perldoc => 1}) unless $self->app->renderer->helpers->{'pod_to_html'} && ($self->render_pod // '') eq 0 ; return $app; } my %loc = ( 'ru-ru'=>{ 'Not found'=>"Не найдено", 'Error on path'=>"Ошибка в", 'Error'=>"Ошибка", 'Permission denied'=>"Нет доступа", 'Cant open directory'=>"Нет доступа в папку", 'Share'=>'Обзор', 'Index of'=>'Содержание', 'Dirs'=>'Папки', 'Files'=>'Файлы', 'Name'=>'Название файла', 'Size'=>'Размер', 'Last Modified'=>'Дата изменения', 'Up'=>'Выше', 'Down'=>'Ниже', 'Add uploads'=>'Добавить файлы', 'Add dir'=>'Добавить папку', 'root'=>"корень", 'Uploading'=>'Загружается', 'file is too big'=>'слишком большой файл', 'path is not directory'=>"нет такого каталога/папки", 'file already exists' => "такой файл уже есть", 'new dir name'=>"имя новой папки", 'Confirm to delete these files'=>"Подтвердите удаление этих файлов", 'Confirm to delete these dirs'=>"Подтвердите удаление этих папок", 'I AM SURE'=>"ДА", }, ); sub i18n {# helper my ($c, $str, $lang) = @_; #~ $lang //= $c->stash('language'); return $str unless $c->stash('language'); my $loc; for ($c->stash('language')->languages) { return $str if /en/; $loc = $loc{$_} || $loc{lc $_} || $loc{lc "$_-$_"} and last; } return $loc->{$str} || $loc->{lc $str} || $str if $loc; return $str; } ############################################## package __internal__::Markdown; sub new { my $class = shift; my $pkg = shift; return unless eval "require $pkg; 1";# #~ $pkg->import #~ if $pkg->can('import'); return $pkg->new() if $pkg->can('new') && $pkg->can('parse'); return unless $pkg->can('markdown'); bless {pkg=>$pkg} => $class; } sub parse { my $self = shift; no strict 'refs'; ($self->{pkg}.'::markdown')->(@_); } 1; =pod =encoding utf8 Доброго всем =head1 Mojolicious::Plugin::StaticShare ¡ ¡ ¡ ALL GLORY TO GLORIA ! ! ! =head1 NAME Mojolicious::Plugin::StaticShare - browse, upload, copy, move, delete static files and dirs. =head1 VERSION 0.055 =head1 SYNOPSIS # Mojolicious $self->plugin('StaticShare', ); # Mojolicious::Lite plugin 'StaticShare', ; # oneliner $ perl -MMojolicious::Lite -E 'plugin("StaticShare", root_url=>"/my/share",)->secrets([rand])->start' daemon =head1 DESCRIPTION This plugin for share static files/dirs and has public and admin functionality: =head2 Public interface Can browse and upload files if name not exists. =head2 Admin interface Can copy, move, delete files/dirs. Append param C<< admin= option >> to any url inside B requests (see below). =head1 OPTIONS =head2 root_dir Absolute or relative file system path root directory. Defaults to '.'. root_dir => '/mnt/usb', root_dir => 'foo', =head2 root_url This prefix to url path. Defaults to '/'. root_url => '/', # mean route '/*pth' root_url => '', # mean also route '/*pth' root_url => '/my/share', # mean route '/my/share/*pth' See L. =head2 admin_pass Admin password (be sure https) for admin tasks. None defaults. admin_pass => '$%^!!9nes--', # Signin to admin interface C< https://myhost/my/share/foo/bar?admin=$%^!!9nes-- > =head2 render_dir Template path, format, handler, etc which render directory index. Defaults to builtin things. render_dir => 'foo/dir_index', render_dir => {template => 'foo/my_directory_index', foo=>...}, # Disable directory index rendering render_dir => 0, =head3 Usefull stash variables C, C, C, C, C, C, C =head4 pth Path of request exept C option, as L object. =head4 url_path Path of request with C option, as L object. =head4 language Req header AcceptLanguage as L object. =head4 dirs List of scalars dirnames. Not sorted. =head4 files List of hashrefs (C keys) files. Not sorted. =head4 index Filename for markdown or pod rendering in page below dirs and files. =head2 render_markdown Same as B but for markdown files. Defaults to builtin things. render_markdown => 'foo/markdown', render_markdown => {template => 'foo/markdown', foo=>...}, # Disable markdown rendering render_markdown => 0, =head2 markdown_pkg Module name for render markdown. Must contains sub C or method C. Defaults to L. markdown_pkg => 'Foo::Markup'; Does not need to install if C<< render_markdown => 0 >> or never render md files. =head2 render_pod Template path, format, handler, etc which render pod files. Defaults to builtin things. render_pod=>'foo/pod', render_pod => {template => 'foo/pod', layout=>'pod', foo=>...}, # Disable pod rendering render_pod => 0, =head2 dir_index Arrayref to match files to include to directory index page. Defaults to C<< [qw(README.md INDEX.md README.pod INDEX.pod)] >>. dir_index => [qw(DIR.md)], dir_index => 0, # disable include markdown to index dir page =head2 public_uploads Boolean to disable/enable uploads for public users. Defaults to undef (disable). public_uploads=>1, # enable =head1 UTF-8 Everywhere and everything: module, files, content. =head1 WINDOWS OS It was not tested but I hope you dont worry and have happy. =head1 Extended markdown & pod You can place classnames and css-style rules to markup elements as below. In markdown: # {.class1 .class2 padding: 0 0.5rem;} Header 1 {.brown-text} brown paragraph text ... In pod: =head2 {.class1 .blue-text border-bottom: 1px dotted;} Header 2 {.red-text} red color text... =head1 METHODS L inherits all methods from L and implements the following new ones. =head2 register $plugin->register(Mojolicious->new); Register plugin in L application. =head1 SEE ALSO L L, L, L. =head1 AUTHOR Михаил Че (Mikhail Che), C<< >> =head1 BUGS / CONTRIBUTING Please report any bugs or feature requests at L. Pull requests also welcome. =head1 COPYRIGHT Copyright 2017 Mikhail Che. This library is free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut