| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package MojoMojo; |
|
2
|
|
|
|
|
|
|
|
|
3
|
35
|
|
|
35
|
|
17565820
|
use strict; |
|
|
35
|
|
|
|
|
89
|
|
|
|
35
|
|
|
|
|
999
|
|
|
4
|
35
|
|
|
35
|
|
562
|
use Path::Class 'file'; |
|
|
35
|
|
|
|
|
27566
|
|
|
|
35
|
|
|
|
|
1912
|
|
|
5
|
|
|
|
|
|
|
|
|
6
|
35
|
|
|
|
|
284
|
use Catalyst qw/ |
|
7
|
|
|
|
|
|
|
ConfigLoader |
|
8
|
|
|
|
|
|
|
Authentication |
|
9
|
|
|
|
|
|
|
Cache |
|
10
|
|
|
|
|
|
|
Session |
|
11
|
|
|
|
|
|
|
Session::Store::Cache |
|
12
|
|
|
|
|
|
|
Session::State::Cookie |
|
13
|
|
|
|
|
|
|
Static::Simple |
|
14
|
|
|
|
|
|
|
SubRequest |
|
15
|
|
|
|
|
|
|
I18N |
|
16
|
|
|
|
|
|
|
Setenv |
|
17
|
35
|
|
|
35
|
|
27135
|
/; |
|
|
35
|
|
|
|
|
35688807
|
|
|
18
|
|
|
|
|
|
|
|
|
19
|
35
|
|
|
35
|
|
403746
|
use Storable; |
|
|
35
|
|
|
|
|
90
|
|
|
|
35
|
|
|
|
|
2218
|
|
|
20
|
35
|
|
|
35
|
|
216
|
use Digest::MD5; |
|
|
35
|
|
|
|
|
96
|
|
|
|
35
|
|
|
|
|
1160
|
|
|
21
|
35
|
|
|
35
|
|
15254
|
use Data::Dumper; |
|
|
35
|
|
|
|
|
106749
|
|
|
|
35
|
|
|
|
|
1789
|
|
|
22
|
35
|
|
|
35
|
|
21907
|
use DateTime; |
|
|
35
|
|
|
|
|
11461127
|
|
|
|
35
|
|
|
|
|
1441
|
|
|
23
|
35
|
|
|
35
|
|
293
|
use MRO::Compat; |
|
|
35
|
|
|
|
|
81
|
|
|
|
35
|
|
|
|
|
732
|
|
|
24
|
35
|
|
|
35
|
|
18947
|
use DBIx::Class::ResultClass::HashRefInflator; |
|
|
35
|
|
|
|
|
9841
|
|
|
|
35
|
|
|
|
|
987
|
|
|
25
|
35
|
|
|
35
|
|
305
|
use Encode (); |
|
|
35
|
|
|
|
|
117
|
|
|
|
35
|
|
|
|
|
466
|
|
|
26
|
35
|
|
|
35
|
|
158
|
use URI::Escape (); |
|
|
35
|
|
|
|
|
89
|
|
|
|
35
|
|
|
|
|
468
|
|
|
27
|
35
|
|
|
35
|
|
13048
|
use MojoMojo::Formatter::Wiki; |
|
|
35
|
|
|
|
|
118
|
|
|
|
35
|
|
|
|
|
1812
|
|
|
28
|
|
|
|
|
|
|
use Module::Pluggable::Ordered |
|
29
|
35
|
|
|
|
|
355
|
search_path => 'MojoMojo::Formatter', |
|
30
|
|
|
|
|
|
|
except => qr/^MojoMojo::Plugin::/, |
|
31
|
35
|
|
|
35
|
|
17057
|
require => 1; |
|
|
35
|
|
|
|
|
96312
|
|
|
32
|
|
|
|
|
|
|
|
|
33
|
|
|
|
|
|
|
our $VERSION = '1.12'; |
|
34
|
35
|
|
|
35
|
|
4999
|
use 5.008004; |
|
|
35
|
|
|
|
|
139
|
|
|
35
|
|
|
|
|
|
|
|
|
36
|
|
|
|
|
|
|
MojoMojo->config->{authentication}{dbic} = { |
|
37
|
|
|
|
|
|
|
user_class => 'DBIC::Person', |
|
38
|
|
|
|
|
|
|
user_field => 'login', |
|
39
|
|
|
|
|
|
|
password_field => 'pass' |
|
40
|
|
|
|
|
|
|
}; |
|
41
|
|
|
|
|
|
|
MojoMojo->config->{default_view} = 'TT'; |
|
42
|
|
|
|
|
|
|
MojoMojo->config->{'Plugin::Cache'}{backend} = { |
|
43
|
|
|
|
|
|
|
class => "Cache::FastMmap", |
|
44
|
|
|
|
|
|
|
unlink_on_exit => 1, |
|
45
|
|
|
|
|
|
|
share_file => '' |
|
46
|
|
|
|
|
|
|
. Path::Class::file( |
|
47
|
|
|
|
|
|
|
File::Spec->tmpdir, |
|
48
|
|
|
|
|
|
|
'mojomojo-sharefile-' . Digest::MD5::md5_hex(MojoMojo->config->{home}) |
|
49
|
|
|
|
|
|
|
), |
|
50
|
|
|
|
|
|
|
}; |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
__PACKAGE__->config( |
|
53
|
|
|
|
|
|
|
authentication => { |
|
54
|
|
|
|
|
|
|
default_realm => 'members', |
|
55
|
|
|
|
|
|
|
use_session => 1, |
|
56
|
|
|
|
|
|
|
realms => { |
|
57
|
|
|
|
|
|
|
members => { |
|
58
|
|
|
|
|
|
|
credential => { |
|
59
|
|
|
|
|
|
|
class => 'Password', |
|
60
|
|
|
|
|
|
|
password_field => 'pass', |
|
61
|
|
|
|
|
|
|
password_type => 'hashed', |
|
62
|
|
|
|
|
|
|
password_hash_type => 'SHA-1', |
|
63
|
|
|
|
|
|
|
}, |
|
64
|
|
|
|
|
|
|
store => {class => 'DBIx::Class', user_class => 'DBIC::Person',}, |
|
65
|
|
|
|
|
|
|
}, |
|
66
|
|
|
|
|
|
|
} |
|
67
|
|
|
|
|
|
|
} |
|
68
|
|
|
|
|
|
|
); |
|
69
|
|
|
|
|
|
|
|
|
70
|
|
|
|
|
|
|
__PACKAGE__->config('Controller::HTML::FormFu' => |
|
71
|
|
|
|
|
|
|
{languages_from_context => 1, localize_from_context => 1,}); |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
__PACKAGE__->config(setup_components => {search_extra => ['::Extensions'],}); |
|
74
|
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
MojoMojo->setup(); |
|
76
|
|
|
|
|
|
|
|
|
77
|
|
|
|
|
|
|
# Check for deployed database |
|
78
|
|
|
|
|
|
|
my $has_DB = 1; |
|
79
|
|
|
|
|
|
|
my $NO_DB_MESSAGE = <<"EOF"; |
|
80
|
|
|
|
|
|
|
|
|
81
|
|
|
|
|
|
|
*********************************************** |
|
82
|
|
|
|
|
|
|
ERROR. Looks like you need to deploy a database. |
|
83
|
|
|
|
|
|
|
Run script/mojomojo_spawn_db.pl |
|
84
|
|
|
|
|
|
|
*********************************************** |
|
85
|
|
|
|
|
|
|
|
|
86
|
|
|
|
|
|
|
EOF |
|
87
|
|
|
|
|
|
|
eval { |
|
88
|
|
|
|
|
|
|
MojoMojo->model('DBIC') |
|
89
|
|
|
|
|
|
|
->schema->resultset('MojoMojo::Schema::Result::Person')->next; |
|
90
|
|
|
|
|
|
|
}; |
|
91
|
|
|
|
|
|
|
if ($@) { |
|
92
|
|
|
|
|
|
|
$has_DB = 0; |
|
93
|
|
|
|
|
|
|
warn $NO_DB_MESSAGE; |
|
94
|
|
|
|
|
|
|
warn "(Error: $@)"; |
|
95
|
|
|
|
|
|
|
} |
|
96
|
|
|
|
|
|
|
|
|
97
|
|
|
|
|
|
|
MojoMojo->model('DBIC') |
|
98
|
|
|
|
|
|
|
->schema->attachment_dir(MojoMojo->config->{attachment_dir} |
|
99
|
|
|
|
|
|
|
|| MojoMojo->path_to('uploads') . ''); |
|
100
|
|
|
|
|
|
|
|
|
101
|
|
|
|
|
|
|
=head1 NAME |
|
102
|
|
|
|
|
|
|
|
|
103
|
|
|
|
|
|
|
MojoMojo - A Wiki with a tree |
|
104
|
|
|
|
|
|
|
|
|
105
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
106
|
|
|
|
|
|
|
|
|
107
|
|
|
|
|
|
|
# Set up database (see mojomojo.conf first) |
|
108
|
|
|
|
|
|
|
|
|
109
|
|
|
|
|
|
|
./script/mojomojo_spawn_db.pl |
|
110
|
|
|
|
|
|
|
|
|
111
|
|
|
|
|
|
|
# Standalone mode |
|
112
|
|
|
|
|
|
|
|
|
113
|
|
|
|
|
|
|
./script/mojomo_server.pl |
|
114
|
|
|
|
|
|
|
|
|
115
|
|
|
|
|
|
|
# In apache conf |
|
116
|
|
|
|
|
|
|
<Location /mojomojo> |
|
117
|
|
|
|
|
|
|
SetHandler perl-script |
|
118
|
|
|
|
|
|
|
PerlHandler MojoMojo |
|
119
|
|
|
|
|
|
|
</Location> |
|
120
|
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
122
|
|
|
|
|
|
|
|
|
123
|
|
|
|
|
|
|
Mojomojo is a content management system, borrowing many concepts from |
|
124
|
|
|
|
|
|
|
wikis and blogs. It allows you to maintain a full tree-structure of pages, |
|
125
|
|
|
|
|
|
|
and to interlink them in various ways. It has full version support, so you can |
|
126
|
|
|
|
|
|
|
always go back to a previous version and see what's changed with an easy diff |
|
127
|
|
|
|
|
|
|
system. There are also a some of useful features like live AJAX preview while |
|
128
|
|
|
|
|
|
|
editing, tagging, built-in fulltext search, image galleries, and RSS feeds |
|
129
|
|
|
|
|
|
|
for every wiki page. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
To find out more about how you can use MojoMojo, please visit |
|
132
|
|
|
|
|
|
|
L<http://mojomojo.org/> or read the installation instructions in |
|
133
|
|
|
|
|
|
|
L<MojoMojo::Installation> to try it out yourself. |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
=head1 METHODS |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head2 prepare |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Accommodate a forcing of SSL if needed in a reverse proxy setup. |
|
140
|
|
|
|
|
|
|
|
|
141
|
|
|
|
|
|
|
=cut |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
sub prepare { |
|
144
|
197
|
|
|
197
|
1
|
8009055
|
my $self = shift->next::method(@_); |
|
145
|
197
|
50
|
|
|
|
263827
|
if ($self->config->{force_ssl}) { |
|
146
|
0
|
|
|
|
|
0
|
my $request = $self->request; |
|
147
|
0
|
|
|
|
|
0
|
$request->base->scheme('https'); |
|
148
|
0
|
|
|
|
|
0
|
$request->uri->scheme('https'); |
|
149
|
|
|
|
|
|
|
} |
|
150
|
197
|
|
|
|
|
17450
|
return $self; |
|
151
|
|
|
|
|
|
|
} |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
|
|
154
|
|
|
|
|
|
|
=head2 ajax |
|
155
|
|
|
|
|
|
|
|
|
156
|
|
|
|
|
|
|
Return whether the request is an AJAX one (used by the live preview, |
|
157
|
|
|
|
|
|
|
for example), as opposed to a rgular request (such as one used to view |
|
158
|
|
|
|
|
|
|
a page). |
|
159
|
|
|
|
|
|
|
|
|
160
|
|
|
|
|
|
|
=cut |
|
161
|
|
|
|
|
|
|
|
|
162
|
|
|
|
|
|
|
sub ajax { |
|
163
|
0
|
|
|
0
|
1
|
0
|
my ($c) = @_; |
|
164
|
0
|
|
0
|
|
|
0
|
return $c->req->header('x-requested-with') |
|
165
|
|
|
|
|
|
|
&& $c->req->header('x-requested-with') eq 'XMLHttpRequest'; |
|
166
|
|
|
|
|
|
|
} |
|
167
|
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
=head2 expand_wikilink |
|
169
|
|
|
|
|
|
|
|
|
170
|
|
|
|
|
|
|
Proxy method for the L<MojoMojo::Formatter::Wiki> expand_wikilink method. |
|
171
|
|
|
|
|
|
|
|
|
172
|
|
|
|
|
|
|
=cut |
|
173
|
|
|
|
|
|
|
|
|
174
|
|
|
|
|
|
|
sub expand_wikilink { |
|
175
|
105
|
|
|
105
|
1
|
2495
|
my $c = shift; |
|
176
|
105
|
|
|
|
|
796
|
return MojoMojo::Formatter::Wiki->expand_wikilink(@_); |
|
177
|
|
|
|
|
|
|
} |
|
178
|
|
|
|
|
|
|
|
|
179
|
|
|
|
|
|
|
=head2 wikiword |
|
180
|
|
|
|
|
|
|
|
|
181
|
|
|
|
|
|
|
Format a wikiword as a link or as a wanted page, as appropriate. |
|
182
|
|
|
|
|
|
|
|
|
183
|
|
|
|
|
|
|
=cut |
|
184
|
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub wikiword { |
|
186
|
62
|
|
|
62
|
1
|
4796
|
return MojoMojo::Formatter::Wiki->format_link(@_); |
|
187
|
|
|
|
|
|
|
} |
|
188
|
|
|
|
|
|
|
|
|
189
|
|
|
|
|
|
|
=head2 pref |
|
190
|
|
|
|
|
|
|
|
|
191
|
|
|
|
|
|
|
Find or create a preference key. Update it if a value is passed, then |
|
192
|
|
|
|
|
|
|
return the current setting. |
|
193
|
|
|
|
|
|
|
|
|
194
|
|
|
|
|
|
|
=cut |
|
195
|
|
|
|
|
|
|
|
|
196
|
|
|
|
|
|
|
sub pref { |
|
197
|
3145
|
|
|
3145
|
1
|
394071
|
my ($c, $setting, $value) = @_; |
|
198
|
|
|
|
|
|
|
|
|
199
|
3145
|
50
|
|
|
|
9223
|
return unless $setting; |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
# Unfortunately there are MojoMojo->pref() calls in |
|
202
|
|
|
|
|
|
|
# MojoMojo::Schema::Result::Person which makes it hard |
|
203
|
|
|
|
|
|
|
# to get cache working for those calls - so we'll just |
|
204
|
|
|
|
|
|
|
# not use caching for those calls. |
|
205
|
3145
|
100
|
|
|
|
14505
|
return $c->pref_cached($setting, $value) if ref($c) eq 'MojoMojo'; |
|
206
|
|
|
|
|
|
|
|
|
207
|
166
|
|
|
|
|
956
|
$setting |
|
208
|
|
|
|
|
|
|
= $c->model('DBIC::Preference')->find_or_create({prefkey => $setting}); |
|
209
|
165
|
50
|
|
|
|
757259
|
if (defined $value) { |
|
210
|
0
|
|
|
|
|
0
|
$setting->prefvalue($value); |
|
211
|
0
|
|
|
|
|
0
|
$setting->update(); |
|
212
|
0
|
|
|
|
|
0
|
return $value; |
|
213
|
|
|
|
|
|
|
} |
|
214
|
165
|
100
|
|
|
|
7036
|
return (defined $setting->prefvalue() ? $setting->prefvalue : ""); |
|
215
|
|
|
|
|
|
|
} |
|
216
|
|
|
|
|
|
|
|
|
217
|
|
|
|
|
|
|
=head2 pref_cached |
|
218
|
|
|
|
|
|
|
|
|
219
|
|
|
|
|
|
|
Get preference key/value from cache if possible. |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
=cut |
|
222
|
|
|
|
|
|
|
|
|
223
|
|
|
|
|
|
|
sub pref_cached { |
|
224
|
2979
|
|
|
2979
|
1
|
7170
|
my ($c, $setting, $value) = @_; |
|
225
|
|
|
|
|
|
|
|
|
226
|
|
|
|
|
|
|
# Already in cache and no new value to set? |
|
227
|
2979
|
100
|
100
|
|
|
11879
|
if (defined $c->cache->get($setting) and not defined $value) { |
|
228
|
2358
|
|
|
|
|
546248
|
return $c->cache->get($setting); |
|
229
|
|
|
|
|
|
|
} |
|
230
|
|
|
|
|
|
|
|
|
231
|
|
|
|
|
|
|
# Check that we have a database, i.e. script/mojomojo_spawn_db.pl was run. |
|
232
|
621
|
|
|
|
|
144161
|
my $row; |
|
233
|
621
|
|
|
|
|
3343
|
$row = $c->model('DBIC::Preference')->find_or_create({prefkey => $setting}); |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
# Update database |
|
236
|
621
|
100
|
|
|
|
2472196
|
$row->update({prefvalue => $value}) if defined $value; |
|
237
|
|
|
|
|
|
|
|
|
238
|
621
|
|
|
|
|
138321
|
my $prefvalue = $row->prefvalue(); |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
# if no entry in preferences, try get one from config or get default value |
|
241
|
621
|
100
|
|
|
|
12951
|
unless (defined $prefvalue) { |
|
242
|
|
|
|
|
|
|
|
|
243
|
502
|
100
|
|
|
|
6240
|
if ($setting eq 'main_formatter') { |
|
|
|
100
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
|
|
100
|
|
|
|
|
|
|
244
|
|
|
|
|
|
|
$prefvalue |
|
245
|
|
|
|
|
|
|
= defined $c->config->{'main_formatter'} |
|
246
|
14
|
50
|
|
|
|
106
|
? $c->config->{'main_formatter'} |
|
247
|
|
|
|
|
|
|
: 'MojoMojo::Formatter::Markdown'; |
|
248
|
|
|
|
|
|
|
} |
|
249
|
|
|
|
|
|
|
elsif ($setting eq 'default_lang') { |
|
250
|
|
|
|
|
|
|
$prefvalue |
|
251
|
30
|
50
|
|
|
|
186
|
= defined $c->config->{$setting} ? $c->config->{$setting} : 'en'; |
|
252
|
|
|
|
|
|
|
} |
|
253
|
|
|
|
|
|
|
elsif ($setting eq 'name') { |
|
254
|
|
|
|
|
|
|
$prefvalue |
|
255
|
0
|
0
|
|
|
|
0
|
= defined $c->config->{$setting} ? $c->config->{$setting} : 'MojoMojo'; |
|
256
|
|
|
|
|
|
|
} |
|
257
|
|
|
|
|
|
|
elsif ($setting eq 'theme') { |
|
258
|
|
|
|
|
|
|
$prefvalue |
|
259
|
0
|
0
|
|
|
|
0
|
= defined $c->config->{$setting} ? $c->config->{$setting} : 'default'; |
|
260
|
|
|
|
|
|
|
} |
|
261
|
|
|
|
|
|
|
elsif ($setting =~ /^(enforce_login|check_permission_on_view)$/) { |
|
262
|
|
|
|
|
|
|
$prefvalue |
|
263
|
|
|
|
|
|
|
= defined $c->config->{'permissions'}{$setting} |
|
264
|
50
|
50
|
|
|
|
301
|
? $c->config->{'permissions'}{$setting} |
|
265
|
|
|
|
|
|
|
: 0; |
|
266
|
|
|
|
|
|
|
} |
|
267
|
|
|
|
|
|
|
elsif ($setting |
|
268
|
|
|
|
|
|
|
=~ /^(cache_permission_data|create_allowed|delete_allowed|edit_allowed|view_allowed|attachment_allowed)$/ |
|
269
|
|
|
|
|
|
|
) |
|
270
|
|
|
|
|
|
|
{ |
|
271
|
|
|
|
|
|
|
$prefvalue |
|
272
|
|
|
|
|
|
|
= defined $c->config->{'permissions'}{$setting} |
|
273
|
132
|
50
|
|
|
|
770
|
? $c->config->{'permissions'}{$setting} |
|
274
|
|
|
|
|
|
|
: 1; |
|
275
|
|
|
|
|
|
|
} |
|
276
|
|
|
|
|
|
|
else { |
|
277
|
276
|
|
|
|
|
1822
|
$prefvalue = $c->config->{$setting}; |
|
278
|
|
|
|
|
|
|
} |
|
279
|
|
|
|
|
|
|
|
|
280
|
|
|
|
|
|
|
} |
|
281
|
|
|
|
|
|
|
|
|
282
|
|
|
|
|
|
|
# Update cache |
|
283
|
621
|
|
|
|
|
74619
|
$c->cache->set($setting => $prefvalue); |
|
284
|
|
|
|
|
|
|
|
|
285
|
621
|
|
|
|
|
197888
|
return $c->cache->get($setting); |
|
286
|
|
|
|
|
|
|
} |
|
287
|
|
|
|
|
|
|
|
|
288
|
|
|
|
|
|
|
=head2 fixw |
|
289
|
|
|
|
|
|
|
|
|
290
|
|
|
|
|
|
|
Clean up wiki words: replace spaces with underscores and remove non-\w, / and . |
|
291
|
|
|
|
|
|
|
characters. |
|
292
|
|
|
|
|
|
|
|
|
293
|
|
|
|
|
|
|
=cut |
|
294
|
|
|
|
|
|
|
|
|
295
|
|
|
|
|
|
|
sub fixw { |
|
296
|
0
|
|
|
0
|
1
|
0
|
my ($c, $w) = @_; |
|
297
|
0
|
|
|
|
|
0
|
$w =~ s/\s/\_/g; |
|
298
|
0
|
|
|
|
|
0
|
$w =~ s/[^\w\/\.]//g; |
|
299
|
0
|
|
|
|
|
0
|
return $w; |
|
300
|
|
|
|
|
|
|
} |
|
301
|
|
|
|
|
|
|
|
|
302
|
|
|
|
|
|
|
=head2 tz |
|
303
|
|
|
|
|
|
|
|
|
304
|
|
|
|
|
|
|
Convert timezone |
|
305
|
|
|
|
|
|
|
|
|
306
|
|
|
|
|
|
|
=cut |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
sub tz { |
|
309
|
107
|
|
|
107
|
1
|
68909
|
my ($c, $dt) = @_; |
|
310
|
107
|
50
|
66
|
|
|
696
|
if ($c->user && $c->user->timezone) { |
|
311
|
0
|
|
|
|
|
0
|
eval { $dt->set_time_zone($c->user->timezone) }; |
|
|
0
|
|
|
|
|
0
|
|
|
312
|
|
|
|
|
|
|
} |
|
313
|
107
|
|
|
|
|
94912
|
return $dt; |
|
314
|
|
|
|
|
|
|
} |
|
315
|
|
|
|
|
|
|
|
|
316
|
|
|
|
|
|
|
=head2 prepare_action |
|
317
|
|
|
|
|
|
|
|
|
318
|
|
|
|
|
|
|
Provide "No DB" message when one needs to spawn the db (script/mojomojo_spawn.pl). |
|
319
|
|
|
|
|
|
|
|
|
320
|
|
|
|
|
|
|
=cut |
|
321
|
|
|
|
|
|
|
|
|
322
|
|
|
|
|
|
|
sub prepare_action { |
|
323
|
|
|
|
|
|
|
my $c = shift; |
|
324
|
|
|
|
|
|
|
|
|
325
|
|
|
|
|
|
|
if ($has_DB) { |
|
326
|
|
|
|
|
|
|
$c->next::method(@_); |
|
327
|
|
|
|
|
|
|
} |
|
328
|
|
|
|
|
|
|
else { |
|
329
|
|
|
|
|
|
|
$c->res->status(404); |
|
330
|
|
|
|
|
|
|
$c->response->body($NO_DB_MESSAGE); |
|
331
|
|
|
|
|
|
|
return; |
|
332
|
|
|
|
|
|
|
} |
|
333
|
|
|
|
|
|
|
} |
|
334
|
|
|
|
|
|
|
|
|
335
|
|
|
|
|
|
|
=head2 prepare_path |
|
336
|
|
|
|
|
|
|
|
|
337
|
|
|
|
|
|
|
We override this method to work around some of Catalyst's assumptions about |
|
338
|
|
|
|
|
|
|
dispatching. Since MojoMojo supports page namespaces |
|
339
|
|
|
|
|
|
|
(e.g. C</parent_page/child_page>), with page paths that always start with C</>, |
|
340
|
|
|
|
|
|
|
we strip the trailing slash from C<< $c->req->base >>. Also, since MojoMojo |
|
341
|
|
|
|
|
|
|
indicates actions by appending a C<.$action> to the path |
|
342
|
|
|
|
|
|
|
(e.g. C</parent_page/child_page.edit>), we remove the page path and save it in |
|
343
|
|
|
|
|
|
|
C<< $c->stash->{path} >> and reset C<< $c->req->path >> to C<< $action >>. |
|
344
|
|
|
|
|
|
|
We save the original URI in C<< $c->stash->{pre_hacked_uri} >>. |
|
345
|
|
|
|
|
|
|
|
|
346
|
|
|
|
|
|
|
=cut |
|
347
|
|
|
|
|
|
|
|
|
348
|
|
|
|
|
|
|
sub prepare_path { |
|
349
|
197
|
|
|
197
|
1
|
1726708
|
my $c = shift; |
|
350
|
197
|
|
|
|
|
1308
|
$c->next::method(@_); |
|
351
|
197
|
|
|
|
|
102455
|
$c->stash->{pre_hacked_uri} = $c->req->uri->clone; |
|
352
|
197
|
|
|
|
|
24021
|
my $base = $c->req->base; |
|
353
|
197
|
|
|
|
|
10041
|
$base =~ s|/+$||; |
|
354
|
197
|
|
|
|
|
3237
|
$c->req->base(URI->new($base)); |
|
355
|
197
|
|
|
|
|
28488
|
my ($path, $action); |
|
356
|
197
|
|
|
|
|
892
|
$path = $c->req->path; |
|
357
|
|
|
|
|
|
|
|
|
358
|
197
|
100
|
|
|
|
33404
|
if ($path =~ /^special(?:\/|$)(.*)/) { |
|
359
|
12
|
|
|
|
|
50
|
$c->stash->{path} = $path; |
|
360
|
12
|
|
|
|
|
726
|
$c->req->path($1); |
|
361
|
|
|
|
|
|
|
} |
|
362
|
|
|
|
|
|
|
else { |
|
363
|
|
|
|
|
|
|
# find the *last* period, so that pages can have periods in their name. |
|
364
|
185
|
|
|
|
|
584
|
my $index = index($path, '.'); |
|
365
|
|
|
|
|
|
|
|
|
366
|
185
|
100
|
|
|
|
740
|
if ($index == -1) { |
|
367
|
|
|
|
|
|
|
|
|
368
|
|
|
|
|
|
|
# no action found, default to view |
|
369
|
24
|
|
|
|
|
250
|
$c->stash->{path} = $path; |
|
370
|
24
|
|
|
|
|
1561
|
$c->req->path('view'); |
|
371
|
|
|
|
|
|
|
} |
|
372
|
|
|
|
|
|
|
else { |
|
373
|
|
|
|
|
|
|
|
|
374
|
|
|
|
|
|
|
# set path in stash, and set req.path to action |
|
375
|
161
|
|
|
|
|
866
|
$c->stash->{path} = substr($path, 0, $index); |
|
376
|
161
|
|
|
|
|
10028
|
$c->req->path(substr($path, $index + 1)); |
|
377
|
|
|
|
|
|
|
} |
|
378
|
|
|
|
|
|
|
} |
|
379
|
197
|
50
|
|
|
|
25621
|
$c->stash->{path} = '/' . $c->stash->{path} unless ($path =~ m!^/!); |
|
380
|
|
|
|
|
|
|
} |
|
381
|
|
|
|
|
|
|
|
|
382
|
|
|
|
|
|
|
=head2 base_uri |
|
383
|
|
|
|
|
|
|
|
|
384
|
|
|
|
|
|
|
Return C<< $c->req->base >> as an URI object. |
|
385
|
|
|
|
|
|
|
|
|
386
|
|
|
|
|
|
|
=cut |
|
387
|
|
|
|
|
|
|
|
|
388
|
|
|
|
|
|
|
sub base_uri { |
|
389
|
5
|
|
|
5
|
1
|
15
|
my $c = shift; |
|
390
|
5
|
|
|
|
|
23
|
return URI->new($c->req->base); |
|
391
|
|
|
|
|
|
|
} |
|
392
|
|
|
|
|
|
|
|
|
393
|
|
|
|
|
|
|
=head2 uri_for |
|
394
|
|
|
|
|
|
|
|
|
395
|
|
|
|
|
|
|
Override C<< $c->uri_for >> to append path, if a relative path is used. |
|
396
|
|
|
|
|
|
|
|
|
397
|
|
|
|
|
|
|
=cut |
|
398
|
|
|
|
|
|
|
|
|
399
|
|
|
|
|
|
|
sub uri_for { |
|
400
|
4227
|
|
|
4227
|
1
|
149941
|
my $c = shift; |
|
401
|
4227
|
100
|
|
|
|
15774
|
unless ($_[0] =~ m/^\//) { |
|
402
|
2020
|
|
|
|
|
4329
|
my $val = shift @_; |
|
403
|
2020
|
50
|
|
|
|
7235
|
my $prefix = $c->stash->{path} =~ m|^/| ? '' : '/'; |
|
404
|
2020
|
|
|
|
|
149026
|
unshift(@_, $prefix . $c->stash->{path} . '.' . $val); |
|
405
|
|
|
|
|
|
|
} |
|
406
|
|
|
|
|
|
|
|
|
407
|
|
|
|
|
|
|
# do I see unicode here? |
|
408
|
4227
|
100
|
|
|
|
128867
|
if (Encode::is_utf8($_[0])) { |
|
409
|
|
|
|
|
|
|
$_[0] |
|
410
|
36
|
|
|
|
|
226
|
= join('/', map { URI::Escape::uri_escape_utf8($_) } split(/\//, $_[0])); |
|
|
82
|
|
|
|
|
1237
|
|
|
411
|
|
|
|
|
|
|
} |
|
412
|
|
|
|
|
|
|
|
|
413
|
4227
|
|
|
|
|
15627
|
my $res = $c->next::method(@_); |
|
414
|
4227
|
50
|
|
|
|
716123
|
$res->scheme('https') if $c->config->{'force_ssl'}; |
|
415
|
4227
|
|
|
|
|
398513
|
return $res; |
|
416
|
|
|
|
|
|
|
} |
|
417
|
|
|
|
|
|
|
|
|
418
|
|
|
|
|
|
|
=head2 uri_for_static |
|
419
|
|
|
|
|
|
|
|
|
420
|
|
|
|
|
|
|
C</static/> has been remapped to C</.static/>. |
|
421
|
|
|
|
|
|
|
|
|
422
|
|
|
|
|
|
|
=cut |
|
423
|
|
|
|
|
|
|
|
|
424
|
|
|
|
|
|
|
sub uri_for_static { |
|
425
|
1688
|
|
|
1688
|
1
|
13719
|
my ($self, $asset) = @_; |
|
426
|
|
|
|
|
|
|
return ( |
|
427
|
|
|
|
|
|
|
defined($self->config->{static_path}) |
|
428
|
1688
|
50
|
|
|
|
5067
|
? $self->config->{static_path} . $asset |
|
429
|
|
|
|
|
|
|
: $self->uri_for('/.static', $asset)); |
|
430
|
|
|
|
|
|
|
} |
|
431
|
|
|
|
|
|
|
|
|
432
|
|
|
|
|
|
|
=head2 _cleanup_path |
|
433
|
|
|
|
|
|
|
|
|
434
|
|
|
|
|
|
|
Lowercase the path and remove any double-slashes. |
|
435
|
|
|
|
|
|
|
|
|
436
|
|
|
|
|
|
|
=cut |
|
437
|
|
|
|
|
|
|
|
|
438
|
|
|
|
|
|
|
sub _cleanup_path { |
|
439
|
117
|
|
|
117
|
|
381
|
my ($c, $path) = @_; |
|
440
|
|
|
|
|
|
|
## Make some changes to the path - we have to do this |
|
441
|
|
|
|
|
|
|
## because path is not always cleaned up before we get it: |
|
442
|
|
|
|
|
|
|
## sometimes we get caps, other times we don't. Permissions are |
|
443
|
|
|
|
|
|
|
## set using lowercase paths. |
|
444
|
|
|
|
|
|
|
|
|
445
|
|
|
|
|
|
|
## lowercase the path - and ensure it has a leading / |
|
446
|
117
|
|
|
|
|
411
|
my $searchpath = lc($path); |
|
447
|
|
|
|
|
|
|
|
|
448
|
|
|
|
|
|
|
# clear out any double-slashes |
|
449
|
117
|
|
|
|
|
385
|
$searchpath =~ s|//|/|g; |
|
450
|
|
|
|
|
|
|
|
|
451
|
117
|
|
|
|
|
359
|
return $searchpath; |
|
452
|
|
|
|
|
|
|
} |
|
453
|
|
|
|
|
|
|
|
|
454
|
|
|
|
|
|
|
=head2 _expand_path_elements |
|
455
|
|
|
|
|
|
|
|
|
456
|
|
|
|
|
|
|
Generate all the intermediary paths to C</path/to/a/page>, starting from C</> |
|
457
|
|
|
|
|
|
|
and ending with the complete path: |
|
458
|
|
|
|
|
|
|
|
|
459
|
|
|
|
|
|
|
/ |
|
460
|
|
|
|
|
|
|
/path |
|
461
|
|
|
|
|
|
|
/path/to |
|
462
|
|
|
|
|
|
|
/path/to/a |
|
463
|
|
|
|
|
|
|
/path/to/a/page |
|
464
|
|
|
|
|
|
|
|
|
465
|
|
|
|
|
|
|
=cut |
|
466
|
|
|
|
|
|
|
|
|
467
|
|
|
|
|
|
|
sub _expand_path_elements { |
|
468
|
117
|
|
|
117
|
|
17099
|
my ($c, $path) = @_; |
|
469
|
117
|
|
|
|
|
550
|
my $searchpath = $c->_cleanup_path($path); |
|
470
|
|
|
|
|
|
|
|
|
471
|
117
|
|
|
|
|
609
|
my @pathelements = split '/', $searchpath; |
|
472
|
|
|
|
|
|
|
|
|
473
|
117
|
100
|
66
|
|
|
747
|
if (@pathelements && $pathelements[0] eq '') { |
|
474
|
43
|
|
|
|
|
125
|
shift @pathelements; |
|
475
|
|
|
|
|
|
|
} |
|
476
|
|
|
|
|
|
|
|
|
477
|
117
|
|
|
|
|
385
|
my @paths_to_check = ('/'); |
|
478
|
|
|
|
|
|
|
|
|
479
|
117
|
|
|
|
|
316
|
my $current_path = ''; |
|
480
|
|
|
|
|
|
|
|
|
481
|
117
|
|
|
|
|
334
|
foreach my $pathitem (@pathelements) { |
|
482
|
54
|
|
|
|
|
156
|
$current_path .= "/" . $pathitem; |
|
483
|
54
|
|
|
|
|
146
|
push @paths_to_check, $current_path; |
|
484
|
|
|
|
|
|
|
} |
|
485
|
|
|
|
|
|
|
|
|
486
|
117
|
|
|
|
|
428
|
return @paths_to_check; |
|
487
|
|
|
|
|
|
|
} |
|
488
|
|
|
|
|
|
|
|
|
489
|
|
|
|
|
|
|
=head2 get_permissions_data |
|
490
|
|
|
|
|
|
|
|
|
491
|
|
|
|
|
|
|
Permissions are checked prior to most actions, including C<view> if that is |
|
492
|
|
|
|
|
|
|
turned on in the configuration. The permission system works as follows: |
|
493
|
|
|
|
|
|
|
|
|
494
|
|
|
|
|
|
|
=over |
|
495
|
|
|
|
|
|
|
|
|
496
|
|
|
|
|
|
|
=item 1. |
|
497
|
|
|
|
|
|
|
|
|
498
|
|
|
|
|
|
|
There is a base set of rules which may be defined in the application |
|
499
|
|
|
|
|
|
|
config. These are: |
|
500
|
|
|
|
|
|
|
|
|
501
|
|
|
|
|
|
|
$c->config->{permissions}{view_allowed} = 1; # or 0 |
|
502
|
|
|
|
|
|
|
|
|
503
|
|
|
|
|
|
|
Similar entries exist for C<delete>, C<edit>, C<create> and C<attachment>. |
|
504
|
|
|
|
|
|
|
If these config variables are not defined, the default is to allow anyone |
|
505
|
|
|
|
|
|
|
to do anything. |
|
506
|
|
|
|
|
|
|
|
|
507
|
|
|
|
|
|
|
=item 2. |
|
508
|
|
|
|
|
|
|
|
|
509
|
|
|
|
|
|
|
Global rules that apply to everyone may be specified by creating a |
|
510
|
|
|
|
|
|
|
record with a role id of 0. |
|
511
|
|
|
|
|
|
|
|
|
512
|
|
|
|
|
|
|
=item 3. |
|
513
|
|
|
|
|
|
|
|
|
514
|
|
|
|
|
|
|
Rules are defined using a combination of path(s)?, and role and may be |
|
515
|
|
|
|
|
|
|
applied to subpages or not. |
|
516
|
|
|
|
|
|
|
|
|
517
|
|
|
|
|
|
|
TODO: clarify. |
|
518
|
|
|
|
|
|
|
|
|
519
|
|
|
|
|
|
|
=item 4. |
|
520
|
|
|
|
|
|
|
|
|
521
|
|
|
|
|
|
|
All rules matching a given user's roles and the current path are used to |
|
522
|
|
|
|
|
|
|
determine the final yes/no on each permission. Rules are evaluated from |
|
523
|
|
|
|
|
|
|
least-specific path to most specific. This means that when checking |
|
524
|
|
|
|
|
|
|
permissions on C</foo/bar/baz>, permission rules set for C</foo> will be |
|
525
|
|
|
|
|
|
|
overridden by rules set on C</foo/bar> when editing C</foo/bar/baz>. When two |
|
526
|
|
|
|
|
|
|
rules (from different roles) are found for the same path prefix, explicit |
|
527
|
|
|
|
|
|
|
C<allow>s override C<deny>s. Null entries for a given permission are always |
|
528
|
|
|
|
|
|
|
ignored and do not affect the permissions defined at earlier level. This |
|
529
|
|
|
|
|
|
|
allows you to change certain permissions (such as C<create>) only while not |
|
530
|
|
|
|
|
|
|
affecting previously determined permissions for the other actions. Finally - |
|
531
|
|
|
|
|
|
|
C<apply_to_subpages> C<yes>/C<no> is exclusive, meaning that a rule for C</foo> with |
|
532
|
|
|
|
|
|
|
C<apply_to_subpages> set to C<yes> will apply to C</foo/bar> but not to C</foo> |
|
533
|
|
|
|
|
|
|
alone. The endpoint in the path is always checked for a rule explicitly for that |
|
534
|
|
|
|
|
|
|
page - meaning C<apply_to_subpages = no>. |
|
535
|
|
|
|
|
|
|
|
|
536
|
|
|
|
|
|
|
=back |
|
537
|
|
|
|
|
|
|
|
|
538
|
|
|
|
|
|
|
=cut |
|
539
|
|
|
|
|
|
|
|
|
540
|
|
|
|
|
|
|
sub get_permissions_data { |
|
541
|
117
|
|
|
117
|
1
|
453
|
my ($c, $current_path, $paths_to_check, $role_ids) = @_; |
|
542
|
|
|
|
|
|
|
|
|
543
|
|
|
|
|
|
|
# default to roles for current user |
|
544
|
117
|
|
33
|
|
|
494
|
$role_ids ||= $c->user_role_ids($c->user); |
|
545
|
|
|
|
|
|
|
|
|
546
|
117
|
|
|
|
|
258
|
my $permdata; |
|
547
|
|
|
|
|
|
|
|
|
548
|
|
|
|
|
|
|
## Now that we have our path elements to check, we have to figure out how we are accessing them. |
|
549
|
|
|
|
|
|
|
## If we have caching turned on, we load the perms from the cache and walk the tree. |
|
550
|
|
|
|
|
|
|
## Otherwise we pull what we need out of the DB. The structure is: |
|
551
|
|
|
|
|
|
|
# $permdata{$pagepath} = { |
|
552
|
|
|
|
|
|
|
# admin => { |
|
553
|
|
|
|
|
|
|
# page => { |
|
554
|
|
|
|
|
|
|
# create => 'yes', |
|
555
|
|
|
|
|
|
|
# delete => 'yes', |
|
556
|
|
|
|
|
|
|
# view => 'yes', |
|
557
|
|
|
|
|
|
|
# edit => 'yes', |
|
558
|
|
|
|
|
|
|
# attachment => 'yes', |
|
559
|
|
|
|
|
|
|
# }, |
|
560
|
|
|
|
|
|
|
# subpages => { |
|
561
|
|
|
|
|
|
|
# create => 'yes', |
|
562
|
|
|
|
|
|
|
# delete => 'yes', |
|
563
|
|
|
|
|
|
|
# view => 'yes', |
|
564
|
|
|
|
|
|
|
# edit => 'yes', |
|
565
|
|
|
|
|
|
|
# attachment => 'yes', |
|
566
|
|
|
|
|
|
|
# }, |
|
567
|
|
|
|
|
|
|
# }, |
|
568
|
|
|
|
|
|
|
# users => ..... |
|
569
|
|
|
|
|
|
|
# } |
|
570
|
117
|
100
|
|
|
|
485
|
if ($c->pref('cache_permission_data')) { |
|
571
|
113
|
|
|
|
|
22613
|
$permdata = $c->cache->get('page_permission_data'); |
|
572
|
|
|
|
|
|
|
} |
|
573
|
|
|
|
|
|
|
|
|
574
|
|
|
|
|
|
|
# If we don't have any permissions data, we have a problem. We need to load it. |
|
575
|
|
|
|
|
|
|
# We have two options here - if we are caching, we will load everything and cache it. |
|
576
|
|
|
|
|
|
|
# If we are not - then we load just the bits we need. |
|
577
|
117
|
100
|
|
|
|
24813
|
if (!$permdata) { |
|
578
|
|
|
|
|
|
|
|
|
579
|
|
|
|
|
|
|
# Initialize $permdata as a reference or we end up with an error |
|
580
|
|
|
|
|
|
|
# when we try to dereference it further down. The error we're avoiding is: |
|
581
|
|
|
|
|
|
|
# Can't use string ("") as a HASH ref while "strict refs" |
|
582
|
26
|
|
|
|
|
80
|
$permdata = {}; |
|
583
|
|
|
|
|
|
|
|
|
584
|
|
|
|
|
|
|
## Either the data hasn't been loaded, or it's expired since we used it last, |
|
585
|
|
|
|
|
|
|
## so we need to reload it. |
|
586
|
26
|
|
|
|
|
142
|
my $rs = $c->model('DBIC::PathPermissions') |
|
587
|
|
|
|
|
|
|
->search(undef, {order_by => 'length(path),role,apply_to_subpages'}); |
|
588
|
|
|
|
|
|
|
|
|
589
|
|
|
|
|
|
|
# If we are not caching, we don't return the whole enchilada. |
|
590
|
26
|
100
|
|
|
|
22642
|
if (!$c->pref('cache_permission_data')) { |
|
591
|
|
|
|
|
|
|
## this seems odd to me - but that's what the DBIx::Class says to do. |
|
592
|
4
|
50
|
|
|
|
743
|
$rs = $rs->search({role => $role_ids}) if $role_ids; |
|
593
|
4
|
|
|
|
|
809
|
$rs = $rs->search( |
|
594
|
|
|
|
|
|
|
{ |
|
595
|
|
|
|
|
|
|
'-or' => [ |
|
596
|
|
|
|
|
|
|
{path => $paths_to_check, apply_to_subpages => 'yes'}, |
|
597
|
|
|
|
|
|
|
{path => $current_path, apply_to_subpages => 'no'} |
|
598
|
|
|
|
|
|
|
] |
|
599
|
|
|
|
|
|
|
} |
|
600
|
|
|
|
|
|
|
); |
|
601
|
|
|
|
|
|
|
} |
|
602
|
26
|
|
|
|
|
7344
|
$rs->result_class('DBIx::Class::ResultClass::HashRefInflator'); |
|
603
|
|
|
|
|
|
|
|
|
604
|
26
|
|
|
|
|
1213
|
my $recordtype; |
|
605
|
26
|
|
|
|
|
212
|
while (my $record = $rs->next) { |
|
606
|
228
|
100
|
|
|
|
89043
|
if ($record->{'apply_to_subpages'} eq 'yes') { |
|
607
|
116
|
|
|
|
|
233
|
$recordtype = 'subpages'; |
|
608
|
|
|
|
|
|
|
} |
|
609
|
|
|
|
|
|
|
else { |
|
610
|
112
|
|
|
|
|
224
|
$recordtype = 'page'; |
|
611
|
|
|
|
|
|
|
} |
|
612
|
228
|
|
|
|
|
1800
|
%{$permdata->{$record->{'path'}}{$record->{'role'}}{$recordtype}} |
|
613
|
228
|
|
|
|
|
420
|
= map { $_ => $record->{$_ . "_allowed"} } |
|
|
1140
|
|
|
|
|
2410
|
|
|
614
|
|
|
|
|
|
|
qw/create edit view delete attachment/; |
|
615
|
|
|
|
|
|
|
} |
|
616
|
|
|
|
|
|
|
} |
|
617
|
|
|
|
|
|
|
|
|
618
|
|
|
|
|
|
|
## now we re-cache it - if we need to. # !$c->cache('memory')->exists('page_permission_data') |
|
619
|
117
|
100
|
|
|
|
4923
|
if ($c->pref('cache_permission_data')) { |
|
620
|
113
|
|
|
|
|
20940
|
$c->cache->set('page_permission_data', $permdata); |
|
621
|
|
|
|
|
|
|
} |
|
622
|
|
|
|
|
|
|
|
|
623
|
117
|
|
|
|
|
31224
|
return $permdata; |
|
624
|
|
|
|
|
|
|
} |
|
625
|
|
|
|
|
|
|
|
|
626
|
|
|
|
|
|
|
=head2 user_role_ids |
|
627
|
|
|
|
|
|
|
|
|
628
|
|
|
|
|
|
|
Get the list of role ids for a user. |
|
629
|
|
|
|
|
|
|
|
|
630
|
|
|
|
|
|
|
=cut |
|
631
|
|
|
|
|
|
|
|
|
632
|
|
|
|
|
|
|
sub user_role_ids { |
|
633
|
117
|
|
|
117
|
1
|
348
|
my ($c, $user) = @_; |
|
634
|
|
|
|
|
|
|
|
|
635
|
|
|
|
|
|
|
## always use role_id 0 - which is default role and includes everyone. |
|
636
|
117
|
|
|
|
|
311
|
my @role_ids = (0); |
|
637
|
|
|
|
|
|
|
|
|
638
|
117
|
50
|
|
|
|
462
|
if (ref($user)) { |
|
639
|
117
|
|
|
|
|
2706
|
push @role_ids, map { $_->role->id } $user->role_members->all; |
|
|
117
|
|
|
|
|
409072
|
|
|
640
|
|
|
|
|
|
|
} |
|
641
|
|
|
|
|
|
|
|
|
642
|
117
|
|
|
|
|
774688
|
return @role_ids; |
|
643
|
|
|
|
|
|
|
} |
|
644
|
|
|
|
|
|
|
|
|
645
|
|
|
|
|
|
|
=head2 check_permissions |
|
646
|
|
|
|
|
|
|
|
|
647
|
|
|
|
|
|
|
Check user permissions for a path. |
|
648
|
|
|
|
|
|
|
|
|
649
|
|
|
|
|
|
|
=cut |
|
650
|
|
|
|
|
|
|
|
|
651
|
|
|
|
|
|
|
sub check_permissions { |
|
652
|
191
|
|
|
191
|
1
|
125073
|
my ($c, $path, $user) = @_; |
|
653
|
|
|
|
|
|
|
|
|
654
|
191
|
100
|
100
|
|
|
1689
|
return {attachment => 1, create => 1, delete => 1, edit => 1, view => 1,} |
|
655
|
|
|
|
|
|
|
if ($user && $user->is_admin); |
|
656
|
|
|
|
|
|
|
|
|
657
|
|
|
|
|
|
|
# if no user is logged in |
|
658
|
117
|
100
|
|
|
|
432
|
if (not $user) { |
|
659
|
|
|
|
|
|
|
|
|
660
|
|
|
|
|
|
|
# if anonymous user is allowed |
|
661
|
106
|
|
|
|
|
394
|
my $anonymous = $c->pref('anonymous_user'); |
|
662
|
106
|
50
|
|
|
|
20288
|
if ($anonymous) { |
|
663
|
|
|
|
|
|
|
|
|
664
|
|
|
|
|
|
|
# get anonymous user for no logged-in users |
|
665
|
106
|
|
|
|
|
585
|
$user = $c->model('DBIC::Person')->search({login => $anonymous})->first; |
|
666
|
|
|
|
|
|
|
} |
|
667
|
|
|
|
|
|
|
} |
|
668
|
|
|
|
|
|
|
|
|
669
|
117
|
|
|
|
|
428752
|
my @paths_to_check = $c->_expand_path_elements($path); |
|
670
|
117
|
|
|
|
|
294
|
my $current_path = $paths_to_check[-1]; |
|
671
|
|
|
|
|
|
|
|
|
672
|
117
|
|
|
|
|
482
|
my @role_ids = $c->user_role_ids($user); |
|
673
|
|
|
|
|
|
|
|
|
674
|
117
|
|
|
|
|
9640
|
my $permdata |
|
675
|
|
|
|
|
|
|
= $c->get_permissions_data($current_path, \@paths_to_check, \@role_ids); |
|
676
|
|
|
|
|
|
|
|
|
677
|
|
|
|
|
|
|
# rules comparison hash |
|
678
|
|
|
|
|
|
|
# allow everything by default |
|
679
|
117
|
|
|
|
|
509
|
my %rulescomparison = ( |
|
680
|
|
|
|
|
|
|
'create' => { |
|
681
|
|
|
|
|
|
|
'allowed' => $c->pref('create_allowed'), |
|
682
|
|
|
|
|
|
|
'role' => '__default', |
|
683
|
|
|
|
|
|
|
'len' => 0, |
|
684
|
|
|
|
|
|
|
}, |
|
685
|
|
|
|
|
|
|
'delete' => { |
|
686
|
|
|
|
|
|
|
'allowed' => $c->pref('delete_allowed'), |
|
687
|
|
|
|
|
|
|
'role' => '__default', |
|
688
|
|
|
|
|
|
|
'len' => 0, |
|
689
|
|
|
|
|
|
|
}, |
|
690
|
|
|
|
|
|
|
'edit' => { |
|
691
|
|
|
|
|
|
|
'allowed' => $c->pref('edit_allowed'), |
|
692
|
|
|
|
|
|
|
'role' => '__default', |
|
693
|
|
|
|
|
|
|
'len' => 0, |
|
694
|
|
|
|
|
|
|
}, |
|
695
|
|
|
|
|
|
|
'view' => { |
|
696
|
|
|
|
|
|
|
'allowed' => $c->pref('view_allowed'), |
|
697
|
|
|
|
|
|
|
'role' => '__default', |
|
698
|
|
|
|
|
|
|
'len' => 0, |
|
699
|
|
|
|
|
|
|
}, |
|
700
|
|
|
|
|
|
|
'attachment' => { |
|
701
|
|
|
|
|
|
|
'allowed' => $c->pref('attachment_allowed'), |
|
702
|
|
|
|
|
|
|
'role' => '__default', |
|
703
|
|
|
|
|
|
|
'len' => 0, |
|
704
|
|
|
|
|
|
|
}, |
|
705
|
|
|
|
|
|
|
); |
|
706
|
|
|
|
|
|
|
|
|
707
|
|
|
|
|
|
|
## The outcome of this loop is a combined permission set. |
|
708
|
|
|
|
|
|
|
## The rule orders are essentially based on how specific the path |
|
709
|
|
|
|
|
|
|
## match is. More specific paths override less specific paths. |
|
710
|
|
|
|
|
|
|
## When conflicting rules at the same level of path hierarchy |
|
711
|
|
|
|
|
|
|
## (with different roles) are discovered, the grant is given precedence |
|
712
|
|
|
|
|
|
|
## over the deny. Note that more-specific denies will still |
|
713
|
|
|
|
|
|
|
## override. |
|
714
|
117
|
|
|
|
|
22452
|
my $permtype = 'subpages'; |
|
715
|
117
|
|
|
|
|
554
|
foreach my $i (0 .. $#paths_to_check) { |
|
716
|
171
|
|
|
|
|
425
|
my $path = $paths_to_check[$i]; |
|
717
|
171
|
100
|
|
|
|
657
|
if ($i == $#paths_to_check) { |
|
718
|
117
|
|
|
|
|
298
|
$permtype = 'page'; |
|
719
|
|
|
|
|
|
|
} |
|
720
|
171
|
|
|
|
|
460
|
foreach my $role (@role_ids) { |
|
721
|
342
|
50
|
66
|
|
|
1932
|
if ( exists($permdata->{$path}) |
|
|
|
|
66
|
|
|
|
|
|
722
|
|
|
|
|
|
|
&& exists($permdata->{$path}{$role}) |
|
723
|
|
|
|
|
|
|
&& exists($permdata->{$path}{$role}{$permtype})) |
|
724
|
|
|
|
|
|
|
{ |
|
725
|
|
|
|
|
|
|
|
|
726
|
119
|
|
|
|
|
295
|
my $len = length($path); |
|
727
|
|
|
|
|
|
|
|
|
728
|
119
|
|
|
|
|
271
|
foreach my $perm (keys %{$permdata->{$path}{$role}{$permtype}}) { |
|
|
119
|
|
|
|
|
570
|
|
|
729
|
|
|
|
|
|
|
|
|
730
|
|
|
|
|
|
|
## if the xxxx_allowed column is null, this permission is ignored. |
|
731
|
595
|
50
|
|
|
|
1543
|
if (defined($permdata->{$path}{$role}{$permtype}{$perm})) { |
|
732
|
595
|
50
|
|
|
|
1907
|
if ($len == $rulescomparison{$perm}{'len'}) { |
|
|
|
50
|
|
|
|
|
|
|
733
|
0
|
0
|
|
|
|
0
|
if ($permdata->{$path}{$role}{$permtype}{$perm} eq 'yes') { |
|
734
|
0
|
|
|
|
|
0
|
$rulescomparison{$perm}{'allowed'} = 1; |
|
735
|
0
|
|
|
|
|
0
|
$rulescomparison{$perm}{'len'} = $len; |
|
736
|
0
|
|
|
|
|
0
|
$rulescomparison{$perm}{'role'} = $role; |
|
737
|
|
|
|
|
|
|
} |
|
738
|
|
|
|
|
|
|
} |
|
739
|
|
|
|
|
|
|
elsif ($len > $rulescomparison{$perm}{'len'}) { |
|
740
|
595
|
100
|
|
|
|
1444
|
if ($permdata->{$path}{$role}{$permtype}{$perm} eq 'yes') { |
|
741
|
365
|
|
|
|
|
708
|
$rulescomparison{$perm}{'allowed'} = 1; |
|
742
|
|
|
|
|
|
|
} |
|
743
|
|
|
|
|
|
|
else { |
|
744
|
230
|
|
|
|
|
463
|
$rulescomparison{$perm}{'allowed'} = 0; |
|
745
|
|
|
|
|
|
|
} |
|
746
|
595
|
|
|
|
|
960
|
$rulescomparison{$perm}{'len'} = $len; |
|
747
|
595
|
|
|
|
|
1412
|
$rulescomparison{$perm}{'role'} = $role; |
|
748
|
|
|
|
|
|
|
} |
|
749
|
|
|
|
|
|
|
} |
|
750
|
|
|
|
|
|
|
} |
|
751
|
|
|
|
|
|
|
} |
|
752
|
|
|
|
|
|
|
} |
|
753
|
|
|
|
|
|
|
} |
|
754
|
|
|
|
|
|
|
|
|
755
|
|
|
|
|
|
|
my %perms |
|
756
|
117
|
|
|
|
|
474
|
= map { $_ => $rulescomparison{$_}{'allowed'} } keys %rulescomparison; |
|
|
585
|
|
|
|
|
1413
|
|
|
757
|
|
|
|
|
|
|
|
|
758
|
117
|
|
|
|
|
3018
|
return \%perms; |
|
759
|
|
|
|
|
|
|
} |
|
760
|
|
|
|
|
|
|
|
|
761
|
|
|
|
|
|
|
=head2 check_view_permission |
|
762
|
|
|
|
|
|
|
|
|
763
|
|
|
|
|
|
|
Check if a user can view a path. |
|
764
|
|
|
|
|
|
|
|
|
765
|
|
|
|
|
|
|
=cut |
|
766
|
|
|
|
|
|
|
|
|
767
|
|
|
|
|
|
|
sub check_view_permission { |
|
768
|
36
|
|
|
36
|
1
|
94
|
my $c = shift; |
|
769
|
|
|
|
|
|
|
|
|
770
|
36
|
50
|
|
|
|
190
|
return 1 unless $c->pref('check_permission_on_view'); |
|
771
|
|
|
|
|
|
|
|
|
772
|
36
|
|
|
|
|
7490
|
my $user; |
|
773
|
36
|
100
|
|
|
|
216
|
if ($c->user_exists()) { |
|
774
|
14
|
|
|
|
|
1948
|
$user = $c->user->obj; |
|
775
|
|
|
|
|
|
|
} |
|
776
|
|
|
|
|
|
|
|
|
777
|
36
|
50
|
|
|
|
24153
|
$c->log->info('Checking permissions') if $c->debug; |
|
778
|
|
|
|
|
|
|
|
|
779
|
36
|
|
|
|
|
303
|
my $perms = $c->check_permissions($c->stash->{path}, $user); |
|
780
|
36
|
50
|
|
|
|
999
|
if (!$perms->{view}) { |
|
781
|
|
|
|
|
|
|
$c->stash->{message} |
|
782
|
0
|
|
|
|
|
0
|
= $c->loc('Permission Denied to view x', $c->stash->{page}->name); |
|
783
|
0
|
|
|
|
|
0
|
$c->stash->{template} = 'message.tt'; |
|
784
|
0
|
|
|
|
|
0
|
return; |
|
785
|
|
|
|
|
|
|
} |
|
786
|
|
|
|
|
|
|
|
|
787
|
36
|
|
|
|
|
258
|
return 1; |
|
788
|
|
|
|
|
|
|
} |
|
789
|
|
|
|
|
|
|
|
|
790
|
|
|
|
|
|
|
my $search_setup_failed = 0; |
|
791
|
|
|
|
|
|
|
|
|
792
|
|
|
|
|
|
|
MojoMojo->config->{index_dir} ||= MojoMojo->path_to('index'); |
|
793
|
|
|
|
|
|
|
MojoMojo->config->{attachment_dir} ||= MojoMojo->path_to('uploads'); |
|
794
|
|
|
|
|
|
|
MojoMojo->config->{root} ||= MojoMojo->path_to('root'); |
|
795
|
|
|
|
|
|
|
unless (-e MojoMojo->config->{index_dir}) { |
|
796
|
|
|
|
|
|
|
if (not mkdir MojoMojo->config->{index_dir}) { |
|
797
|
|
|
|
|
|
|
warn 'Could not make index directory <' |
|
798
|
|
|
|
|
|
|
. MojoMojo->config->{index_dir} |
|
799
|
|
|
|
|
|
|
. '> - FIX IT OR SEARCH WILL NOT WORK!'; |
|
800
|
|
|
|
|
|
|
$search_setup_failed = 1; |
|
801
|
|
|
|
|
|
|
} |
|
802
|
|
|
|
|
|
|
} |
|
803
|
|
|
|
|
|
|
unless (-w MojoMojo->config->{index_dir}) { |
|
804
|
|
|
|
|
|
|
warn 'Require write access to index <' |
|
805
|
|
|
|
|
|
|
. MojoMojo->config->{index_dir} |
|
806
|
|
|
|
|
|
|
. '> - FIX IT OR SEARCH WILL NOT WORK!'; |
|
807
|
|
|
|
|
|
|
$search_setup_failed = 1; |
|
808
|
|
|
|
|
|
|
} |
|
809
|
|
|
|
|
|
|
|
|
810
|
|
|
|
|
|
|
MojoMojo->model('Search')->prepare_search_index() |
|
811
|
|
|
|
|
|
|
if not -f MojoMojo->config->{index_dir} . '/segments' |
|
812
|
|
|
|
|
|
|
and not $search_setup_failed |
|
813
|
|
|
|
|
|
|
and not MojoMojo->pref('disable_search'); |
|
814
|
|
|
|
|
|
|
|
|
815
|
|
|
|
|
|
|
unless (-e MojoMojo->config->{attachment_dir}) { |
|
816
|
|
|
|
|
|
|
mkdir MojoMojo->config->{attachment_dir} |
|
817
|
|
|
|
|
|
|
or die 'Could not make attachment directory <' |
|
818
|
|
|
|
|
|
|
. MojoMojo->config->{attachment_dir} . '>'; |
|
819
|
|
|
|
|
|
|
} |
|
820
|
|
|
|
|
|
|
die 'Require write access to attachment_dir: <' |
|
821
|
|
|
|
|
|
|
. MojoMojo->config->{attachment_dir} . '>' |
|
822
|
|
|
|
|
|
|
unless -w MojoMojo->config->{attachment_dir}; |
|
823
|
|
|
|
|
|
|
|
|
824
|
|
|
|
|
|
|
1; |
|
825
|
|
|
|
|
|
|
|
|
826
|
|
|
|
|
|
|
=head1 SUPPORT |
|
827
|
|
|
|
|
|
|
|
|
828
|
|
|
|
|
|
|
=over |
|
829
|
|
|
|
|
|
|
|
|
830
|
|
|
|
|
|
|
=item * |
|
831
|
|
|
|
|
|
|
|
|
832
|
|
|
|
|
|
|
L<http://mojomojo.org> |
|
833
|
|
|
|
|
|
|
|
|
834
|
|
|
|
|
|
|
=item * |
|
835
|
|
|
|
|
|
|
|
|
836
|
|
|
|
|
|
|
IRC: L<irc://irc.perl.org/mojomojo>. |
|
837
|
|
|
|
|
|
|
|
|
838
|
|
|
|
|
|
|
=item * |
|
839
|
|
|
|
|
|
|
|
|
840
|
|
|
|
|
|
|
Mailing list: L<http://mojomojo.2358427.n2.nabble.com/> |
|
841
|
|
|
|
|
|
|
|
|
842
|
|
|
|
|
|
|
=item * |
|
843
|
|
|
|
|
|
|
|
|
844
|
|
|
|
|
|
|
Commercial support and customization for MojoMojo is also provided by Nordaaker |
|
845
|
|
|
|
|
|
|
Ltd. Contact C<arneandmarcus@nordaaker.com> for details. |
|
846
|
|
|
|
|
|
|
|
|
847
|
|
|
|
|
|
|
=back |
|
848
|
|
|
|
|
|
|
|
|
849
|
|
|
|
|
|
|
=head1 AUTHORS |
|
850
|
|
|
|
|
|
|
|
|
851
|
|
|
|
|
|
|
Marcus Ramberg C<marcus@nordaaker.com> |
|
852
|
|
|
|
|
|
|
|
|
853
|
|
|
|
|
|
|
David Naughton C<naughton@umn.edu> |
|
854
|
|
|
|
|
|
|
|
|
855
|
|
|
|
|
|
|
Andy Grundman C<andy@hybridized.org> |
|
856
|
|
|
|
|
|
|
|
|
857
|
|
|
|
|
|
|
Jonathan Rockway C<jrockway@jrockway.us> |
|
858
|
|
|
|
|
|
|
|
|
859
|
|
|
|
|
|
|
A number of other contributors over the years: |
|
860
|
|
|
|
|
|
|
https://www.ohloh.net/p/mojomojo/contributors |
|
861
|
|
|
|
|
|
|
|
|
862
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
863
|
|
|
|
|
|
|
|
|
864
|
|
|
|
|
|
|
Unless explicitly stated otherwise, all modules and scripts in this distribution are: |
|
865
|
|
|
|
|
|
|
Copyright 2005-2010, Marcus Ramberg |
|
866
|
|
|
|
|
|
|
|
|
867
|
|
|
|
|
|
|
=head1 LICENSE |
|
868
|
|
|
|
|
|
|
|
|
869
|
|
|
|
|
|
|
You may distribute this code under the same terms as Perl itself. |
|
870
|
|
|
|
|
|
|
|
|
871
|
|
|
|
|
|
|
=cut |