File Coverage

script/mojopaste
Criterion Covered Total %
statement 55 56 98.2
branch 10 14 71.4
condition 3 7 42.8
subroutine 12 12 100.0
pod n/a
total 80 89 89.8


line stmt bran cond sub pod time code
1             #!perl
2             package App::mojopaste::Backend::File;
3 7     7   3900 use Mojo::Base 'Mojolicious::Plugin';
  7         12  
  7         116  
4              
5 7     7   6354 use Mojo::File 'path';
  7         10  
  7         304  
6 7     7   33 use Mojo::Util qw(encode decode);
  7         10  
  7         264  
7 7     7   4523 use Text::CSV;
  7         90736  
  7         2932  
8              
9             my $ID = 0;
10              
11             sub register {
12 7     7   2741 my ($self, $app, $config) = @_;
13 7         27 my $dir = $app->config('paste_dir');
14 7 100       253 path($dir)->make_path unless -d $dir;
15 7     12   405 $app->helper('paste.load_p' => sub { _load_p($dir, @_) });
  12         626  
16 7     3   2625 $app->helper('paste.save_p' => sub { _save_p($dir, @_) });
  3         146  
17             }
18              
19             sub _load_p {
20 12     12   41 my ($dir, $c, $id) = @_;
21 12         42 my @res = ('', '');
22              
23             eval {
24 12 100 66     113 die "Hacking attempt! paste_id=($id)" if !$id or $id =~ m!\W!;
25 11         73 return Mojo::Promise->new->resolve(decode 'UTF-8', path($dir, $id)->slurp);
26 12 100       27 } or do {
27 4   50     3233 return Mojo::Promise->new->reject($@ || 'Paste not found');
28             };
29             }
30              
31             sub _save_p {
32 3     3   10 my ($dir, $c, $text) = @_;
33 3         26 my $id = substr Mojo::Util::md5_sum($$ . time . $ID++), 0, 12;
34 3         20 my @res = ('', '');
35              
36             eval {
37 3         13 path($dir, $id)->spurt(encode 'UTF-8', $text);
38 3         793 return Mojo::Promise->new->resolve($id);
39 3 50       6 } or do {
40 0   0     0 return Mojo::Promise->new->reject($@ || 'Unknown error');
41             };
42             }
43              
44             package main;
45 7     7   3407 use Mojolicious::Lite;
  7         442445  
  7         45  
46              
47 7     7   150858 use Mojo::JSON 'true';
  7         16  
  7         12120  
48              
49             plugin 'config' if $ENV{MOJO_CONFIG};
50             app->config->{backend} ||= $ENV{PASTE_BACKEND} || 'File';
51             app->config->{paste_dir} ||= $ENV{PASTE_DIR} || 'paste';
52              
53             app->defaults(
54             brand_link => app->config('brand_link') || $ENV{PASTE_BRAND_LINK} || 'index',
55             brand_logo => app->config('brand_logo') // $ENV{PASTE_BRAND_LOGO} // '/images/logo.png',
56             brand_name => app->config('brand_name') // $ENV{PASTE_BRAND_NAME} // 'Mojopaste',
57             enable_charts => app->config('enable_charts') // $ENV{PASTE_ENABLE_CHARTS},
58             embed => 'description,graph,heading,nav',
59             error => '',
60             paste => '',
61             placeholder => 'Enter your text here and then press the "Save" button above.',
62             title => 'Mojopaste',
63             );
64              
65             my $backend = app->config('backend');
66             plugin $backend =~ /::/ ? $backend : "App::mojopaste::Backend::$backend";
67              
68             helper no_such_paste => sub {
69             my ($c, $err) = @_;
70             $c->app->log->debug("no_such_paste: $err");
71             $c->stash($_ => 'Could not find paste') for qw(error heading title);
72             $c->render(description => '', layout => 'mojopaste', status => 404);
73             };
74              
75             helper set_title => sub {
76             my ($c, $prefix, $suffix) = @_;
77             my $brand_name = $c->stash('brand_name') || 'Mojopaste';
78             $suffix = $suffix ? "$brand_name $suffix" : $brand_name;
79             $prefix =~ s![\n\r]+! !g;
80             $prefix =~ s!^\W+!!g;
81             $prefix = substr $prefix, 0, 56 - length $suffix;
82             return $c->stash(title => "$prefix - $suffix");
83             };
84              
85             get(
86             '/' => {layout => 'mojopaste'} => sub {
87             my $c = shift;
88              
89             return $c->set_title("Create new paste") unless my $id = $c->param('edit');
90             return $c->render_later->paste->load_p($id)->then(sub {
91             return $c->no_such_paste('Could not find paste') unless my $paste = shift;
92             $c->set_title(substr($paste, 0, 80), 'edit');
93             $c->param(paste => $paste)->render;
94             })->catch(sub { $c->no_such_paste(shift) });
95             },
96             'index'
97             );
98              
99             post(
100             '/' => {layout => 'mojopaste'},
101             sub {
102             my $c = shift;
103             my $paste = $c->param('paste') || '';
104              
105             return $c->render('index', placeholder => 'You neeed to enter some characters!', status => 400)
106             unless $paste =~ /\w/;
107             return $c->render_later->paste->save_p($paste)->then(sub {
108             $c->redirect_to('show', paste_id => shift);
109             })->catch(sub { $c->reply->exception(shift) });
110             }
111             );
112              
113             get(
114             '/:paste_id',
115             [format => ['html', 'txt']],
116             {format => undef},
117             sub {
118             my $c = shift;
119             my $format = $c->stash('format') || '';
120              
121             $c->render_later->paste->load_p($c->stash('paste_id'))->then(sub {
122             my $paste = shift;
123             if (!$paste) {
124             $c->no_such_paste('Could not find paste');
125             }
126             elsif ($c->param('raw') or $format eq 'txt') {
127             $c->res->headers->content_type('text/plain; charset=utf-8');
128             $c->render(text => $paste);
129             }
130             else {
131             $c->set_title(substr($paste, 0, 80));
132             $c->res->headers->header('X-Plain-Text-URL' => $c->url_for(format => 'txt')->userinfo(undef)->to_abs);
133             $c->stash(embed => $c->param('embed')) if $c->param('embed');
134             $c->render(layout => 'mojopaste', paste => $paste);
135             }
136             })->catch(sub { $c->no_such_paste(shift) });
137             },
138             'show'
139             );
140              
141             app->defaults('enable_charts') and get(
142             '/:paste_id/chart' => {layout => 'mojopaste'},
143             sub {
144             my $c = shift;
145             my $chart = {element => 'chart', data => [], hideHover => true, resize => true};
146             my ($heading, $description, $error) = ('', '', '');
147              
148             $c->render_later->paste->load_p($c->stash('paste_id'))->then(sub {
149             return $c->no_such_paste('Could not find paste') unless my $paste = shift;
150              
151             while ($paste =~ s!^\s*(?://|\#)(.*)!!m) {
152             $description .= $1 if $heading;
153             $heading ||= $1;
154             }
155              
156             eval {
157             _chart($chart, grep { $_ =~ /\S/ } split /\r?\n/, $paste);
158             } or do {
159             $error = $@ || 'Unknown error';
160             $error =~ s!\s*at .*? line \d+.*!!s;
161             };
162              
163             $c->set_title($heading || $description || substr($paste, 0, 80), 'graph');
164             $c->stash(embed => $c->param('embed')) if $c->param('embed');
165             $c->render(chart => $chart, description => $description // '', error => $error, heading => $heading);
166             })->catch(sub { $c->no_such_paste(shift) });
167             },
168             'chart'
169             );
170              
171             app->start;
172              
173             sub _chart {
174 1     1   2 my $chart = shift;
175 1         6 my $csv = Text::CSV->new;
176              
177 1         190 $csv->parse(shift @_); # heading
178 1         62 $chart->{ykeys} = [$csv->fields];
179 1         8 $chart->{xkey} = shift @{$chart->{ykeys}};
  1         2  
180 1         2 $chart->{labels} = $chart->{ykeys};
181 1         2 $chart->{pointStrokeColors} = '#222';
182              
183 1         2 while (@_) {
184 3 50       7 die $csv->error_input unless $csv->parse(shift @_);
185 3 50       46 my @row = $csv->fields or next;
186 3         17 push @{$chart->{data}}, {$chart->{xkey} => shift(@row), map { ($_ => 0 + shift @row) } @{$chart->{ykeys}}};
  3         4  
  6         25  
  3         3  
187             }
188              
189 1 50       1 die 'Could not parse CSV data.' unless @{$chart->{data}};
  1         2  
190 1         11 return $chart;
191             }
192              
193             =pod
194              
195             =encoding utf8
196              
197             =head1 NAME
198              
199             mojopaste - Pastebin application
200              
201             =head1 DESCRIPTION
202              
203             See L.
204              
205             =head1 AUTHOR
206              
207             Jan Henning Thorsen - C
208              
209             =cut
210              
211             __DATA__