File Coverage

blib/lib/MojoMojo.pm
Criterion Covered Total %
statement 189 212 89.1
branch 72 102 70.5
condition 15 24 62.5
subroutine 30 32 93.7
pod 16 16 100.0
total 322 386 83.4


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