File Coverage

blib/lib/MojoMojo/Controller/Attachment.pm
Criterion Covered Total %
statement 99 144 68.7
branch 13 44 29.5
condition 1 3 33.3
subroutine 28 34 82.3
pod 14 14 100.0
total 155 239 64.8


line stmt bran cond sub pod time code
1             package MojoMojo::Controller::Attachment;
2              
3 35     35   16028 use strict;
  35         95  
  35         1024  
4 35     35   195 use parent 'Catalyst::Controller';
  35         80  
  35         255  
5              
6 35     35   2480 use IO::File;
  35         80  
  35         4392  
7 35     35   220 use URI::Escape ();
  35         72  
  35         2525  
8              
9             =head1 NAME
10              
11             MojoMojo::Controller::Attachment - Attachment controller
12              
13             =head1 DESCRIPTION
14              
15             MojoMojo supports attaching files to nodes. This controller handles
16             administration and serving of these assets.
17              
18              
19             =head1 ACTIONS
20              
21             =head2 auth
22              
23             Return whether the current user has attachment manipulation rights (upload/delete).
24              
25             =cut
26              
27             sub auth : Private {
28 3     3   1335 my ( $self, $c ) = @_;
29              
30             my $perms =
31 3 50       14 $c->check_permissions( $c->stash->{'path'},
32             ( $c->user_exists ? $c->user->obj : undef ) );
33 3         18 return $perms->{'attachment'}
34 35     35   205 }
  35         84  
  35         275  
35              
36             =head2 unauthorized
37              
38             Private action to return a 403 with an explanatory template.
39              
40             =cut
41              
42             sub unauthorized : Private {
43 0     0 1 0 my ( $self, $c, $operation ) = @_;
44 0         0 $c->stash->{template} = 'message.tt';
45 0         0 $c->stash->{message} = $c->loc('You do not have permissions to x attachments for this page', $operation);
46 0         0 $c->response->status(403); # 403 Forbidden
47 35     35   1326190 }
  35         99  
  35         181  
48              
49             =head2 default
50              
51             Private action to return a 404 not found page.
52              
53             =cut
54              
55             sub default : Private {
56 3     3 1 8293 my ( $self, $c ) = @_;
57 3         14 $c->stash->{template} = 'message.tt';
58 3         189 $c->stash->{message} = $c->loc("Attachment not found.");
59 3         1395 return ( $c->res->status(404) );
60 35     35   34937 }
  35         91  
  35         158  
61              
62             =head2 attachments
63              
64             Main attachment screen. Handles uploading of new attachments.
65              
66             =cut
67              
68             sub attachments : Global {
69 6     6 1 6196 my ( $self, $c ) = @_;
70              
71 6 50       35 $c->detach('unauthorized', ['view']) if not $c->check_view_permission;
72              
73 6         36 $c->stash->{template} = 'page/attachments.tt';
74 35     35   32659 }
  35         95  
  35         167  
75              
76             =head2 list
77              
78             Display the list of attachments if the user has view permissions.
79              
80             B<template>: F<attachments/list.tt>
81              
82             =cut
83              
84             sub list : Local {
85 0     0 1 0 my ( $self, $c ) = @_;
86              
87 0 0       0 $c->detach('unauthorized', ['view']) if not $c->check_view_permission;
88              
89 0         0 $c->stash->{template}='attachments/list.tt';
90 35     35   32153 }
  35         86  
  35         160  
91              
92             =head2 plain_upload
93              
94             Upload feature that uses the traditional upload technique.
95              
96             =cut
97              
98             sub plain_upload : Global {
99 2     2 1 2033 my ( $self, $c ) = @_;
100 2 50       11 $c->detach('unauthorized', ['upload']) if not $c->forward('auth');
101 2         217 $c->forward('check_file');
102 35     35   32163 }
  35         92  
  35         169  
103              
104             =head2 check_file
105              
106             Check if the file(s) uploaded could be added to the Attachment table.
107              
108             =cut
109             sub check_file : Private {
110 2     2 1 1005 my ($self,$c)=@_;
111 2         8 my $page = $c->stash->{page};
112 2 50       118 if ( my $file = $c->req->params->{file} ) {
113 2         191 my $upload = $c->request->upload('file');
114 2         181 my (@att) = # an array is returned if a ZIP upload was unpacked
115             $c->model("DBIC::Attachment")
116             ->create_from_file( $page, $file, $upload->tempname );
117 2 50       32 if ( !@att ) {
118 0         0 $c->stash->{template} = 'message.tt';
119 0         0 $c->stash->{message} = $c->loc("Could not create attachment from x", $file);
120             }
121              
122 2         74 my $redirect_uri = $c->uri_for('attachments', {plain => $c->req->params->{plain}});
123             $c->res->redirect($redirect_uri) # TODO weird condition. This should be an else to the 'if' above
124 2 50 33     13 unless defined $c->stash->{template} && $c->stash->{template} eq 'message.tt';
125             }
126 35     35   35109 }
  35         100  
  35         160  
127              
128             =head2 flash_upload
129              
130             Upload feature that uses flash
131              
132             =cut
133              
134             sub flash_upload : Local {
135 0     0 1 0 my ( $self, $c ) = @_;
136              
137 0         0 my $user = $c->model('DBIC::Person')->find( $c->req->params->{id} );
138              
139             $c->detach('/default')
140             unless (
141 0 0       0 $user->hashed( $c->pref('entropy') ) eq $c->req->params->{verify} );
142              
143 0         0 $c->forward('check_file');
144              
145 0 0       0 if ( $c->res->redirect ) {
146 0         0 $c->res->redirect( undef, 200 );
147 0         0 return $c->res->body('1');
148             }
149              
150 0         0 $c->res->body('0');
151 35     35   33509 }
  35         94  
  35         154  
152              
153             =head2 attachment
154              
155             Find and stash an attachment.
156              
157             =cut
158              
159             sub attachment : Chained CaptureArgs(1) {
160 6     6 1 7379 my ( $self, $c, $att ) = @_;
161              
162             # DBIC complains if find argument is not numeric
163 6 100       47 if ( $att !~ /^\d+$/ ) {
164 1         12 $c->detach('default');
165             }
166 5 100       29 $c->stash->{att} = $c->model("DBIC::Attachment")->find($att)
167             or $c->detach('default');
168 35     35   33541 }
  35         103  
  35         171  
169              
170             =head2 defaultaction
171              
172             Set the default action for an attachment which is forwarding to a view.
173              
174             =cut
175              
176             sub defaultaction : PathPart('') Chained('attachment') Args(0) {
177 0     0 1 0 my ( $self, $c ) = @_;
178 0         0 $c->forward('view');
179 35     35   31160 }
  35         96  
  35         150  
180              
181             =head2 view
182              
183             Render the attachment in the browser (C<Content-Disposition: inline>), with
184             caching for 1 day.
185              
186             =cut
187              
188             sub view : Chained('attachment') Args(0) {
189 2     2 1 987 my ( $self, $c ) = @_;
190 2         9 my $att = $c->stash->{att};
191 2 50       119 $c->detach('unauthorized', ['view']) if not $c->check_view_permission;
192              
193             # avoid broken binary files
194 2 50       17 my $io_file = IO::File->new( $att->filename )
195             or $c->detach('default');
196 2         283 $io_file->binmode;
197              
198 2         31 $c->res->output( $io_file );
199 2         146 $c->res->header( 'content-type', $att->contenttype );
200 2         769 $c->res->header(
201             "Content-Disposition" => "inline; filename=" . URI::Escape::uri_escape_utf8( $att->name ) );
202 2         637 $c->res->header( 'Cache-Control', 'max-age=86400, must-revalidate' );
203 35     35   34000 }
  35         87  
  35         165  
204              
205             =head2 download
206              
207             Forwards to L</view> then forces the attachment to be downloaded
208             (C<Content-Disposition: attachment>) and disables caching.
209              
210             =cut
211              
212             sub download : Chained('attachment') Args(0) {
213 2     2 1 8985 my ( $self, $c ) = @_;
214 2         13 $c->forward('view');
215 2         664 $c->res->header( "Content-Disposition" => "attachment; filename=" . URI::Escape::uri_escape_utf8( $c->stash->{att}->name ) );
216 2         685 $c->res->header( 'Cache-Control', 'no-cache' );
217              
218 35     35   32264 }
  35         105  
  35         181  
219              
220             =head2 thumb
221              
222             Thumb action for attachments. Makes 100x100px thumbnails.
223              
224             =cut
225              
226             sub thumb : Chained('attachment') Args(0) {
227 0     0 1 0 my ( $self, $c ) = @_;
228 0 0       0 $c->detach('unauthorized', ['view']) if not $c->check_view_permission;
229 0         0 my $att = $c->stash->{att};
230 0         0 my $photo;
231 0 0       0 unless ( $photo = $att->photo ) {
232 0         0 return $c->res->body($c->loc('Can only make thumbnails of photos'));
233             }
234 0 0       0 $photo->make_thumb() unless -f $att->thumb_filename;
235 0 0       0 my $io_file = IO::File->new( $att->thumb_filename )
236             or $c->detach('default');
237 0         0 $io_file->binmode;
238              
239 0         0 $c->res->output( $io_file );
240 0         0 $c->res->header( 'content-type', $att->contenttype );
241 0         0 $c->res->header( "Content-Disposition" => "inline; filename=" . URI::Escape::uri_escape_utf8( $att->name ) );
242 0         0 $c->res->header( 'Cache-Control', 'max-age=86400, must-revalidate' );
243              
244 35     35   34691 }
  35         91  
  35         185  
245              
246             =head2 inline
247              
248             Show 800x600 inline versions of photo attachments.
249              
250             =cut
251              
252             sub inline : Chained('attachment') Args(0) {
253 0     0 1 0 my ( $self, $c ) = @_;
254 0 0       0 $c->detach('unauthorized', ['view']) if not $c->check_view_permission;
255 0         0 my $att = $c->stash->{att};
256 0         0 my $photo;
257 0 0       0 unless ( $photo = $att->photo ) {
258 0         0 return $c->res->body($c->loc('Can only make inline version of photos'));
259             }
260 0 0       0 $photo->make_inline unless -f $att->inline_filename;
261 0 0       0 my $io_file = IO::File->new( $att->inline_filename )
262             or $c->detach('default');
263 0         0 $io_file->binmode;
264              
265 0         0 $c->res->output( $io_file );
266 0         0 $c->res->header( 'content-type', $c->stash->{att}->contenttype );
267             $c->res->header(
268 0         0 "Content-Disposition" => "inline; filename=" . URI::Escape::uri_escape_utf8( $c->stash->{att}->name ) );
269 0         0 $c->res->header( 'Cache-Control', 'max-age=86400, must-revalidate' );
270              
271 35     35   35382 }
  35         106  
  35         164  
272              
273             =head2 delete
274              
275             Delete the attachment from this node. Will leave the original file on the
276             file system but delete its thumbnail and inline versions.
277              
278             =cut
279              
280             sub delete : Chained('attachment') Args(0) {
281 1     1 1 3963 my ( $self, $c ) = @_;
282 1 50       5 $c->detach('unauthorized', ['delete']) if not $c->forward('auth');
283 1         117 $c->stash->{att}->delete();
284 1         13401 $c->forward('attachments');
285 35     35   31874 }
  35         88  
  35         178  
286              
287             =head1 AUTHOR
288              
289             Marcus Ramberg C<marcus@nordaaker.com>
290              
291             =head1 LICENSE
292              
293             This library is free software. You can redistribute it and/or modify
294             it under the same terms as Perl itself.
295              
296             =cut
297              
298             1;