File Coverage

blib/lib/Catalyst/Controller/DirectoryDispatch.pm
Criterion Covered Total %
statement 46 48 95.8
branch 7 8 87.5
condition n/a
subroutine 15 16 93.7
pod 0 5 0.0
total 68 77 88.3


line stmt bran cond sub pod time code
1             package Catalyst::Controller::DirectoryDispatch;
2             # ABSTRACT: Simple directory listing with built in url dispatching
3             $Catalyst::Controller::DirectoryDispatch::VERSION = '1.03';
4 1     1   1455835 use Moose;
  1         2  
  1         4  
5 1     1   3696 BEGIN { extends 'Catalyst::Controller' }
6              
7 1     1   3251 use JSON;
  1         2  
  1         6  
8 1     1   126 use Try::Tiny;
  1         1  
  1         53  
9 1     1   3 use namespace::autoclean;
  1         1  
  1         4  
10              
11             __PACKAGE__->config(
12             'default' => 'application/json',
13             'stash_key' => 'response',
14             'map' => {
15             'application/x-www-form-urlencoded' => 'JSON',
16             'application/json' => 'JSON',
17             }
18             );
19              
20             has 'root' => (
21             is => 'ro',
22             isa => 'Str',
23             default => '/',
24             );
25              
26             has 'full_paths' => (
27             is => 'ro',
28             isa => 'Bool',
29             default => 0,
30             );
31              
32             has 'filter' => (
33             is => 'ro',
34             isa => 'RegexpRef',
35             );
36              
37             has 'data_root' => (
38             is => 'ro',
39             isa => 'Str',
40             default => 'data',
41             );
42              
43 1     1 0 114 sub setup :Chained('specify.in.subclass.config') :CaptureArgs(0) :PathPart('specify.in.subclass.config') {}
  1     7   1  
  1         5  
44              
45             sub list :Chained('setup') :PathPart('') :Args {
46 7     7 0 1975 my ( $self, $c, @dirpath ) = @_;
47              
48 7         18 my $path = join '/', @dirpath;
49 7 100       20 $path = "/$path" if ($path);
50 7         243 my $full_path = $self->root . $path;
51              
52 7         11 my @files = ();
53             try {
54 7 50   7   361 opendir (my $dir, $full_path) or die;
55 7         105 @files = readdir $dir;
56 7         118 closedir $dir;
57             } catch {
58             $c->stash->{response} = {
59 0     0   0 "error" => "Failed to open directory '$full_path'",
60             "success" => JSON::false,
61             };
62 0         0 $c->detach('serialize');
63 7         50 };
64              
65 7         426 my $regexp = $self->filter;
66 7 100       20 @files = grep { !/$regexp/ } @files if ($regexp);
  17         44  
67              
68 7 100       298 @files = map { "$path/$_" } @files if ($self->full_paths);
  20         41  
69              
70 7         32 my $files_ref = $self->process_files( $c, \@files );
71              
72 7         264 $c->stash(
73             response => {
74             $self->data_root => $files_ref,
75             success => JSON::true,
76             }
77             );
78 1     1   917 }
  1         1  
  1         3  
79              
80             sub process_files {
81 6     6 0 11 my ( $self, $c, $files ) = @_;
82              
83 6         10 return $files;
84             }
85              
86             sub end :Private {
87 7     7 0 6600 my ( $self, $c ) = @_;
88              
89 7         24 $c->res->status(200);
90 7         833 $c->forward('serialize');
91 1     1   665 }
  1         1  
  1         4  
92              
93 1     1 0 637 sub serialize :ActionClass('Serialize') {}
  1     7   2  
  1         3  
94              
95             __PACKAGE__->meta->make_immutable;
96             1;
97              
98             __END__
99              
100             =pod
101              
102             =encoding UTF-8
103              
104             =head1 NAME
105              
106             Catalyst::Controller::DirectoryDispatch - Simple directory listing with built in url dispatching
107              
108             =head1 VERSION
109              
110             version 1.03
111              
112             =head1 SYNOPSIS
113              
114             package MyApp::Controller::Browser::Example;
115             use Moose;
116             BEGIN { extends 'Catalyst::Controller::DirectoryDispatch' }
117              
118             __PACKAGE__->config(
119             action => { setup => { Chained => '/browser/base', PathPart => 'mydir' } },
120             root => '/home/andy',
121             filter => qr{^\.|.conf$},
122             data_root => 'data',
123             full_paths => 1,
124             );
125              
126             =head1 DESCRIPTION
127              
128             Provides a simple configuration based controller for listing local system directories and dispatching them as URLs.
129              
130             =head2 Example Usage
131              
132             If you created the controller at http://localhost/mydir and set root to '/home/user1' then browsing to the controller might give the following output:
133              
134             {
135             "success":true,
136             "data":[
137             "file1",
138             "file2",
139             "dir1",
140             "dir2"
141             ],
142             }
143              
144             You could then point your browser to http://localhost/mydir/dir1 to get a directory listing of the folder '/home/user1/dir1' and so on...
145              
146             =head2 Changing Views
147              
148             The default view for DirectoryDispatch serializes the file list as JSON but it's easy to change it to whatever view you'd like.
149              
150             __PACKAGE__->config(
151             'default' => 'text/html',
152             'map' => {
153             'text/html' => [ 'View', 'TT' ],
154             }
155             );
156              
157             Then in your template...
158              
159             [% FOREACH node IN response.data %]
160             [% node %]
161             [% END %]
162              
163             =head2 Post Processing
164              
165             If you need to process the files in anyway before they're passed to the view you can override process_files in your controller.
166              
167             sub process_files {
168             my ($self, $c, $files) = @_;
169              
170             foreach my $file ( @$files ) {
171             # Modify $file
172             }
173              
174             return $files;
175             }
176              
177             This is the last thing that happens before the list of files are passed on to the view. $files is sent in as an ArrayRef[Str] but you
178             are free to return any thing you want as long as the serializer you're using can handle it.
179              
180             =head1 CONFIGURATION
181              
182             =head2 root
183              
184             is: ro, isa: Str
185              
186             The folder that will be listed when accessing the controller (default '/').
187              
188             =head2 filter
189              
190             is: ro, isa: RegexpRef
191              
192             A regular expression that will remove matching files or folders from the directory listing (default: undef).
193              
194             =head2 data_root
195              
196             is: ro, isa: Str
197              
198             The name of the key inside $c->stash->{response} where the directory listing will be stored (default: data).
199              
200             =head2 full_paths
201              
202             is: ro, isa: Bool
203              
204             Returns full paths for the directory listing rather than just the names (default: 0).
205              
206             =head1 THANKS
207              
208             The design for this module was heavly influenced by the fantastic L<Catalyst::Controller::DBIC::API>.
209              
210             =head1 AUTHOR
211              
212             Andy Gorman <agorman@cpan.org>
213              
214             =head1 COPYRIGHT AND LICENSE
215              
216             This software is copyright (c) 2010 by Andy Gorman.
217              
218             This is free software; you can redistribute it and/or modify it under
219             the same terms as the Perl 5 programming language system itself.
220              
221             =cut