|
|
|
@ -10,11 +10,63 @@ use Mojo::Base 'Mojolicious::Controller';
|
|
|
|
|
use Mojo::Asset::File; |
|
|
|
|
use Mojo::Util qw(b64_encode b64_decode decode encode); |
|
|
|
|
|
|
|
|
|
sub _paste_path { |
|
|
|
|
sub _metadata_path { |
|
|
|
|
my ($self, $time) = @_; |
|
|
|
|
my $root ||= $self->app->config->{zerobin}->{root}; |
|
|
|
|
|
|
|
|
|
return $self->app->home->rel_file("$root/$time.json"); |
|
|
|
|
return $self->app->home->rel_file("data/zerobin/$time.json"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub _metadata_save { |
|
|
|
|
my ($self, $time, $data) = @_; |
|
|
|
|
|
|
|
|
|
my $path = $self->_metadata_path($time); |
|
|
|
|
my $asset = Mojo::Asset::File->new; |
|
|
|
|
$asset->add_chunk(encode_json($data)); |
|
|
|
|
$asset->move_to($path); |
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub _metadata_load { |
|
|
|
|
my ($self, $time) = @_; |
|
|
|
|
|
|
|
|
|
my $path = $self->_metadata_path($time); |
|
|
|
|
die("paste metadata not found\n") unless (-f $path); |
|
|
|
|
my $asset = Mojo::Asset::File->new(path => $path); |
|
|
|
|
$asset->cleanup(0); |
|
|
|
|
|
|
|
|
|
return decode_json($asset->slurp); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub _content_path { |
|
|
|
|
my ($self, $time) = @_; |
|
|
|
|
|
|
|
|
|
return $self->app->home->rel_file("public/zerobin/$time.txt"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub _content_save { |
|
|
|
|
my ($self, $time, $content) = @_; |
|
|
|
|
|
|
|
|
|
unless (ref $content) { |
|
|
|
|
my $asset = Mojo::Asset::File->new; |
|
|
|
|
$asset->add_chunk($content); |
|
|
|
|
$content = $asset; # wrap plaintext to Mojo::Asset |
|
|
|
|
} |
|
|
|
|
my $path = $self->_content_path($time); |
|
|
|
|
$content->move_to($path); |
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub _content_load { |
|
|
|
|
my ($self, $time) = @_; |
|
|
|
|
|
|
|
|
|
my $path = $self->_content_path($time); |
|
|
|
|
die("paste content not found\n") unless (-f $path); |
|
|
|
|
my $asset = Mojo::Asset::File->new(path => $path); |
|
|
|
|
$asset->cleanup(0); |
|
|
|
|
|
|
|
|
|
return $asset->slurp; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub create { |
|
|
|
@ -26,7 +78,7 @@ sub create {
|
|
|
|
|
if (ref($langs) eq 'ARRAY'); |
|
|
|
|
|
|
|
|
|
$self->stash({syntax => \@syntax}); |
|
|
|
|
$self->render(); |
|
|
|
|
$self->render; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub view { |
|
|
|
@ -34,17 +86,13 @@ sub view {
|
|
|
|
|
my $time = $self->stash('time'); |
|
|
|
|
|
|
|
|
|
eval { |
|
|
|
|
die("paste not found\n") unless ($time); |
|
|
|
|
my $path = $self->_paste_path($time); |
|
|
|
|
die("paste not found\n") unless (-f $path); |
|
|
|
|
my $asset = Mojo::Asset::File->new(path => $path); |
|
|
|
|
my $json = decode_json($asset->slurp()); |
|
|
|
|
$json->{data} = decode('UTF-8', b64_decode($json->{data})); |
|
|
|
|
if (time() > $json->{expire}) { |
|
|
|
|
unlink($path); |
|
|
|
|
die("paste expired\n"); |
|
|
|
|
} |
|
|
|
|
$self->stash({paste => $json}); |
|
|
|
|
die("paste not found\n") unless $time; |
|
|
|
|
my $paste = $self->_metadata_load($time); |
|
|
|
|
$paste->{data} = $self->_content_load($time); |
|
|
|
|
$paste->{time} = $time; |
|
|
|
|
utf8::decode($paste->{data}); |
|
|
|
|
$self->stash({paste => $paste}); |
|
|
|
|
1; |
|
|
|
|
} or do { |
|
|
|
|
chomp $@; |
|
|
|
|
$self->app->log->error($@); |
|
|
|
@ -54,7 +102,7 @@ sub view {
|
|
|
|
|
return; |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
$self->render(); |
|
|
|
|
$self->render; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub save { |
|
|
|
@ -62,7 +110,7 @@ sub save {
|
|
|
|
|
|
|
|
|
|
eval { |
|
|
|
|
my $source = $self->req->param('source') || '-'; |
|
|
|
|
my $expire = $self->req->param('expire') || 30; # 1 month |
|
|
|
|
my $expire = $self->req->param('expire') || 30; # 30 days or 1 month |
|
|
|
|
my $syntax = $self->req->param('syntax') || ''; |
|
|
|
|
my $paste; |
|
|
|
|
if ($source eq 'form') { |
|
|
|
@ -83,7 +131,7 @@ sub save {
|
|
|
|
|
my $mime = File::MimeInfo::Magic::mimetype($tmpfile); |
|
|
|
|
die("uploaded file not looks like text\n") |
|
|
|
|
unless $mime =~ m{^text/}; |
|
|
|
|
$paste = $upload->asset->slurp; |
|
|
|
|
$paste = $upload->asset; |
|
|
|
|
unlink $tmpfile; |
|
|
|
|
} else { |
|
|
|
|
die("unknown 'source'\n"); |
|
|
|
@ -92,14 +140,11 @@ sub save {
|
|
|
|
|
$syntax = 'auto' unless ($syntax =~ m|^[a-z0-9]+$|oi); |
|
|
|
|
|
|
|
|
|
my $time = time(); |
|
|
|
|
my $json = { |
|
|
|
|
$self->_metadata_save($time, { |
|
|
|
|
expire => $time + ($expire * 86400), |
|
|
|
|
syntax => $syntax, |
|
|
|
|
data => b64_encode(encode('UTF-8', $paste)), |
|
|
|
|
}; |
|
|
|
|
my $asset = Mojo::Asset::File->new; |
|
|
|
|
$asset->add_chunk(encode_json($json)); |
|
|
|
|
$asset->move_to($self->_paste_path($time)); |
|
|
|
|
}); |
|
|
|
|
$self->_content_save($time, $paste); |
|
|
|
|
$self->redirect_to("/zerobin2/$time"); 1; |
|
|
|
|
} or do { |
|
|
|
|
chomp $@; |
|
|
|
@ -109,38 +154,34 @@ sub save {
|
|
|
|
|
$self->redirect_to("/zerobin2"); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
$self->rendered(); |
|
|
|
|
return 1; |
|
|
|
|
$self->rendered; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
sub prune { |
|
|
|
|
my ($self) = @_; |
|
|
|
|
|
|
|
|
|
eval { |
|
|
|
|
my $time = time(); |
|
|
|
|
my $storage = $self->app->config->{zerobin}->{root}; |
|
|
|
|
my $files = $self->app->home->list_files($storage); |
|
|
|
|
foreach my $file (@$files) { |
|
|
|
|
my $currtime = time(); |
|
|
|
|
my $files = $self->app->home->list_files("data/zerobin"); |
|
|
|
|
foreach my $file (@{ $files }) { |
|
|
|
|
next unless $file =~ m/^(\d+)\.json$/oi; |
|
|
|
|
my $time = $1; |
|
|
|
|
my $path = $self->app->home->rel_file("$storage/$file"); |
|
|
|
|
my $asset = Mojo::Asset::File->new(path => $path); |
|
|
|
|
my $data = decode_json($asset->slurp); |
|
|
|
|
next if ($data->{expire} > $time); # not yet |
|
|
|
|
my $data = $self->_metadata_load($time); |
|
|
|
|
next if $data->{expire} > $time; # not yet |
|
|
|
|
my $date = strftime("%Y-%m-%d %H:%M", localtime($data->{expire})); |
|
|
|
|
$self->app->log->info("Removing expired paste: $file ($date)"); |
|
|
|
|
unlink $path; |
|
|
|
|
unlink $self->_metadata_path($time); |
|
|
|
|
unlink $self->_content_path($time); |
|
|
|
|
} 1; |
|
|
|
|
} or do { |
|
|
|
|
chomp $@; |
|
|
|
|
$self->app->log->error($@); |
|
|
|
|
$@ = "internal error" if ($@ =~ m|at \S+ line \d+|oi); |
|
|
|
|
$self->stash({'result' => $@}); |
|
|
|
|
$self->stash({result => $@}); |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
$self->redirect_to("/zerobin2"); |
|
|
|
|
$self->rendered(); |
|
|
|
|
return 1; |
|
|
|
|
$self->rendered; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
1; |
|
|
|
|