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