File Coverage

blib/lib/MojoMojo/Formatter/File.pm
Criterion Covered Total %
statement 85 86 98.8
branch 24 30 80.0
condition 5 6 83.3
subroutine 14 14 100.0
pod 6 6 100.0
total 134 142 94.3


line stmt bran cond sub pod time code
1             package MojoMojo::Formatter::File;
2              
3 26     26   74973 use strict;
  26         79  
  26         753  
4 26     26   142 use warnings;
  26         66  
  26         781  
5 26     26   182 use base qw/MojoMojo::Formatter/;
  26         68  
  26         2402  
6 26     26   12388 use File::Slurp;
  26         98386  
  26         1702  
7 26     26   735 use Encode;
  26         8697  
  26         1902  
8 26     26   511 use MojoMojo::Formatter::Dir;
  26         71  
  26         413  
9 26     26   633 use File::Basename;
  26         73  
  26         1608  
10             use Module::Pluggable (
11 26         313 search_path => ['MojoMojo::Formatter::File'],
12             require => 1,
13 26     26   664 );
  26         8833  
14             my $debug=0;
15              
16             =head1 NAME
17              
18             MojoMojo::Formatter::File - format file as XHTML
19              
20             =head1 DESCRIPTION
21              
22             This formatter will format the file argument as XHTML.
23              
24             Usage: {{file TYPE filename}}
25              
26              
27             {{file Text uploads/Files/test.txt}}
28              
29              
30             TYPE is a plugin present in Formatter/File/ directory.
31              
32             Currently there are only three: Pod, DocBook and Text
33              
34             The plugin TYPE format only the file which the extension match with 'can_format' method. Respectively pod, xml and txt for existing plugins.
35              
36             For security reasons the path of file must be include in 'whitelisting' directory. You can use path_to(DIR) to describe directory in mojomojo.conf:
37              
38              
39             Just an example to view the test pod file t/var/files/test.pod :
40              
41             Add this to mojomojo.conf :
42              
43             <Formatter::Dir>
44             prefix_url /myfiles
45             whitelisting __path_to(t/var/files)__
46             </Formatter::Dir>
47              
48             To see the pod content formatted in xhtml, write in the text area:
49              
50             {{file Pod path_to(t/var/files)test.pod}}
51              
52              
53             To show recursively all files of directory see script/util/dir2mojomojo.pl script. To test it:
54              
55             # start mojomojo
56              
57             ./script/mojomojo_server.pl
58              
59             # run dir2mojomojo script
60              
61             ./script/util/dir2mojomojo.pl --dir=~/dev/mojomojo/t/var/files/ --url=/myfiles
62              
63              
64             Connect to http://server:3000/myfiles/
65              
66              
67             =head1 METHODS
68              
69             =over 4
70              
71             =item format_content_order
72              
73             Format order can be 1-99. The File formatter runs on 92.
74              
75             =cut
76              
77 744     744 1 2235 sub format_content_order { 92 }
78              
79             =item format_content
80              
81             Calls the formatter. Takes a ref to the content as well as the
82             context object.
83              
84             =cut
85              
86              
87             sub format_content {
88 129     129 1 3631 my ( $self, $content, $c ) = @_;
89              
90              
91             # TODO : Add cache if file is not modified
92              
93              
94 129         640 my @lines = split /\n/, $$content;
95              
96 129         333 $$content = "";
97 129         306 my $is_image = 0;
98 129         321 foreach my $line (@lines) {
99              
100 735 100       1698 if ( $line =~ m|\{\{\s*file\s*(\w+)\s*(.*)}}.*| ) {
101 4         10 my $plugin=$1; # DocBook, Pod, ...
102 4         9 my $file=$2; # File, Attachment
103              
104 4 50       13 $is_image = 1 if ( $plugin eq 'Image' );
105              
106             # use path_to(dir)/filename ?
107 4         15 my $path_to = $c->path_to();
108 4         743 $file =~ s/path_to\([\s|\/]*(\S*)[\s|\/]*\)\s*(\S*)\s*/${path_to}\/$1\/$2/;
109              
110 4         6 my $error;
111 4 100       11 if ( $error = checkplugin($plugin, $file)){
112 1         3 $$content .= $error;
113             }
114 4 100 100     16 if ( ! $error && ( $error = $self->checkfile($file, $c))){
115 2         5 $$content .= $error;
116             }
117              
118 4 100       16 if ( ! $error ){
119             # format with plugin
120 1         3 $$content .= $self->format($plugin,$file);
121             }
122             }
123             else{
124             # Image have not more content
125 731 50       1597 if ( ! $is_image ){
126 731         1436 $$content .= $line . "\n";
127             }
128             }
129             }
130 129         380 return $content;
131             }
132              
133              
134             =item plugin
135              
136             Return the plugin to use with file attachment
137              
138             =cut
139              
140             sub plugin {
141 2     2 1 13699 my $self = shift;
142 2         4 my $filename = shift;
143              
144 2         13 my ($name,$extension) = $filename =~ /(.*)\.(.*)/;
145              
146 2         10 foreach my $plugin ( plugins() ) {
147 7 100 66     7107 if ( $plugin->can('can_format') && $plugin->can_format($extension)){
148 2         3 my $pluginname = $plugin;
149 2         11 $pluginname =~ s/.*:://;
150              
151 2         9 return $pluginname;
152             }
153             }
154             }
155              
156              
157             =item format
158              
159             Return the content formatted
160              
161             =cut
162              
163             sub format {
164 3     3 1 1653 my $self = shift;
165 3         7 my $pluginname = shift;
166 3         5 my $file = shift;
167              
168 3         5 my $error;
169 3 50       7 if ( $error = checkplugin($pluginname)){
170 0         0 return $error;
171             }
172              
173 3         13 my $text = read_file( $file );
174 3         206 utf8::decode($text);
175 3         13 $text = encode('utf-8', $text);
176 3         298 $text = Encode::decode('utf-8', $text);
177              
178 3         151 my $plugin = __PACKAGE__ . "::$pluginname";
179 3         20 return $plugin->to_xhtml($text,$file) . "\n";
180             }
181              
182              
183             =item checkplugin
184              
185             Return 0 if plugin exist
186              
187             =cut
188             sub checkplugin{
189 7     7 1 14 my $pluginname = shift;
190 7         12 my $file = shift;
191              
192 7         17 my $plugin = __PACKAGE__ . "::$pluginname";
193              
194 7 100       61 return 0 if $plugin->can('can_format');
195              
196 1         5 return "Can't find plugin for $file !";
197             }
198              
199             =item checkfile
200              
201             Directory must be include in whitelisting
202              
203             =cut
204             sub checkfile{
205 6     6 1 2149 my ($self, $file, $c) = @_;
206              
207 6 50       18 return "Append a file after 'file'"
208             if ( ! $file );
209              
210 6 100       20 return "You can't use '..' in the name of file"
211             if ( $file =~ /\.\./ );
212              
213 5         117 my $dir = dirname($file);
214              
215 5         21 my $confwl = $c->config->{'Formatter::Dir'}{whitelisting};
216 5 50       431 my @whitelist = ref $confwl eq 'ARRAY' ?
217             @$confwl : ( $confwl );
218             # Add '/' if not exist at the end of whitelist directories
219 5         13 my @wl = map { $_ . '/' } # Add '/'
220 5         11 ( map{ /(\S*[^\/])/ } # Delete '/' if exist
  5         22  
221             @whitelist );
222              
223              
224             # Add '/' if not exist at the end of dierctory
225 5         30 $dir =~ s|^(\S*[^/])$|$1\/|;
226              
227             # if $dir is not include in whitelisting
228 5 100       39 if ( ! map ( $dir =~ m|^$_| , @wl) ){
229 2         13 return "Directory '$dir' must be include in whitelisting ! see Formatter::Dir:whitelisting in mojomojo.conf"
230             }
231              
232              
233 3 50       39 return "'$dir' is not a directory !\n"
234             if ( ! -d $dir );
235              
236 3 100       47 return "Can not read '$file' !\n"
237             if ( ! -r $file );
238              
239 2         13 return 0;
240             }
241              
242             =back
243              
244             =head1 SEE ALSO
245              
246             L<MojoMojo>,L<Module::Pluggable::Ordered>
247              
248             =head1 AUTHORS
249              
250             Daniel Brosseau <dab@catapulse.org>
251              
252             =head1 LICENSE
253              
254             This module is licensed under the same terms as Perl itself.
255              
256             =cut
257              
258             1;