Slovo
Slovo copied to clipboard
Искони бѣ Слово - already in production at https://слово.бг
=encoding utf8
=head1 NAME
Slovo - Искони бѣ Слово
=head1 SYNOPSIS
Install Slovo locally with all dependencies in less than two minutes
time curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org \
-q -n -l ~/opt/slovo Slovo
Run slovo for the first time in debug mode
morbo ~/opt/slovo/bin/slovo
Visit Lhttp://127.0.0.1:3000. For help visit Lhttp://127.0.0.1:3000/perldoc.
=head1 DESCRIPTION
L<Slovo> is a simple to install and extensible L<Mojolicious> L<CMS|https://en.wikipedia.org/wiki/Web_content_management_system> with nice core features, listed below.
This is a usable release, yet B
=over
=item * On the fly generation of static pages under Apache/CGI – perfect for cheap shared hosting and blogging – BETA;
=item * Multi-domain support - BETA;
=item * Multi-language pages - WIP;
=item * Cached published pages and content - DONE;
=item * Multi-user support - DONE;
=item * User onboarding - WIP;
=item * User sign in - DONE;
=item * Managing pages, content, domains, users - WIP;
=item * Managing groups - BASIC;
=item * Multiple groups per user - DONE;
=item * Ownership and permissions management per page and it's content - BETA;
=item * Automatic 301 and 308 (Moved Permanently) redirects for renamed pages and content - DONE;
=item * Embedded fonts for displaying all L<Azbuka|https://en.wikipedia.org/wiki/Cyrillic_script> and L<Glagolitsa|https://en.wikipedia.org/wiki/Glagolitic_script> characters - DONE;
=item * OpenAPI 2/3.0 (Swagger) REST API - BASIC;
=item * Embedded Trumbowyg - L<A lightweight WYSIWYG editor|https://alex-d.github.io/Trumbowyg/>;
=item * Embedded Editor.md - L<The open source embeddable online markdown editor (component), based on CodeMirror & jQuery & Marked|http://editor.md.ipandao.com/>;
=item * Example startup scripts for slovo and slovo_minion services for L<systemd|https://freedesktop.org/wiki/Software/systemd/>, L<Apache 2.4|https://httpd.apache.org/docs/2.4/> and NGINX vhost configuration files.
=item * Inflatable embedded themes support - BETA;
=item * and more to come…
=back
By default Slovo comes with SQLite database, but support for PostgreSQL or MySQL is about to be added when needed. It is just a question of making compatible and/or translating some limited number of SQL queries to the corresponding SQL dialects. Contributors are welcome.
The word "slovo" (слово) has one unchanged meaning during the last millennium among all slavic languages. It is actually one language that started splitting apart less than one thousand years ago. The meaning is "word" – the God's word (when used with capital letter). Hence the self-naming of this group of people C<qr/sl(o|a)v(e|a|i)n(i|y|e)/> - people who have been given the God's word or people who can speak. All others were considered "mute", hence the naming (немци)...
=head1 INSTALL
All you need is a one-liner, it takes less than a minute.
$ curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org -n -l ~/opt/slovo Slovo
We recommend the use of a L<Perlbrew|http://perlbrew.pl> environment.
If you already downloaded it and you have L
$ cpanm -l ~/opt/slovo Slovo-XXXX.XX.XX.tar.gz
Or even if you don't have C
tar zxf Slovo-XXXX.XX.XX.tar.gz
cd Slovo-XXXX.XX.XX
INSTALL_BASE=~/opt/slovo && rm -rf $INSTALL_BASE && make distclean; \
perl Makefile.PL INSTALL_BASE=$INSTALL_BASE && make && make test && make install \
&& $INSTALL_BASE/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});' \
&& $INSTALL_BASE/bin/slovo
Use cpanm to install or update into a custom location as self contained application and run slovo to see how it's going.
# From metacpan. org
export PREFIX=~/opt/slovo;
cpanm -M https://cpan.metacpan.org -n --self-contained -l $PREFIX Slovo \
$PREFIX/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});' \
$PREFIX/bin/slovo
# From the directory where you unpacked Slovo
export PREFIX=~/opt/slovo;
cpanm . -n --self-contained -l $PREFIX Slovo
$PREFIX/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});'
$PREFIX/bin/slovo
Start the development server and open a browser
morbo ./script/slovo -l http://*:3000 & sleep 1 exo-open http://localhost:3000
=head1 USAGE
cd /path/to/installed/slovo
# ...and see various options
./bin/slovo
=head1 CONFIGURATION, PATHS and UPGRADING
L<Slovo> is a L<Mojolicious> application which means that everything
applying to Mojolicious applies to it too. Slovo main configuration file is
in C<lib/Slovo/resourses/etc/slovo.conf>. You can use your own by setting
C<$ENV{MOJO_CONFIG}> or by just copying C<slovo.conf> to $ENV{MOJO_HOME} and
modify it as you wish. Routes can be added or removed in C<routes.conf>. See
LMojolicious::Plugin::RoutesConfig for details and examples. New plugins can
be added per deployment in C
C<$ENV{MOJO_HOME}> (L<where you installed Slovo|/home>) is automatically detected and used. All paths, used in the application, are expected to be its children. You can add your own templates in C<$ENV{MOJO_HOME}/templates> and they will be loaded and used with priority. You can theme your own instance of Slovo by just copying C<$ENV{MOJO_HOME}/lib/Slovo/resources/templates> to C<$ENV{MOJO_HOME}/templates> and modify them. You can add your own static files to C<$ENV{MOJO_HOME}/public>. You can create custom themes by forking LSlovo::Themes::Malka and using it as a starting point.
You can have separate static files and templates per domain under C<$ENV{MOJO_HOME}/domove/your.domain/public>, C<$ENV{MOJO_HOME}/domove/your.other.domain/templates>, etc. See C<$ENV{MOJO_HOME}/domove/localhost> for example.
You can switch between different themes by just selecting the theme in the form for editing domains.
Last but not least, you can add your own classes into C<$ENV{MOJO_HOME}/site/lib> and (why not) replace entirely some Slovo classes or just extend them. C<$ENV{MOJO_HOME}/bin/slovo> will load them with priority.
With all the above, you can upgrade L<Slovo> by just installing new versions over it and your files will not be touched. And of course, we know that you are using versioning just in case anything goes wrong. See L.
=head1 ATTRIBUTES
L<Slovo> inherits all attributes from L<Mojolicious> and implements the following new ones.
=head2 home
L<Slovo> detects where B
Examples:
berov@Skylake:Slovo$ pwd
/home/berov/opt/dev/Slovo
berov@Skylake:Slovo$ perl script/slovo eval 'say app->home'
/home/berov/opt/dev/Slovo
berov@Skylake:Slovo$ cpanm . -n -l ~/opt/t.com/slovo
--> Working on .
Configuring /home/berov/opt/dev/Slovo ... OK
Building Slovo-v2019.06.09 ... OK
Successfully installed Slovo-v2019.06.09
1 distribution installed
berov@Skylake:t.com$ pwd
/home/berov/opt/t.com
berov@Skylake:t.com$ slovo/bin/slovo eval 'say app->home'
/home/berov/opt/t.com/slovo
berov@Skylake:t.com$ pwd
/home/berov/opt/t.com
berov@Skylake:t.com$ perl -Islovo/lib/perl5 -MSlovo -E 'say Slovo->new->home'
/home/berov/opt/t.com/slovo
=head2 log
Overrides L<Mojolicious/log>. Logs to C<self-E
=head2 resources
push @{$app->static->paths}, $app->resources->child('public');
Returns a LMojo::File instance for path L<Slovo/resources> next to where C<Slovo.pm> is installed.
=head2 validator
my $validator = $app->validator; $app = $app->validator(Slovo::Validator->new);
Validate values, defaults to a LSlovo::Validator object.
Add validation check
$app->validator->add_check(foo => sub { my ($v, $name, $value) = @_; return $value ne 'foo'; });
Add validation filter
$app->validator->add_filter(quotemeta => sub { my ($v, $name, $value) = @_; return quotemeta $value; });
=head1 METHODS
L<Slovo> inherits all methods from L<Mojolicious> and implements the following new ones.
=head2 load_class
A convenient wrapper with check for LMojo::Loader/load_class. Loads a class and croaks if something is wrong. This could be a helper.
for my $class (@{$config->{load_classes} // []}) { $app->load_class($class); }
=head2 startup
Starts the application. Adds hooks, prepares C<$app-E
=head1 HOOKS
Slovo adds custom code to the following hooks.
=head2 around_action
On each request we set the following variables in the stash so they are available in the respective templates. Here they are:
$stash->{l} //= $c->language; # current language
$stash->{user} //= $c->user; # current user
=head2 around_dispatch
On each request we determine the current host and modify the static and renderer paths accordingly. This is how each domain has its own templates and static files.
Also if the C
It is also important to note that in a long running application (not CGI) the templates are cached in memory and the relative path from the current templates root to each template is used as the key in LMojo::Cache cache. We had to implement LSlovo::Cache/key_prefix to be able to differentiate between templates having the same names, but found in different paths. All this is possible thanks to L<Mojolicious>'s well decoupled components.
Example: Let's suppose that the domain Lhttps://слово.бг has the field 'templates' value set to C<themes/malka> (малка==small f. in Bulgarian).
Renderer paths before the check is performed:
[ "/home/berov/opt/dev/Slovo/templates", "/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/templates", "/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates" ]
Static paths before the check:
[ "/home/berov/opt/dev/Slovo/public", "/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/public", "/home/berov/opt/dev/Slovo/lib/Slovo/resources/public" ]
Renderer paths after the check is performed. The first path in the list will be used with priority:
[ "/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates/themes/malka", # if exists! "/home/berov/opt/dev/Slovo/domove/xn--b1arjbl.xn--90ae/templates", # if exists! "/home/berov/opt/dev/Slovo/templates", "/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/templates", "/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates" ]
Static paths after the check:
[ "/home/berov/opt/dev/Slovo/domove/xn--b1arjbl.xn--90ae/public", # if exists! "/home/berov/opt/dev/Slovo/public", "/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/public", "/home/berov/opt/dev/Slovo/lib/Slovo/resources/public" ]
In addition the current domain row from table C
In a controller or model
$c->stash('domain')->{id}; $m->c->stash('domain')->{aliases};
In a template like
lib/Slovo/resources/templates/stranici/_form.html.ep
<%= select_box dom_id => $domove, required => 1, label => 'Дом', title => 'В кой сайт се намира страницата.', readonly => '', value => $domain->{id} #default value %>
=head2 before_dispatch
On each request we check if we have a logged in user and set the current user
to C
=head1 HELPERS
Slovo implements the following helpers.
=head2 openapi_spec
We need to have our OpenAPI API specification always at hand as a unified source of truth so here it is.
# anywhere via $app or $c, even not via a REST call
state $columns =
$c->openapi_spec('/paths/~1stranici/get/parameters/3/default');
[
"id",
"pid",
"alias",
"title",
"is_dir"
]
=head1 BUGS, SUPPORT, CONTRIBUTING, DISCUSS
To report a bug, please create issues at L<GitHub|https://github.com/kberov/Slovo/issues>, fork the project and make pull requests.
=head1 AUTHOR
Красимир Беров
CPAN ID: BEROV
berov на cpan точка org
http://i-can.eu
=head1 CONTRIBUTORS
Ordered by time of first commit.
=over
=item * MANWAR (Mohammad S Anwar)
=item * KABANOID (Mikhail Katasonov)
=item * 0xAF (Stanislav Lechev)
=back
=head1 COPYRIGHT
This is free software, licensed under:
The Artistic License 2.0 (GPL Compatible)
The full text of the license can be found in the LICENSE file included with this module.
This distribution contains other free software which belongs to their respective authors.
=head1 TODO
=over
=item * Stop adding features. Stabilize what we have.
=item * Gradually replace L<MUI CSS|https://www.muicss.com/> with L<Chota CSS|https://jenil.github.io/chota/> - site part is done.
=item * Considerably improve the Adminiastration UI - now it is quite simplistic. Use ES6 directly as per L<browsers compatibility table|https://kangax.github.io/compat-table/es6/>
=item * Consider using L<Mithril|https://github.com/MithrilJS/mithril.js> or L<Vue.js|https://vuejs.org/> or something light as frontend framework for building UI. We already use jQuery distributed with the Mojolicious distro.
=back
=head1 SEE ALSO
LSlovo::Plugin::TagHelpers, LSlovo::Plugin::DefaultHelpers, LSlovo::Validator, L<Mojolicious>, LMojolicious::Guides