package LDV::Zerobin; use strict; use warnings; use utf8; use JSON qw(encode_json decode_json); use POSIX qw(strftime); use Mojo::Base 'Mojolicious::Controller'; use Mojo::Asset::File; use Mojo::Util qw(b64_encode b64_decode decode encode); sub _paste_path { my ($self, $time) = @_; my $root ||= $self->app->config->{zerobin}->{root}; return $self->app->home->rel_file("$root/$time.json"); } sub create { my ($self) = @_; my @syntax = ('auto'); my $langs = $self->app->config->{zerobin}->{syntax}; push @syntax, $self->c('-------' => $langs) if (ref($langs) eq 'ARRAY'); $self->stash({syntax => \@syntax}); $self->render(); } sub view { my ($self) = @_; 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}); } or do { chomp $@; $self->app->log->error($@); $@ = "internal error" if ($@ =~ m|at \S+ line \d+|oi); $self->flash({'result' => $@}); $self->redirect_to("/zerobin2"); return; }; $self->render(); } sub save { my ($self) = @_; eval { my $expire = $self->req->param('expire') || 30; # 1 month my $syntax = $self->req->param('syntax') || ''; my $paste = $self->req->param('paste') || ''; die("empty paste\n") unless $paste; $expire = 30 unless ($expire =~ m|^\d+$|o); $syntax = 'auto' unless ($syntax =~ m|^[a-z0-9]+$|oi); my $time = time(); my $json = { 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->redirect_to("/zerobin2/$time"); 1; } or do { chomp $@; $self->app->log->error($@); $@ = "internal error" if ($@ =~ m|at \S+ line \d+|oi); $self->flash({'result' => $@}); $self->redirect_to("/zerobin2"); }; $self->rendered(); return 1; } 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) { 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 $date = strftime("%Y-%m-%d %H:%M", localtime($data->{expire})); $self->app->log->info("Removing expired paste: $file ($date)"); unlink $path; } 1; } or do { chomp $@; $self->app->log->error($@); $@ = "internal error" if ($@ =~ m|at \S+ line \d+|oi); $self->stash({'result' => $@}); }; $self->redirect_to("/zerobin2"); $self->rendered(); return 1; } 1;