package LDV::Filebin; use strict; use warnings; use utf8; use Mojo::Base 'Mojolicious::Controller'; use Mojo::Asset::File; use File::MimeInfo::Magic qw(mimetype); use Imager; sub _file_path { my ($self, $fname, $fext, $full) = @_; my $path = sprintf "/files/%s.%s", $fname, $fext; return $full ? $self->app->home->rel_file("public/$path") : $path; } sub create { my ($self) = @_; $self->access_allowed($self->app->config->{filebin}->{access}) or return; $self->render; } sub view { my ($self) = @_; my $time = $self->stash('time') || 0; eval { my $now = time(); my $file = $self->app->db->select('filebin', '*', {created => $time, expire => {'>=' => $now}})->hash or die "file not found\n"; $file->{path} = $self->_file_path($time, $file->{fext}); $self->stash({file => $file}); 1; $self->render; 1; } or do { chomp $@; $self->flash({error => $@}); $self->app->log->error($@); $self->redirect_to('/filebin'); }; $self->rendered; } sub save { my ($self) = @_; $self->access_allowed($self->app->config->{filebin}->{access}) or return; eval { my $time = time(); my $conf = $self->app->config->{filebin}; die "request too large\n" if $self->req->is_limit_exceeded; my $expire = $self->req->param('expire') || 7; # days my $hidden = $self->req->param('hidden') || 0; my $upload = $self->req->upload('file'); die "no file uploaded\n" unless ($upload and $upload->size > 0); die "file too large\n" if ($upload->size > $conf->{file_maxsize}); { # hack: don't use memory backend my $path = POSIX::tmpnam; $upload->move_to($path); $upload->asset(Mojo::Asset::File->new(path => $path)); $upload->asset->cleanup(1); # rearm self-destruction } my $file = { created => $time, expire => $time + $expire * 86400, hidden => $hidden, ftype => 'b', # default -- generic binary fsize => $upload->size, fname => $upload->filename, fmime => mimetype($upload->asset->path), fext => '', res_w => 0, res_h => 0, }; if ($file->{fname} =~ m<\.([a-z0-9]{1,5})$>oi) { $file->{fext} = lc($1); } if ($file->{fmime} =~ m{^image/}o) { my ($max_w, $max_h) = ($conf->{image_maxres} =~ m/(\d+)x(\d+)/oi); Imager->set_file_limits( width => $max_w, height => $max_h, bytes => $conf->{image_maxmem}, ); # query image my $image = Imager->new(file => $upload->asset->path) or die(Imager->errstr() . "\n"); $file->{ftype} = 'i'; $file->{fext} = $image->tags(name => 'i_format'), $file->{res_w} = $image->getwidth, $file->{res_h} = $image->getheight, # make thumb my ($th_w, $th_h) = ($conf->{thumbs_size} =~ m/(\d+)x(\d+)/oi); my $thumb = $image->scale(xpixels => $th_w, ypixels => $th_h, type => 'min'); my $path = $self->_file_path("${time}_tn", $conf->{thumbs_ext}, 'fullpath'); $thumb->write(file => $path) or die $thumb->errstr; } elsif ($file->{fmime} =~ m{^video/}o) { $file->{ftype} = 'v'; } elsif ($file->{fmime} =~ m{^audio/}o) { $file->{ftype} = 'a'; } elsif ($file->{fmime} =~ m{^text/}o) { $file->{ftype} = 't'; } $upload->move_to($self->_file_path($time, $file->{fext}, 'fullpath')); $self->app->db->insert('filebin', $file); $self->redirect_to("/filebin/$time"); } or do { chomp $@; $self->app->log->error($@); $@ =~ s/\s+ at \s+ .+ \s+ line \s+ \d+//oxi; $self->flash({error => $@}); $self->redirect_to('/filebin'); }; $self->rendered; } sub latest { my ($self) = @_; eval { my $now = time(); my @files = $self->app->db->select('filebin', '*', {expire => {'>=' => $now}, hidden => 0}, {-desc => 'created'})->hashes; splice(@files, 15); # first 15 elements foreach my $file (@files) { $file->{thumb} = $self->_file_path($file->{created}, $file->{fext}); $file->{url} = sprintf '/filebin/%d', $file->{created}; } $self->stash(files => \@files); $self->render; } or do { chomp $@; $self->flash({error => $@}); $self->app->log->error($@); $self->redirect_to('/filebin'); }; } sub prune { my ($self) = @_; $self->access_allowed($self->app->config->{filebin}->{access}) or return; eval { my $now = time(); my $conf = $self->app->config->{filebin}; my @files = $self->app->db->select('filebin', '*', {expire => {'<=' => $now}})->hashes; foreach my $file (@files) { unlink $self->_file_path($file->{created}, $file->{fext}, 1); if ($file->{ftype} eq 'i') { unlink $self->_file_path("$file->{created}_tn", $conf->{thumbs_ext}, 1); } $self->app->db->delete('filebin', {id => $file->{id}}); } 1; } or do { chomp $@; $self->flash({error => $@}); $self->app->log->error($@); }; $self->redirect_to('/filebin'); $self->rendered; } 1;