line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Slovo; |
2
|
14
|
|
|
14
|
|
1624836
|
use feature ':5.26'; |
|
14
|
|
|
|
|
37
|
|
|
14
|
|
|
|
|
1792
|
|
3
|
14
|
|
|
14
|
|
473
|
use Mojo::Base 'Mojolicious', -signatures; |
|
14
|
|
|
|
|
160526
|
|
|
14
|
|
|
|
|
107
|
|
4
|
|
|
|
|
|
|
|
5
|
14
|
|
|
14
|
|
1056344
|
use Mojo::Util 'class_to_path'; |
|
14
|
|
|
|
|
55
|
|
|
14
|
|
|
|
|
646
|
|
6
|
14
|
|
|
14
|
|
74
|
use Mojo::File 'path'; |
|
14
|
|
|
|
|
24
|
|
|
14
|
|
|
|
|
519
|
|
7
|
14
|
|
|
14
|
|
86
|
use Mojo::Collection 'c'; |
|
14
|
|
|
|
|
27
|
|
|
14
|
|
|
|
|
603
|
|
8
|
14
|
|
|
14
|
|
7524
|
use Slovo::Controller::Auth; |
|
14
|
|
|
|
|
35
|
|
|
14
|
|
|
|
|
275
|
|
9
|
14
|
|
|
14
|
|
6269
|
use Slovo::Validator; |
|
14
|
|
|
|
|
39
|
|
|
14
|
|
|
|
|
123
|
|
10
|
14
|
|
|
14
|
|
8745
|
use Slovo::Cache; |
|
14
|
|
|
|
|
34
|
|
|
14
|
|
|
|
|
100
|
|
11
|
14
|
|
|
14
|
|
6712
|
use Time::Piece; |
|
14
|
|
|
|
|
81750
|
|
|
14
|
|
|
|
|
73
|
|
12
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:BEROV'; |
14
|
|
|
|
|
|
|
our $VERSION = '2022.02.02'; |
15
|
|
|
|
|
|
|
our $CODENAME = 'U+2C15 GLAGOLITIC CAPITAL LETTER TVRIDO (Ⱅ)'; |
16
|
|
|
|
|
|
|
my $CLASS = __PACKAGE__; |
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
has resources => sub { |
19
|
|
|
|
|
|
|
path($INC{class_to_path $CLASS})->sibling("$CLASS/resources")->realpath; |
20
|
|
|
|
|
|
|
}; |
21
|
|
|
|
|
|
|
has validator => sub { Slovo::Validator->new }; |
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
# We prefer $MOJO_HOME to be the folder where the folders bin or script |
24
|
|
|
|
|
|
|
# reside. |
25
|
|
|
|
|
|
|
has home => sub { |
26
|
|
|
|
|
|
|
if ($ENV{MOJO_HOME}) { return Mojo::Home->new($ENV{MOJO_HOME}); } |
27
|
|
|
|
|
|
|
my $r = Mojo::Home->new($INC{class_to_path $CLASS})->dirname->to_abs; |
28
|
|
|
|
|
|
|
my $m = $_[0]->moniker; |
29
|
|
|
|
|
|
|
while (($r = $r->dirname) && @{$r->to_array} > 2) { |
30
|
|
|
|
|
|
|
if (-x $r->child("bin/$m") || -x $r->child("script/$m")) { |
31
|
|
|
|
|
|
|
return $r; |
32
|
|
|
|
|
|
|
} |
33
|
|
|
|
|
|
|
} |
34
|
|
|
|
|
|
|
return $_[0]->SUPER::home; |
35
|
|
|
|
|
|
|
}; |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
# Writes to $home/log/slovo.log if $home/log/ exists and is writable. |
38
|
|
|
|
|
|
|
has log => sub { |
39
|
|
|
|
|
|
|
my $self = shift; |
40
|
|
|
|
|
|
|
|
41
|
|
|
|
|
|
|
my $mode = $self->mode; |
42
|
|
|
|
|
|
|
my $log = Mojo::Log->new; |
43
|
|
|
|
|
|
|
|
44
|
|
|
|
|
|
|
my $home = $self->home; |
45
|
|
|
|
|
|
|
if (-d $home->child('log') && -w _) { |
46
|
|
|
|
|
|
|
$log->path($home->child('log', $self->moniker . ".log")); |
47
|
|
|
|
|
|
|
} |
48
|
|
|
|
|
|
|
|
49
|
|
|
|
|
|
|
# Reduced log output outside of development mode |
50
|
|
|
|
|
|
|
return $log->level($ENV{MOJO_LOG_LEVEL}) if $ENV{MOJO_LOG_LEVEL}; |
51
|
|
|
|
|
|
|
return $mode eq 'development' ? $log : $log->level('info'); |
52
|
|
|
|
|
|
|
}; |
53
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
# This method will run once at server start |
55
|
14
|
|
|
14
|
1
|
273225
|
sub startup ($app) { |
|
14
|
|
|
|
|
36
|
|
|
14
|
|
|
|
|
22
|
|
56
|
14
|
|
|
|
|
53
|
$app->log->debug("Starting $CLASS $VERSION|$CODENAME"); |
57
|
14
|
|
|
|
|
405
|
$app->controller_class('Slovo::Controller'); |
58
|
14
|
|
|
|
|
168
|
$app->commands->namespaces( |
59
|
|
|
|
|
|
|
['Slovo::Command::Author', 'Slovo::Command', 'Mojolicious::Command']); |
60
|
|
|
|
|
|
|
## no critic qw(Subroutines::ProtectPrivateSubs) |
61
|
14
|
|
|
|
|
1054
|
$app->hook(around_action => \&_around_action); |
62
|
14
|
|
|
|
|
168
|
$app->hook(around_dispatch => \&_around_dispatch); |
63
|
14
|
|
|
|
|
123
|
$app->hook(before_dispatch => \&_before_dispatch); |
64
|
14
|
|
|
|
|
136
|
$app->_set_routes_attrs->_load_config->_load_pugins->_default_paths->_add_media_types(); |
65
|
14
|
|
|
|
|
132
|
my $cache = Slovo::Cache->new(); |
66
|
14
|
|
|
|
|
44
|
$app->renderer->cache($cache); |
67
|
14
|
|
|
|
|
171
|
$app->routes->cache($cache); |
68
|
14
|
|
|
|
|
332
|
$app->defaults( |
69
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
# layout => 'default' |
71
|
|
|
|
|
|
|
boxes => $app->openapi_spec('/parameters/box/enum'), |
72
|
|
|
|
|
|
|
data_formats => $app->openapi_spec('/parameters/data_format/enum'), |
73
|
|
|
|
|
|
|
data_types => $app->openapi_spec('/parameters/data_type/enum'), |
74
|
|
|
|
|
|
|
lang => 'bg-bg', |
75
|
|
|
|
|
|
|
languages => $app->languages, # /parameters/language/enum |
76
|
|
|
|
|
|
|
page_types => $app->openapi_spec('/parameters/page_type/enum'), |
77
|
|
|
|
|
|
|
permissions => $app->openapi_spec('/parameters/permissions/enum'), |
78
|
|
|
|
|
|
|
stranici_columns => |
79
|
|
|
|
|
|
|
$app->openapi_spec('/paths/~1stranici/get/parameters/4/items/enum'), |
80
|
|
|
|
|
|
|
); |
81
|
14
|
|
|
|
|
3289
|
return $app; |
82
|
|
|
|
|
|
|
} |
83
|
|
|
|
|
|
|
|
84
|
143
|
|
|
143
|
|
4268
|
sub _before_dispatch ($c) { |
|
143
|
|
|
|
|
228
|
|
|
143
|
|
|
|
|
179
|
|
85
|
143
|
|
|
|
|
311
|
state $guest = $c->users->find_by_login_name('guest'); |
86
|
6
|
|
|
|
|
439
|
state $auth_config = c(@{$c->config('load_plugins')})->first(sub { |
87
|
18
|
50
|
|
18
|
|
518
|
ref $_ eq 'HASH' and exists $_->{Authentication}; |
88
|
143
|
|
|
|
|
27273
|
}); |
89
|
143
|
|
|
|
|
302
|
state $session_key = $auth_config->{Authentication}{session_key}; |
90
|
143
|
|
|
|
|
238
|
state $current_user_fn = $auth_config->{Authentication}{current_user_fn}; |
91
|
143
|
100
|
|
|
|
548
|
unless ($c->session->{$session_key}) { |
92
|
|
|
|
|
|
|
|
93
|
|
|
|
|
|
|
#set the guest user as default to always have a user |
94
|
51
|
|
|
|
|
16598
|
$c->$current_user_fn($guest); |
95
|
|
|
|
|
|
|
} |
96
|
143
|
|
|
|
|
34071
|
return; |
97
|
|
|
|
|
|
|
} |
98
|
|
|
|
|
|
|
|
99
|
|
|
|
|
|
|
# Make some variables available to the templates being rendered, so |
100
|
|
|
|
|
|
|
# these do not need to be set in the actions. |
101
|
203
|
|
|
203
|
|
311823
|
sub _around_action ($next, $c, $action, $last) { |
|
203
|
|
|
|
|
350
|
|
|
203
|
|
|
|
|
358
|
|
|
203
|
|
|
|
|
250
|
|
|
203
|
|
|
|
|
294
|
|
|
203
|
|
|
|
|
278
|
|
102
|
203
|
100
|
66
|
|
|
1223
|
if ($last && $c->current_route !~ /^api\./) { |
103
|
138
|
|
|
|
|
4702
|
my $stash = $c->stash; |
104
|
138
|
|
33
|
|
|
2272
|
$stash->{l} //= $c->language; # current language of the text being edited |
105
|
138
|
|
33
|
|
|
32357
|
$stash->{user} //= $c->user; # current user |
106
|
|
|
|
|
|
|
} |
107
|
203
|
|
|
|
|
107804
|
return $next->(); |
108
|
|
|
|
|
|
|
} |
109
|
|
|
|
|
|
|
|
110
|
|
|
|
|
|
|
# This code is executed on every request, so we try to save as much as possible |
111
|
|
|
|
|
|
|
# method calls. |
112
|
143
|
|
|
143
|
|
2126625
|
sub _around_dispatch ($next, $c) { |
|
143
|
|
|
|
|
341
|
|
|
143
|
|
|
|
|
228
|
|
|
143
|
|
|
|
|
223
|
|
113
|
143
|
|
|
|
|
318
|
state $app = $c->app; |
114
|
143
|
|
|
|
|
275
|
state $root = $app->config('domove_root'); |
115
|
|
|
|
|
|
|
|
116
|
143
|
|
|
|
|
348
|
state $s_paths = $app->static->paths; |
117
|
143
|
|
|
|
|
315
|
state $r_paths = $app->renderer->paths; |
118
|
143
|
|
|
|
|
273
|
state $cache = $app->renderer->cache; |
119
|
|
|
|
|
|
|
my $dom |
120
|
143
|
|
50
|
|
|
274
|
= eval { $c->domove->find_by_host($c->host_only) } |
121
|
|
|
|
|
|
|
|| die 'No such Host (' |
122
|
|
|
|
|
|
|
. $c->host_only |
123
|
|
|
|
|
|
|
. ')! Looks like a Proxy Server misconfiguration, readonly' |
124
|
|
|
|
|
|
|
. " database file or a missing domain alias in table domove.\n"; |
125
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
# Use domain specific public and templates' paths with priority. |
127
|
143
|
|
|
|
|
4318
|
unshift @{$s_paths}, "$root/$dom->{domain}/public"; |
|
143
|
|
|
|
|
815
|
|
128
|
143
|
50
|
|
|
|
532
|
if (my $tpls = $dom->{templates}) { |
129
|
|
|
|
|
|
|
|
130
|
|
|
|
|
|
|
# absolute path |
131
|
143
|
50
|
33
|
|
|
705
|
if ($tpls =~ m|^/| && -d $tpls) { |
132
|
0
|
|
|
|
|
0
|
unshift @{$r_paths}, $tpls; |
|
0
|
|
|
|
|
0
|
|
133
|
|
|
|
|
|
|
} |
134
|
|
|
|
|
|
|
else { |
135
|
143
|
|
|
|
|
215
|
unshift @{$r_paths}, "$root/$dom->{domain}/templates"; |
|
143
|
|
|
|
|
548
|
|
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# try to find the relative path to the theme in the list of paths |
138
|
143
|
|
|
|
|
278
|
for my $path (@{$r_paths}) { |
|
143
|
|
|
|
|
333
|
|
139
|
575
|
50
|
|
|
|
9728
|
if (-d "$path/$tpls") { |
140
|
0
|
|
|
|
|
0
|
unshift @{$r_paths}, "$path/$tpls"; |
|
0
|
|
|
|
|
0
|
|
141
|
0
|
|
|
|
|
0
|
last; |
142
|
|
|
|
|
|
|
} |
143
|
|
|
|
|
|
|
} |
144
|
|
|
|
|
|
|
} |
145
|
|
|
|
|
|
|
} |
146
|
|
|
|
|
|
|
else { |
147
|
0
|
|
|
|
|
0
|
unshift @{$r_paths}, "$root/$dom->{domain}/templates"; |
|
0
|
|
|
|
|
0
|
|
148
|
|
|
|
|
|
|
} |
149
|
|
|
|
|
|
|
|
150
|
|
|
|
|
|
|
# Templates and routes are cached per domain. By the 'key_prefix' trick we |
151
|
|
|
|
|
|
|
# can provide different templates with the same name to the renderer. This is |
152
|
|
|
|
|
|
|
# how a long running application can switch to different themes per domain |
153
|
|
|
|
|
|
|
# and have different templates although looking like having "the same" path. |
154
|
|
|
|
|
|
|
# This is transparent for the renderer. |
155
|
143
|
|
|
|
|
1068
|
$cache->key_prefix($dom->{domain}); |
156
|
143
|
|
|
|
|
1365
|
$c->stash(domain => $dom); |
157
|
143
|
|
|
|
|
3002
|
$next->(); |
158
|
142
|
|
|
|
|
149475
|
shift @{$s_paths}; |
|
142
|
|
|
|
|
333
|
|
159
|
142
|
|
|
|
|
314
|
shift @{$r_paths}; |
|
142
|
|
|
|
|
294
|
|
160
|
142
|
|
|
|
|
465
|
return; |
161
|
|
|
|
|
|
|
} |
162
|
|
|
|
|
|
|
|
163
|
14
|
|
|
14
|
|
22
|
sub _load_config ($app) { |
|
14
|
|
|
|
|
22
|
|
|
14
|
|
|
|
|
21
|
|
164
|
14
|
|
|
|
|
48
|
my $etc = $app->resources->child('etc'); |
165
|
14
|
|
|
|
|
2297
|
my $moniker = $app->moniker; |
166
|
14
|
|
|
|
|
87
|
my $mode = $app->mode; |
167
|
14
|
|
|
|
|
66
|
my $home = $app->home; |
168
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
# Load configuration from hash returned by "slovo.conf" |
170
|
14
|
|
|
|
|
75
|
my $file = $etc->child("$moniker.conf"); |
171
|
14
|
|
|
|
|
228
|
my $mode_file = $etc->child("$moniker.$mode.conf"); |
172
|
14
|
|
|
|
|
207
|
my $home_file = $home->child("$moniker.conf"); |
173
|
14
|
|
|
|
|
211
|
my $home_mode_file = $home->child("$moniker.$mode.conf"); |
174
|
|
|
|
|
|
|
$ENV{MOJO_CONFIG} |
175
|
14
|
|
33
|
|
|
272
|
//= (-f $home_mode_file && $home_mode_file) |
|
|
|
66
|
|
|
|
|
176
|
|
|
|
|
|
|
|| (-f $home_file && $home_file) |
177
|
|
|
|
|
|
|
|| (-f $mode_file ? $mode_file : $file); |
178
|
|
|
|
|
|
|
|
179
|
14
|
|
|
|
|
1209
|
my $config = $app->plugin('Config'); |
180
|
14
|
|
50
|
|
|
4424
|
for my $class (@{$config->{load_classes} // []}) { |
|
14
|
|
|
|
|
102
|
|
181
|
0
|
|
|
|
|
0
|
$app->load_class($class); |
182
|
|
|
|
|
|
|
} |
183
|
14
|
|
|
|
|
145
|
$app->secrets($config->{secrets}); |
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
# Enable response compression |
186
|
14
|
50
|
|
|
|
118
|
if ($config->{response_compression}) { |
187
|
0
|
|
|
|
|
0
|
$app->renderer->compress(1); |
188
|
|
|
|
|
|
|
} |
189
|
|
|
|
|
|
|
|
190
|
14
|
|
50
|
|
|
29
|
for my $setting (@{$config->{sessions} // []}) { |
|
14
|
|
|
|
|
57
|
|
191
|
28
|
|
|
|
|
636
|
my ($a, $v) = (keys %$setting, values %$setting); |
192
|
28
|
|
|
|
|
111
|
$app->sessions->$a($v); |
193
|
|
|
|
|
|
|
} |
194
|
|
|
|
|
|
|
|
195
|
14
|
|
|
|
|
248
|
return $app; |
196
|
|
|
|
|
|
|
} |
197
|
|
|
|
|
|
|
|
198
|
14
|
|
|
14
|
|
32
|
sub _load_pugins ($app) { |
|
14
|
|
|
|
|
425
|
|
|
14
|
|
|
|
|
28
|
|
199
|
|
|
|
|
|
|
|
200
|
|
|
|
|
|
|
# Namespaces to load plugins from |
201
|
|
|
|
|
|
|
# See /perldoc/Mojolicious#plugins |
202
|
|
|
|
|
|
|
# See /perldoc/Mojolicious/Plugins#PLUGINS |
203
|
14
|
|
|
|
|
48
|
$app->plugins->namespaces(['Slovo::Plugin', 'Slovo', 'Mojolicious::Plugin']); |
204
|
14
|
|
50
|
|
|
212
|
my $plugins = $app->config('load_plugins') // []; |
205
|
14
|
|
|
|
|
219
|
foreach my $plugin (@$plugins) { |
206
|
167
|
100
|
|
|
|
2523
|
my $name = (ref $plugin ? (keys %$plugin)[0] : $plugin); |
207
|
|
|
|
|
|
|
|
208
|
|
|
|
|
|
|
# $app->log->debug('Loading Plugin ' . $name); |
209
|
|
|
|
|
|
|
# some plugins return $self and we are going to abuse this. |
210
|
167
|
|
|
|
|
268
|
my $plug; |
211
|
167
|
100
|
|
|
|
509
|
if (ref $plugin eq 'HASH') { |
|
|
50
|
|
|
|
|
|
212
|
125
|
|
|
|
|
250
|
my $value = (values %$plugin)[0]; |
213
|
125
|
100
|
|
|
|
1301
|
$plug = $app->plugin($name => ref $value eq 'CODE' ? $value->() : $value); |
214
|
|
|
|
|
|
|
} |
215
|
|
|
|
|
|
|
elsif (!ref($plugin)) { |
216
|
42
|
|
|
|
|
149
|
$plug = $app->plugin($name); |
217
|
|
|
|
|
|
|
} |
218
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
# Make OpenAPI specification allways available! |
220
|
167
|
100
|
|
|
|
6103730
|
if ($name eq 'OpenAPI') { |
221
|
356
|
|
|
|
|
487
|
$app->helper( |
222
|
356
|
|
|
356
|
|
436
|
openapi_spec => sub ($c_or_app, $path = '/') { |
|
356
|
|
|
|
|
17054
|
|
|
356
|
|
|
|
|
569
|
|
223
|
356
|
|
|
|
|
1382
|
$plug->validator->get($path); |
224
|
14
|
|
|
|
|
148
|
}); |
225
|
|
|
|
|
|
|
} |
226
|
|
|
|
|
|
|
} |
227
|
14
|
|
|
|
|
87
|
$app->routes->any('/*page_alias')->to('stranici#execute')->name('catch_all'); |
228
|
|
|
|
|
|
|
|
229
|
14
|
|
|
|
|
5803
|
return $app; |
230
|
|
|
|
|
|
|
} |
231
|
|
|
|
|
|
|
|
232
|
14
|
|
|
14
|
|
36
|
sub _default_paths ($app) { |
|
14
|
|
|
|
|
28
|
|
|
14
|
|
|
|
|
22
|
|
233
|
|
|
|
|
|
|
|
234
|
|
|
|
|
|
|
# Fallback "public" directory |
235
|
14
|
|
|
|
|
29
|
push @{$app->static->paths}, $app->resources->child('public')->to_string; |
|
14
|
|
|
|
|
52
|
|
236
|
|
|
|
|
|
|
|
237
|
|
|
|
|
|
|
# Fallback templates directory |
238
|
|
|
|
|
|
|
# See /perldoc/Mojolicious/Renderer#paths |
239
|
14
|
|
|
|
|
790
|
push @{$app->renderer->paths}, $app->resources->child('templates')->to_string; |
|
14
|
|
|
|
|
51
|
|
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
# Current heme |
242
|
14
|
|
|
|
|
399
|
return $app; |
243
|
|
|
|
|
|
|
} |
244
|
|
|
|
|
|
|
|
245
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
# Set Mojolicious::Routes object attributes and types |
247
|
|
|
|
|
|
|
# See Mojolicious::Routes#base_classes |
248
|
|
|
|
|
|
|
# See Mojolicious::Guides::Routing#Placeholder-types |
249
|
14
|
|
|
14
|
|
26
|
sub _set_routes_attrs ($app) { |
|
14
|
|
|
|
|
26
|
|
|
14
|
|
|
|
|
20
|
|
250
|
14
|
|
|
|
|
57
|
my $r = $app->routes; |
251
|
14
|
|
|
|
|
52
|
push @{$r->base_classes}, $app->controller_class; |
|
14
|
|
|
|
|
66
|
|
252
|
14
|
|
|
|
|
193
|
$r->namespaces($r->base_classes); |
253
|
14
|
|
|
|
|
159
|
my $w = qr/[\w\-]+/; |
254
|
14
|
|
|
|
|
60
|
@{$r->types}{qw(lng str cel fl_token)} |
|
14
|
|
|
|
|
49
|
|
255
|
|
|
|
|
|
|
= (qr/[A-z]{2}(?:\-[A-z]{2})?/a, $w, $w, qr/[a-f0-9]{40}/); |
256
|
14
|
|
|
|
|
184
|
return $app; |
257
|
|
|
|
|
|
|
} |
258
|
|
|
|
|
|
|
|
259
|
|
|
|
|
|
|
# Add more media types |
260
|
14
|
|
|
14
|
|
27
|
sub _add_media_types ($app) { |
|
14
|
|
|
|
|
25
|
|
|
14
|
|
|
|
|
24
|
|
261
|
14
|
|
|
|
|
95
|
$app->types->type(woff => ['application/font-woff', 'font/woff']); |
262
|
14
|
|
|
|
|
1258
|
$app->types->type(woff2 => ['application/font-woff2', 'font/woff2']); |
263
|
14
|
|
|
|
|
196
|
return $app; |
264
|
|
|
|
|
|
|
} |
265
|
|
|
|
|
|
|
|
266
|
84
|
|
|
84
|
1
|
138
|
sub load_class ($app, $class) { |
|
84
|
|
|
|
|
125
|
|
|
84
|
|
|
|
|
130
|
|
|
84
|
|
|
|
|
91
|
|
267
|
|
|
|
|
|
|
|
268
|
|
|
|
|
|
|
# state $log = $app->log; |
269
|
|
|
|
|
|
|
# $log->debug("Loading $class"); |
270
|
84
|
50
|
|
|
|
213
|
if (my $e = Mojo::Loader::load_class $class) { |
271
|
0
|
0
|
|
|
|
0
|
Carp::croak ref $e ? "Exception: $e" : "$class - Not found!"; |
272
|
|
|
|
|
|
|
} |
273
|
84
|
|
|
|
|
932582
|
return; |
274
|
|
|
|
|
|
|
} |
275
|
|
|
|
|
|
|
|
276
|
|
|
|
|
|
|
1; |
277
|
|
|
|
|
|
|
|
278
|
|
|
|
|
|
|
=encoding utf8 |
279
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
=head1 NAME |
281
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
Slovo - Искони бѣ Слово |
283
|
|
|
|
|
|
|
|
284
|
|
|
|
|
|
|
=head1 SYNOPSIS |
285
|
|
|
|
|
|
|
|
286
|
|
|
|
|
|
|
Install Slovo locally with all dependencies in less than two minutes |
287
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
time curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org \ |
289
|
|
|
|
|
|
|
-q -n -l ~/opt/slovo Slovo |
290
|
|
|
|
|
|
|
|
291
|
|
|
|
|
|
|
Run slovo for the first time in debug mode |
292
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
morbo ~/opt/slovo/bin/slovo |
294
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
Visit L. |
296
|
|
|
|
|
|
|
For help visit L. |
297
|
|
|
|
|
|
|
|
298
|
|
|
|
|
|
|
=head1 DESCRIPTION |
299
|
|
|
|
|
|
|
|
300
|
|
|
|
|
|
|
L is a simple to install and extensible L |
301
|
|
|
|
|
|
|
L |
302
|
|
|
|
|
|
|
with nice core features, listed below. |
303
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
This is a usable release, yet B and B
|
305
|
|
|
|
|
|
|
pieces>! The project is in active development, so expect often breaking changes. |
306
|
|
|
|
|
|
|
|
307
|
|
|
|
|
|
|
=over |
308
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
=item * On the fly generation of static pages under Apache/CGI – perfect for |
310
|
|
|
|
|
|
|
cheap shared hosting and blogging – BETA; |
311
|
|
|
|
|
|
|
|
312
|
|
|
|
|
|
|
=item * Multi-domain support - BETA; |
313
|
|
|
|
|
|
|
|
314
|
|
|
|
|
|
|
=item * Multi-language pages - WIP; |
315
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=item * Cached published pages and content - DONE; |
317
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
=item * Multi-user support - DONE; |
319
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=item * User onboarding - WIP; |
321
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
=item * User sign in - DONE; |
323
|
|
|
|
|
|
|
|
324
|
|
|
|
|
|
|
=item * Managing pages, content, domains, users - WIP; |
325
|
|
|
|
|
|
|
|
326
|
|
|
|
|
|
|
=item * Managing groups - BASIC; |
327
|
|
|
|
|
|
|
|
328
|
|
|
|
|
|
|
=item * Multiple groups per user - DONE; |
329
|
|
|
|
|
|
|
|
330
|
|
|
|
|
|
|
=item * Ownership and permissions management per page and it's content - BETA; |
331
|
|
|
|
|
|
|
|
332
|
|
|
|
|
|
|
=item * Automatic 301 and 308 (Moved Permanently) redirects for renamed pages |
333
|
|
|
|
|
|
|
and content - DONE; |
334
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=item * Embedded fonts for displaying all |
336
|
|
|
|
|
|
|
L and |
337
|
|
|
|
|
|
|
L characters - |
338
|
|
|
|
|
|
|
DONE; |
339
|
|
|
|
|
|
|
|
340
|
|
|
|
|
|
|
=item * OpenAPI 2/3.0 (Swagger) REST API - BASIC; |
341
|
|
|
|
|
|
|
|
342
|
|
|
|
|
|
|
=item * Embedded Trumbowyg - L; |
343
|
|
|
|
|
|
|
|
344
|
|
|
|
|
|
|
=item * Embedded Editor.md - L
|
345
|
|
|
|
|
|
|
(component), based on CodeMirror & jQuery & |
346
|
|
|
|
|
|
|
Marked|http://editor.md.ipandao.com/>; |
347
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
=item * Example startup scripts for slovo and slovo_minion services |
349
|
|
|
|
|
|
|
for L, L
|
350
|
|
|
|
|
|
|
2.4|https://httpd.apache.org/docs/2.4/> and NGINX vhost configuration files. |
351
|
|
|
|
|
|
|
|
352
|
|
|
|
|
|
|
=item * Inflatable embedded themes support - BETA; |
353
|
|
|
|
|
|
|
|
354
|
|
|
|
|
|
|
=item * and more to come… |
355
|
|
|
|
|
|
|
|
356
|
|
|
|
|
|
|
=back |
357
|
|
|
|
|
|
|
|
358
|
|
|
|
|
|
|
By default Slovo comes with SQLite database, but support for PostgreSQL or |
359
|
|
|
|
|
|
|
MySQL is about to be added when needed. It is just a question of making |
360
|
|
|
|
|
|
|
compatible and/or translating some limited number of SQL queries to the |
361
|
|
|
|
|
|
|
corresponding SQL dialects. Contributors are welcome. |
362
|
|
|
|
|
|
|
|
363
|
|
|
|
|
|
|
The word "slovo" (слово) has one unchanged meaning during the last millennium |
364
|
|
|
|
|
|
|
among all slavic languages. It is actually one language that started splitting |
365
|
|
|
|
|
|
|
apart less than one thousand years ago. The meaning is "word" – the God's word |
366
|
|
|
|
|
|
|
(when used with capital letter). Hence the self-naming of this group of people |
367
|
|
|
|
|
|
|
C - people who have been given the God's word or |
368
|
|
|
|
|
|
|
people who can speak. All others were considered "mute", hence the naming |
369
|
|
|
|
|
|
|
(немци)... |
370
|
|
|
|
|
|
|
|
371
|
|
|
|
|
|
|
=head1 INSTALL |
372
|
|
|
|
|
|
|
|
373
|
|
|
|
|
|
|
All you need is a one-liner, it takes less than a minute. |
374
|
|
|
|
|
|
|
|
375
|
|
|
|
|
|
|
$ curl -L https://cpanmin.us | perl - -M https://cpan.metacpan.org -n -l ~/opt/slovo Slovo |
376
|
|
|
|
|
|
|
|
377
|
|
|
|
|
|
|
We recommend the use of a L environment. |
378
|
|
|
|
|
|
|
|
379
|
|
|
|
|
|
|
If you already downloaded it and you have L. |
380
|
|
|
|
|
|
|
|
381
|
|
|
|
|
|
|
$ cpanm -l ~/opt/slovo Slovo-XXXX.XX.XX.tar.gz |
382
|
|
|
|
|
|
|
|
383
|
|
|
|
|
|
|
Or even if you don't have C. Note that you need to install dependencies first. |
384
|
|
|
|
|
|
|
Set C, remove old Slovo installation, make, test, install, create |
385
|
|
|
|
|
|
|
data directory for sqlite database and run slovo to see available commands. |
386
|
|
|
|
|
|
|
|
387
|
|
|
|
|
|
|
tar zxf Slovo-XXXX.XX.XX.tar.gz |
388
|
|
|
|
|
|
|
cd Slovo-XXXX.XX.XX |
389
|
|
|
|
|
|
|
INSTALL_BASE=~/opt/slovo && rm -rf $INSTALL_BASE && make distclean; \ |
390
|
|
|
|
|
|
|
perl Makefile.PL INSTALL_BASE=$INSTALL_BASE && make && make test && make install \ |
391
|
|
|
|
|
|
|
&& $INSTALL_BASE/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});' \ |
392
|
|
|
|
|
|
|
&& $INSTALL_BASE/bin/slovo |
393
|
|
|
|
|
|
|
|
394
|
|
|
|
|
|
|
Use cpanm to install or update into a custom location as self contained application and |
395
|
|
|
|
|
|
|
run slovo to see how it's going. |
396
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
# From metacpan. org |
398
|
|
|
|
|
|
|
export PREFIX=~/opt/slovo; |
399
|
|
|
|
|
|
|
cpanm -M https://cpan.metacpan.org -n --self-contained -l $PREFIX Slovo \ |
400
|
|
|
|
|
|
|
$PREFIX/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});' \ |
401
|
|
|
|
|
|
|
$PREFIX/bin/slovo |
402
|
|
|
|
|
|
|
|
403
|
|
|
|
|
|
|
# From the directory where you unpacked Slovo |
404
|
|
|
|
|
|
|
export PREFIX=~/opt/slovo; |
405
|
|
|
|
|
|
|
cpanm . -n --self-contained -l $PREFIX Slovo |
406
|
|
|
|
|
|
|
$PREFIX/bin/slovo eval 'app->home->child("data")->make_path({mode => 0700});' |
407
|
|
|
|
|
|
|
$PREFIX/bin/slovo |
408
|
|
|
|
|
|
|
|
409
|
|
|
|
|
|
|
Start the development server and open a browser |
410
|
|
|
|
|
|
|
|
411
|
|
|
|
|
|
|
morbo ./script/slovo -l http://*:3000 & sleep 1 exo-open http://localhost:3000 |
412
|
|
|
|
|
|
|
|
413
|
|
|
|
|
|
|
=head1 USAGE |
414
|
|
|
|
|
|
|
|
415
|
|
|
|
|
|
|
cd /path/to/installed/slovo |
416
|
|
|
|
|
|
|
# ...and see various options |
417
|
|
|
|
|
|
|
./bin/slovo |
418
|
|
|
|
|
|
|
|
419
|
|
|
|
|
|
|
=head1 CONFIGURATION, PATHS and UPGRADING |
420
|
|
|
|
|
|
|
|
421
|
|
|
|
|
|
|
L is a L application which means that everything |
422
|
|
|
|
|
|
|
applying to Mojolicious applies to it too. Slovo main configuration file is |
423
|
|
|
|
|
|
|
in C. You can use your own by setting |
424
|
|
|
|
|
|
|
C<$ENV{MOJO_CONFIG}> or by just copying C to $ENV{MOJO_HOME} and |
425
|
|
|
|
|
|
|
modify it as you wish. Routes can be added or removed in C. See |
426
|
|
|
|
|
|
|
L for details and examples. New plugins can |
427
|
|
|
|
|
|
|
be added per deployment in C section in C. |
428
|
|
|
|
|
|
|
|
429
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}> (L) is automatically |
430
|
|
|
|
|
|
|
detected and used. All paths, used in the application, are expected to be its |
431
|
|
|
|
|
|
|
children. You can add your own templates in C<$ENV{MOJO_HOME}/templates> and |
432
|
|
|
|
|
|
|
they will be loaded and used with priority. You can theme your own instance of |
433
|
|
|
|
|
|
|
Slovo by just copying C<$ENV{MOJO_HOME}/lib/Slovo/resources/templates> to |
434
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}/templates> and modify them. You can add your own static files |
435
|
|
|
|
|
|
|
to C<$ENV{MOJO_HOME}/public>. You can create custom themes by forking |
436
|
|
|
|
|
|
|
L and using it as a starting point. |
437
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
You can have separate static files and templates per domain under |
439
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}/domove/your.domain/public>, |
440
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}/domove/your.other.domain/templates>, etc. See |
441
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}/domove/localhost> for example. |
442
|
|
|
|
|
|
|
|
443
|
|
|
|
|
|
|
You can switch between different themes by just selecting the theme in the |
444
|
|
|
|
|
|
|
form for editing domains. |
445
|
|
|
|
|
|
|
|
446
|
|
|
|
|
|
|
Last but not least, you can add your own classes into |
447
|
|
|
|
|
|
|
C<$ENV{MOJO_HOME}/site/lib> and (why not) replace entirely some Slovo classes |
448
|
|
|
|
|
|
|
or just extend them. C<$ENV{MOJO_HOME}/bin/slovo> will load them with priority. |
449
|
|
|
|
|
|
|
|
450
|
|
|
|
|
|
|
With all the above, you can upgrade L by just installing new versions |
451
|
|
|
|
|
|
|
over it and your files will not be touched. And of course, we know that you are |
452
|
|
|
|
|
|
|
using versioning just in case anything goes wrong. See L. |
453
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=head1 ATTRIBUTES |
455
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
L inherits all attributes from L and implements |
457
|
|
|
|
|
|
|
the following new ones. |
458
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
=head2 home |
460
|
|
|
|
|
|
|
|
461
|
|
|
|
|
|
|
L detects where B is not like L by where |
462
|
|
|
|
|
|
|
C is but by where the C or C folder resides |
463
|
|
|
|
|
|
|
starting from where C is and going up the tree. If in one of |
464
|
|
|
|
|
|
|
these folders there is a C executable, then the upper folder is the |
465
|
|
|
|
|
|
|
home. |
466
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
Examples: |
468
|
|
|
|
|
|
|
|
469
|
|
|
|
|
|
|
berov@Skylake:Slovo$ pwd |
470
|
|
|
|
|
|
|
/home/berov/opt/dev/Slovo |
471
|
|
|
|
|
|
|
berov@Skylake:Slovo$ perl script/slovo eval 'say app->home' |
472
|
|
|
|
|
|
|
/home/berov/opt/dev/Slovo |
473
|
|
|
|
|
|
|
|
474
|
|
|
|
|
|
|
berov@Skylake:Slovo$ cpanm . -n -l ~/opt/t.com/slovo |
475
|
|
|
|
|
|
|
--> Working on . |
476
|
|
|
|
|
|
|
Configuring /home/berov/opt/dev/Slovo ... OK |
477
|
|
|
|
|
|
|
Building Slovo-v2019.06.09 ... OK |
478
|
|
|
|
|
|
|
Successfully installed Slovo-v2019.06.09 |
479
|
|
|
|
|
|
|
1 distribution installed |
480
|
|
|
|
|
|
|
|
481
|
|
|
|
|
|
|
berov@Skylake:t.com$ pwd |
482
|
|
|
|
|
|
|
/home/berov/opt/t.com |
483
|
|
|
|
|
|
|
berov@Skylake:t.com$ slovo/bin/slovo eval 'say app->home' |
484
|
|
|
|
|
|
|
/home/berov/opt/t.com/slovo |
485
|
|
|
|
|
|
|
|
486
|
|
|
|
|
|
|
berov@Skylake:t.com$ pwd |
487
|
|
|
|
|
|
|
/home/berov/opt/t.com |
488
|
|
|
|
|
|
|
berov@Skylake:t.com$ perl -Islovo/lib/perl5 -MSlovo -E 'say Slovo->new->home' |
489
|
|
|
|
|
|
|
/home/berov/opt/t.com/slovo |
490
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
=head2 log |
492
|
|
|
|
|
|
|
|
493
|
|
|
|
|
|
|
Overrides L. Logs to Chome-Echild('log/slovo.log')> |
494
|
|
|
|
|
|
|
if C<$self-Ehome-Echild('log')> exists and is writable. Oderwise writes to |
495
|
|
|
|
|
|
|
STDERR. The log-level will default to either the C environment |
496
|
|
|
|
|
|
|
variable, C if the "mode" is C, or C otherwise. |
497
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
=head2 resources |
499
|
|
|
|
|
|
|
|
500
|
|
|
|
|
|
|
push @{$app->static->paths}, $app->resources->child('public'); |
501
|
|
|
|
|
|
|
|
502
|
|
|
|
|
|
|
Returns a L instance for path L next to where |
503
|
|
|
|
|
|
|
C is installed. |
504
|
|
|
|
|
|
|
|
505
|
|
|
|
|
|
|
=head2 validator |
506
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
my $validator = $app->validator; |
508
|
|
|
|
|
|
|
$app = $app->validator(Slovo::Validator->new); |
509
|
|
|
|
|
|
|
|
510
|
|
|
|
|
|
|
Validate values, defaults to a L object. |
511
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
# Add validation check |
513
|
|
|
|
|
|
|
$app->validator->add_check(foo => sub { |
514
|
|
|
|
|
|
|
my ($v, $name, $value) = @_; |
515
|
|
|
|
|
|
|
return $value ne 'foo'; |
516
|
|
|
|
|
|
|
}); |
517
|
|
|
|
|
|
|
|
518
|
|
|
|
|
|
|
# Add validation filter |
519
|
|
|
|
|
|
|
$app->validator->add_filter(quotemeta => sub { |
520
|
|
|
|
|
|
|
my ($v, $name, $value) = @_; |
521
|
|
|
|
|
|
|
return quotemeta $value; |
522
|
|
|
|
|
|
|
}); |
523
|
|
|
|
|
|
|
|
524
|
|
|
|
|
|
|
=head1 METHODS |
525
|
|
|
|
|
|
|
|
526
|
|
|
|
|
|
|
L inherits all methods from L and implements |
527
|
|
|
|
|
|
|
the following new ones. |
528
|
|
|
|
|
|
|
|
529
|
|
|
|
|
|
|
=head2 load_class |
530
|
|
|
|
|
|
|
|
531
|
|
|
|
|
|
|
A convenient wrapper with check for L. |
532
|
|
|
|
|
|
|
Loads a class and croaks if something is wrong. This could be a helper. |
533
|
|
|
|
|
|
|
|
534
|
|
|
|
|
|
|
for my $class (@{$config->{load_classes} // []}) { |
535
|
|
|
|
|
|
|
$app->load_class($class); |
536
|
|
|
|
|
|
|
} |
537
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=head2 startup |
539
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
Starts the application. Adds hooks, prepares C<$app-Eroutes> for use, loads |
541
|
|
|
|
|
|
|
configuration files and applies settings from them, loads plugins, sets default |
542
|
|
|
|
|
|
|
paths, and returns the application instance. See also L. |
543
|
|
|
|
|
|
|
|
544
|
|
|
|
|
|
|
=head1 HOOKS |
545
|
|
|
|
|
|
|
|
546
|
|
|
|
|
|
|
Slovo adds custom code to the following hooks. |
547
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
=head2 around_action |
549
|
|
|
|
|
|
|
|
550
|
|
|
|
|
|
|
On each request we set the following variables in the stash so they are |
551
|
|
|
|
|
|
|
available in the respective templates. Here they are: |
552
|
|
|
|
|
|
|
|
553
|
|
|
|
|
|
|
$stash->{l} //= $c->language; # current language |
554
|
|
|
|
|
|
|
$stash->{user} //= $c->user; # current user |
555
|
|
|
|
|
|
|
|
556
|
|
|
|
|
|
|
=head2 around_dispatch |
557
|
|
|
|
|
|
|
|
558
|
|
|
|
|
|
|
On each request we determine the current host and modify the static and |
559
|
|
|
|
|
|
|
renderer paths accordingly. This is how each domain has its own templates and |
560
|
|
|
|
|
|
|
static files. |
561
|
|
|
|
|
|
|
|
562
|
|
|
|
|
|
|
Also if the C field for the current domain is not empty, we |
563
|
|
|
|
|
|
|
determine from it the templates root for the theme to be used for this domain |
564
|
|
|
|
|
|
|
during this request. This is how the themes support for multiple domains in one |
565
|
|
|
|
|
|
|
L instance work. |
566
|
|
|
|
|
|
|
|
567
|
|
|
|
|
|
|
It is also important to note that in a long running application (not CGI) the |
568
|
|
|
|
|
|
|
templates are cached in memory and the relative path from the current |
569
|
|
|
|
|
|
|
templates root to each template is used as the key in L cache. We |
570
|
|
|
|
|
|
|
had to implement L to be able to differentiate between |
571
|
|
|
|
|
|
|
templates having the same names, but found in different paths. All this is |
572
|
|
|
|
|
|
|
possible thanks to L's well decoupled components. |
573
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
Example: Let's suppose that the domain L has the field |
575
|
|
|
|
|
|
|
'templates' value set to C (малка==small f. in Bulgarian). |
576
|
|
|
|
|
|
|
|
577
|
|
|
|
|
|
|
Renderer paths before the check is performed: |
578
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
[ |
580
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/templates", |
581
|
|
|
|
|
|
|
"/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/templates", |
582
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates" |
583
|
|
|
|
|
|
|
] |
584
|
|
|
|
|
|
|
|
585
|
|
|
|
|
|
|
Static paths before the check: |
586
|
|
|
|
|
|
|
|
587
|
|
|
|
|
|
|
[ |
588
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/public", |
589
|
|
|
|
|
|
|
"/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/public", |
590
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/lib/Slovo/resources/public" |
591
|
|
|
|
|
|
|
] |
592
|
|
|
|
|
|
|
|
593
|
|
|
|
|
|
|
Renderer paths after the check is performed. The first path in the list will be |
594
|
|
|
|
|
|
|
used with priority: |
595
|
|
|
|
|
|
|
|
596
|
|
|
|
|
|
|
[ |
597
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates/themes/malka", # if exists! |
598
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/domove/xn--b1arjbl.xn--90ae/templates", # if exists! |
599
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/templates", |
600
|
|
|
|
|
|
|
"/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/templates", |
601
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/lib/Slovo/resources/templates" |
602
|
|
|
|
|
|
|
] |
603
|
|
|
|
|
|
|
|
604
|
|
|
|
|
|
|
Static paths after the check: |
605
|
|
|
|
|
|
|
|
606
|
|
|
|
|
|
|
[ |
607
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/domove/xn--b1arjbl.xn--90ae/public", # if exists! |
608
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/public", |
609
|
|
|
|
|
|
|
"/home/berov/perl5/perlbrew/perls/perl-5.28.2/lib/site_perl/5.28.2/Mojolicious/Plugin/Minion/resources/public", |
610
|
|
|
|
|
|
|
"/home/berov/opt/dev/Slovo/lib/Slovo/resources/public" |
611
|
|
|
|
|
|
|
] |
612
|
|
|
|
|
|
|
|
613
|
|
|
|
|
|
|
In addition the current domain row from table C becomes available in |
614
|
|
|
|
|
|
|
the stash as C<$domain>. |
615
|
|
|
|
|
|
|
|
616
|
|
|
|
|
|
|
# In a controller or model |
617
|
|
|
|
|
|
|
$c->stash('domain')->{id}; |
618
|
|
|
|
|
|
|
$m->c->stash('domain')->{aliases}; |
619
|
|
|
|
|
|
|
|
620
|
|
|
|
|
|
|
# In a template like |
621
|
|
|
|
|
|
|
# lib/Slovo/resources/templates/stranici/_form.html.ep |
622
|
|
|
|
|
|
|
<%= |
623
|
|
|
|
|
|
|
select_box |
624
|
|
|
|
|
|
|
dom_id => $domove, |
625
|
|
|
|
|
|
|
required => 1, |
626
|
|
|
|
|
|
|
label => 'Дом', |
627
|
|
|
|
|
|
|
title => 'В кой сайт се намира страницата.', |
628
|
|
|
|
|
|
|
readonly => '', |
629
|
|
|
|
|
|
|
value => $domain->{id} #default value |
630
|
|
|
|
|
|
|
%> |
631
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
=head2 before_dispatch |
633
|
|
|
|
|
|
|
|
634
|
|
|
|
|
|
|
On each request we check if we have a logged in user and set the current user |
635
|
|
|
|
|
|
|
to C if we don't. This way every part of the application (including |
636
|
|
|
|
|
|
|
newly developed plugins) can count on having a current user. The user is needed |
637
|
|
|
|
|
|
|
to determine the permissions for any table that has column C. The |
638
|
|
|
|
|
|
|
current user is available as C<$c-Euser>. |
639
|
|
|
|
|
|
|
|
640
|
|
|
|
|
|
|
=head1 HELPERS |
641
|
|
|
|
|
|
|
|
642
|
|
|
|
|
|
|
Slovo implements the following helpers. |
643
|
|
|
|
|
|
|
|
644
|
|
|
|
|
|
|
=head2 openapi_spec |
645
|
|
|
|
|
|
|
|
646
|
|
|
|
|
|
|
We need to have our OpenAPI API specification always at hand as a unified |
647
|
|
|
|
|
|
|
source of truth so here it is. |
648
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
# anywhere via $app or $c, even not via a REST call |
650
|
|
|
|
|
|
|
state $columns = |
651
|
|
|
|
|
|
|
$c->openapi_spec('/paths/~1stranici/get/parameters/3/default'); |
652
|
|
|
|
|
|
|
[ |
653
|
|
|
|
|
|
|
"id", |
654
|
|
|
|
|
|
|
"pid", |
655
|
|
|
|
|
|
|
"alias", |
656
|
|
|
|
|
|
|
"title", |
657
|
|
|
|
|
|
|
"is_dir" |
658
|
|
|
|
|
|
|
] |
659
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
=head1 BUGS, SUPPORT, CONTRIBUTING, DISCUSS |
661
|
|
|
|
|
|
|
|
662
|
|
|
|
|
|
|
=for html |
663
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
To report a bug, please create issues at |
665
|
|
|
|
|
|
|
L, fork the project and make |
666
|
|
|
|
|
|
|
pull requests. |
667
|
|
|
|
|
|
|
|
668
|
|
|
|
|
|
|
|
669
|
|
|
|
|
|
|
=head1 AUTHOR |
670
|
|
|
|
|
|
|
|
671
|
|
|
|
|
|
|
Красимир Беров |
672
|
|
|
|
|
|
|
CPAN ID: BEROV |
673
|
|
|
|
|
|
|
berov на cpan точка org |
674
|
|
|
|
|
|
|
http://i-can.eu |
675
|
|
|
|
|
|
|
|
676
|
|
|
|
|
|
|
=head1 CONTRIBUTORS |
677
|
|
|
|
|
|
|
|
678
|
|
|
|
|
|
|
Ordered by time of first commit. |
679
|
|
|
|
|
|
|
|
680
|
|
|
|
|
|
|
=over |
681
|
|
|
|
|
|
|
|
682
|
|
|
|
|
|
|
=item * MANWAR (Mohammad S Anwar) |
683
|
|
|
|
|
|
|
|
684
|
|
|
|
|
|
|
=item * KABANOID (Mikhail Katasonov) |
685
|
|
|
|
|
|
|
|
686
|
|
|
|
|
|
|
=item * 0xAF (Stanislav Lechev) |
687
|
|
|
|
|
|
|
|
688
|
|
|
|
|
|
|
=back |
689
|
|
|
|
|
|
|
|
690
|
|
|
|
|
|
|
=head1 COPYRIGHT |
691
|
|
|
|
|
|
|
|
692
|
|
|
|
|
|
|
This is free software, licensed under: |
693
|
|
|
|
|
|
|
|
694
|
|
|
|
|
|
|
The Artistic License 2.0 (GPL Compatible) |
695
|
|
|
|
|
|
|
|
696
|
|
|
|
|
|
|
The full text of the license can be found in the |
697
|
|
|
|
|
|
|
LICENSE file included with this module. |
698
|
|
|
|
|
|
|
|
699
|
|
|
|
|
|
|
This distribution contains other free software which belongs to their |
700
|
|
|
|
|
|
|
respective authors. |
701
|
|
|
|
|
|
|
|
702
|
|
|
|
|
|
|
=head1 TODO |
703
|
|
|
|
|
|
|
|
704
|
|
|
|
|
|
|
=over |
705
|
|
|
|
|
|
|
|
706
|
|
|
|
|
|
|
=item * Stop adding features. Stabilize what we have. |
707
|
|
|
|
|
|
|
|
708
|
|
|
|
|
|
|
=item * Gradually replace L with L
|
709
|
|
|
|
|
|
|
CSS|https://jenil.github.io/chota/> - site part is done. |
710
|
|
|
|
|
|
|
|
711
|
|
|
|
|
|
|
=item * Considerably improve the Adminiastration UI - now it is quite |
712
|
|
|
|
|
|
|
simplistic. Use ES6 directly as per L
|
713
|
|
|
|
|
|
|
table|https://kangax.github.io/compat-table/es6/> |
714
|
|
|
|
|
|
|
|
715
|
|
|
|
|
|
|
=item * Consider using L or |
716
|
|
|
|
|
|
|
L or something light as frontend framework for |
717
|
|
|
|
|
|
|
building UI. We already use jQuery distributed with the Mojolicious distro. |
718
|
|
|
|
|
|
|
|
719
|
|
|
|
|
|
|
=back |
720
|
|
|
|
|
|
|
|
721
|
|
|
|
|
|
|
=head1 SEE ALSO |
722
|
|
|
|
|
|
|
|
723
|
|
|
|
|
|
|
L, L, |
724
|
|
|
|
|
|
|
L, L, L |
725
|
|
|
|
|
|
|
|
726
|
|
|
|
|
|
|
=cut |
727
|
|
|
|
|
|
|
|