File Coverage

blib/lib/MojoMojo/Controller/Admin.pm
Criterion Covered Total %
statement 72 167 43.1
branch 9 62 14.5
condition 4 14 28.5
subroutine 14 22 63.6
pod 9 9 100.0
total 108 274 39.4


line stmt bran cond sub pod time code
1             package MojoMojo::Controller::Admin;
2              
3 35     35   18690 use strict;
  35         92  
  35         1137  
4 35     35   191 use parent 'Catalyst::Controller::HTML::FormFu';
  35         77  
  35         268  
5              
6             =head1 NAME
7              
8             MojoMojo::Controller::Admin - Site Administration
9              
10             =head1 DESCRIPTION
11              
12             Action to handle management of MojoMojo. Click the admin link at the
13             bottom of the page while logged in as admin to access these functions.
14              
15              
16             =head1 METHODS
17              
18             =head2 auto
19              
20             Access control. Only administrators should access functions in this controller.
21              
22             =cut
23              
24             sub auto : Private {
25 4     4   1795 my ( $self, $c ) = @_;
26            
27 4         17 my $user = $c->stash->{user};
28 4 100 66     266 unless ( $user && $user->is_admin ) {
29             $c->stash->{message} =
30 1         8 $c->loc('Restricted area. Admin access required');
31 1         514 $c->stash->{template} = 'message.tt';
32 1         64 return 0;
33             }
34 3         12 return 1;
35 35     35   5170 }
  35         111  
  35         206  
36              
37             =head2 settings ( /.admin )
38              
39             Show settings screen.
40              
41             =cut
42              
43             sub settings : Path FormConfig Args(0) {
44 0     0 1 0 my ( $self, $c ) = @_;
45              
46 0         0 my $form = $c->stash->{form};
47 0         0 my $user = $c->stash->{user}->login;
48              
49 0         0 my $admins = $c->pref('admins');
50 0         0 $admins =~ s/\b$user\b//g;
51 0         0 my $select_theme = $form->get_all_element( { name => 'theme' } );
52 0         0 my @themes;
53 0         0 foreach my $theme ( MojoMojo::Model::Themes->list ) {
54 0         0 push @themes, [ $theme, $theme ];
55             }
56 0         0 $select_theme->options( \@themes );
57 0 0       0 unless ( $form->submitted ) {
58 0         0 $form->default_values(
59             {
60             name => $c->pref('name'),
61             admins => $admins,
62             anonymous_user => $c->pref('anonymous_user'),
63             open_registration => $c->pref('open_registration'),
64             restricted_user => $c->pref('restricted_user'),
65             disable_search => $c->pref('disable_search'),
66             enable_emoticons => $c->pref('enable_emoticons'),
67             check_permission_on_view =>
68             $c->pref('check_permission_on_view'),
69             cache_permission_data => $c->pref('cache_permission_data'),
70             enforce_login => $c->pref('enforce_login'),
71             create_allowed => $c->pref('create_allowed'),
72             delete_allowed => $c->pref('delete_allowed'),
73             edit_allowed => $c->pref('edit_allowed'),
74             view_allowed => $c->pref('view_allowed'),
75             attachment_allowed => $c->pref('attachment_allowed'),
76             use_captcha => $c->pref('use_captcha'),
77             theme => $c->pref('theme'),
78             main_formatter => $c->pref('main_formatter')
79             }
80             );
81 0         0 $form->process();
82 0         0 return;
83             }
84 0         0 my @users = split( m/\s+/, $form->params->{admins} );
85 0         0 foreach my $user (@users) {
86 0 0       0 unless ( $c->model("DBIC::Person")->get_user($user) ) {
87 0         0 $c->stash->{message} = $c->loc('Cant find admin user: ') . $user;
88 0         0 return;
89             }
90             }
91             $c->pref( 'check_permission_on_view',
92 0 0       0 $form->params->{check_permission_on_view} ? 1 : 0 );
93             $c->pref( 'cache_permission_data',
94 0 0       0 $form->params->{cache_permission_data} ? 1 : 0 );
95 0 0       0 $c->pref( 'open_registration', $form->params->{open_registration} ? 1 : 0 );
96 0 0       0 $c->pref( 'restricted_user', $form->params->{restricted_user} ? 1 : 0 );
97 0 0       0 $c->pref( 'use_captcha', $form->params->{use_captcha} ? 1 : 0 );
98 0 0       0 $c->pref( 'disable_search', $form->params->{disable_search} ? 1 : 0 );
99 0 0       0 $c->pref( 'enable_emoticons', $form->params->{enable_emoticons} ? 1 : 0 );
100 0 0       0 $c->pref( 'enforce_login', $form->params->{enforce_login} ? 1 : 0 );
101 0 0       0 $c->pref( 'create_allowed', $form->params->{create_allowed} ? 1 : 0 );
102 0 0       0 $c->pref( 'delete_allowed', $form->params->{delete_allowed} ? 1 : 0 );
103 0 0       0 $c->pref( 'edit_allowed', $form->params->{edit_allowed} ? 1 : 0 );
104 0 0       0 $c->pref( 'view_allowed', $form->params->{view_allowed} ? 1 : 0 );
105             $c->pref( 'attachment_allowed',
106 0 0       0 $form->params->{attachment_allowed} ? 1 : 0 );
107              
108 0         0 $c->pref( 'admins', join( ' ', @users, $c->stash->{user}->login ) );
109 0         0 $c->pref( 'name', $form->params->{name} );
110 0   0     0 $c->pref( 'anonymous_user', $form->params->{anonymous_user} || '' );
111 0   0     0 $c->pref( 'theme', $form->params->{theme} || 'default' );
112 0         0 $c->pref( 'main_formatter', $form->params->{main_formatter} );
113              
114 0         0 $c->stash->{message} = $c->loc("Updated successfully.");
115 35     35   449562 }
  35         98  
  35         338  
116              
117             =head2 user ( .admin/user )
118              
119             User listing with pager, for enabling/disabling users.
120              
121             =cut
122              
123             sub user : Local {
124 0     0 1 0 my ( $self, $c ) = @_;
125 0   0     0 my $res = $c->model("DBIC::Person")->search(
126             {},
127             {
128             page => $c->req->param('page') || 1,
129             rows => 20,
130             order_by => 'active desc, login'
131             }
132             );
133 0         0 $c->stash->{users} = $res;
134 0         0 $c->stash->{pager} = $res->pager;
135 0         0 $c->stash->{template} = 'admin/user.tt'; # TT finds the template by default; added line for clarity
136 35     35   36186 }
  35         146  
  35         151  
137              
138             =head2 role ( .admin/role )
139              
140             Role listing, creation and assignment.
141              
142             =cut
143              
144             sub role : Local Args(0) {
145 0     0 1 0 my ( $self, $c ) = @_;
146             $c->stash->{roles} =
147 0         0 [ $c->model('DBIC::Role')->search( undef, { order_by => ['id asc'] } ) ];
148 35     35   32425 }
  35         89  
  35         4059  
149              
150             =head2 create_role ( .admin/create_role )
151              
152             Role creation page.
153              
154             =cut
155              
156             sub create_role : Local Args(0) FormConfig('admin/role_form.yml') {
157 0     0 1 0 my ( $self, $c ) = @_;
158 0         0 $c->forward('handle_role_form');
159 35     35   32285 }
  35         93  
  35         166  
160              
161             =head2 edit_role ( .admin/role/ )
162              
163             Role edit page.
164              
165             =cut
166              
167             sub edit_role : Path('role') Args(1) FormConfig('admin/role_form.yml') {
168 0     0 1 0 my ( $self, $c, $role_name ) = @_;
169 0         0 my $form = $c->stash->{form};
170              
171 0         0 my $role = $c->model('DBIC::Role')->find( { name => $role_name } );
172              
173 0 0       0 if ($role) {
174              
175             # load stash parameters if the page is only being displayed
176 0 0       0 unless ( $c->forward( 'handle_role_form', [$role] ) ) {
177 0         0 $c->stash->{members} = [ $role->members->all ];
178 0         0 $c->stash->{role} = $role;
179             }
180             }
181             else {
182 0         0 $c->res->redirect( $c->uri_for('admin/role') );
183             }
184 35     35   34954 }
  35         3891  
  35         172  
185              
186             =head2 handle_role_form
187              
188             Handle role form processing.
189             Returns true when a submitted form was actually processed.
190              
191             =cut
192              
193             sub handle_role_form : Private {
194 0     0 1 0 my ( $self, $c, $role ) = @_;
195 0         0 my $form = $c->stash->{form};
196              
197 0 0       0 if ( $form->submitted_and_valid ) {
198 0         0 my $params = $form->params;
199              
200             my $fields = {
201             name => $params->{name},
202 0 0       0 active => ( $params->{active} ? 1 : 0 )
203             };
204              
205             # make sure updating works
206 0 0       0 $fields->{id} = $role->id if $role;
207              
208 0         0 $role = $c->model('DBIC::Role')->update_or_create($fields);
209              
210 0 0       0 if ($role) {
211              
212             # in order to safely update the role members, they're removed and
213             # then reinserted - this is a bit inefficient but updating role
214             # members shouldn't be a frequent operation
215 0         0 $role->role_members->delete;
216              
217 0 0       0 if ( $params->{role_members} ) {
218             my @role_members =
219             ref $params->{role_members} eq 'ARRAY'
220 0         0 ? @{ $params->{role_members} }
221 0 0       0 : $params->{role_members};
222              
223 0         0 for my $person_id (@role_members) {
224 0         0 $role->add_to_role_members(
225             {
226             person => $person_id,
227             admin => 0
228             }
229             );
230             }
231             }
232              
233 0         0 $c->res->redirect( $c->uri_for('admin/role') );
234             }
235              
236 0         0 return 1;
237             }
238 35     35   36662 }
  35         95  
  35         4108  
239              
240             =head2 update_user ( *private*)
241              
242             Update user based on user listing.
243              
244             =cut
245              
246             sub update_user : Local {
247 0     0 1 0 my ( $self, $c, $user ) = @_;
248 0   0     0 $user = $c->model("DBIC::Person")->find($user) || return;
249              
250             # if ($action eq 'active') {
251 0 0       0 $user->active( ($user->active == 1) ? 0 : 1 );
252              
253             # }
254 0         0 $user->update;
255 0         0 $c->stash->{user} = $user;
256 35     35   33115 }
  35         95  
  35         214  
257              
258             =head2 precompile_pages
259              
260             Make a formatted version of content body and store it in content.precompiled.
261             This makes MojoMojo go zing, when loading content for page requests.
262              
263             Depending on the number of pages, and versions of them, this could take some minutes.
264             For 2000 page versions on a 2.4 GHz desktop this script took about 3 minutes to run.
265              
266             =cut
267              
268             sub precompile_pages : Global {
269 0     0 1 0 my ( $self, $c ) = @_;
270              
271 0         0 my $content_rs = $c->model('DBIC::Content');
272 0         0 while ( my $content_record = $content_rs->next ) {
273 0         0 my $body = $content_record->body;
274 0 0       0 next if !$body;
275 0         0 my $page = $content_record->page;
276             # Get path from path_pages_by_id().
277 0         0 my @path_pages = $c->model('DBIC::Page')->path_pages_by_id( $page->id );
278 0         0 my @node_names = map { $_->name } @path_pages;
  0         0  
279 0         0 my $path = join( '/', @node_names );
280            
281             # Collapse leading '//' into '/' since '/' is first in path
282             # since we just joined with '/'.
283 0         0 $path =~ s{^//}{/};
284 0         0 $c->stash->{path} = $path;
285              
286 0         0 $c->call_plugins( "format_content", \$body, $c, $page );
287 0 0       0 $body = '' if $c->stash->{precompile_off};
288 0         0 $content_record->precompiled($body);
289 0         0 $content_record->update;
290            
291             # Reset precompile_off
292 0         0 $c->stash->{precompile_off} = 0;
293             }
294              
295 0         0 $c->response->body('Precompile Done.');
296 0         0 return;
297 35     35   37612 }
  35         426  
  35         3987  
298              
299             =head2 delete
300              
301             Delete a page and its descendants. This is in L<MojoMojo::Controller::Admin>
302             because we are restricting page deletion to admins only for the time being.
303              
304             TODO: this method should reside in the Model, not in a Controller (issue #87).
305              
306             =cut
307              
308             sub delete : Global FormConfig {
309 3     3 1 50529 my ( $self, $c ) = @_;
310 3         14 my $stash = $c->stash;
311 3         171 my $form = $stash->{form};
312 3         13 $stash->{template} = 'page/delete.tt';
313 3         7 my @descendants;
314             push @descendants, {
315             name => $_->name_orig,
316             id => $_->id,
317             can_delete => ($_->id == 1) ? 0 : $c->check_permissions($_->path, $c->user)->{delete},
318 3 100       14 } for sort { $a->{path} cmp $b->{path} } $c->stash->{page}->descendants;
  3         71  
319 3         13 $stash->{descendants} = \@descendants;
320 3 100       159 $stash->{allowed_to_delete} = ( grep {$_->{can_delete} == 0} @descendants )
  5         24  
321             ? 0 : 1;
322 3 50 66     19 if ( $form->submitted_and_valid && $stash->{allowed_to_delete} ) {
323 1         466 my @deleted_pages;
324             my @ids_to_delete;
325 1         6 for my $page ( $c->stash->{page}->descendants ) {
326 1         60 push @deleted_pages, $page->name_orig;
327 1         29 push @ids_to_delete, $page->id;
328             # Handling Circular Constraints:
329             # Must set page version column to NULL (undef in Perl speak)
330             # to remove the page(id, version) -> page_version(page, version)
331             # constraint which then allows a page_version record to be deleted.
332 1         39 $page->update({version => undef});
333             # remove page from search index
334 1         10471 $c->model('Search')->delete_page($page);
335             }
336 1         5481 my @tables = (
337             { module => 'DBIC::PageVersion', column => 'page' },
338             { module => 'DBIC::Attachment', column => 'page' },
339             { module => 'DBIC::Comment', column => 'page' },
340             { module => 'DBIC::Link', column => [ qw(from_page to_page) ] },
341             { module => 'DBIC::RolePrivilege', column => 'page' },
342             { module => 'DBIC::Tag', column => 'page' },
343             { module => 'DBIC::WantedPage', column => 'from_page' },
344             { module => 'DBIC::Journal', column => 'pageid' },
345             { module => 'DBIC::Entry', column => 'journal' },
346             { module => 'DBIC::Content', column => 'page' },
347             { module => 'DBIC::Page', column => 'id' },
348             );
349 1         94 for my $descendant ( reverse @descendants ) {
350 1         3 for my $table ( @tables ) {
351 11         119407 my $search;
352 11 100       46 if( ref $table->{column} ) {
353 2         9 push @{$search}, { $_ => $descendant->{id} }
354 1         3 for(@{$table->{column}});
  1         5  
355             } else {
356             $search = { $table->{column} => $descendant->{id} }
357 10         47 }
358 11         63 $c->model( $table->{module} )->search( $search )->delete_all;
359             }
360             }
361 1         4242 $stash->{deleted_pages} = \@deleted_pages;
362 1         30 $stash->{template} = 'page/deleted.tt';
363             }
364 35     35   42167 }
  35         87  
  35         163  
365              
366             =head1 AUTHOR
367              
368             Marcus Ramberg <mramberg@cpan.org>
369              
370             =head1 LICENSE
371              
372             This library is free software. You can redistribute it and/or modify
373             it under the same terms as Perl itself.
374              
375             =cut
376              
377             1;