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   3286 use Mojo::Base 'Mojolicious::Plugin';
  7         11  
  7         57  
4              
5 7     7   5201 use Mojo::File 'path';
  7         11  
  7         287  
6 7     7   60 use Mojo::Util qw(encode decode);
  7         9  
  7         261  
7 7     7   3992 use Text::CSV;
  7         76796  
  7         2599  
8              
9             my $ID = 0;
10              
11             sub register {
12 7     7   2222 my ($self, $app, $config) = @_;
13 7         26 my $dir = $app->config('paste_dir');
14 7 100       188 path($dir)->make_path unless -d $dir;
15 7     12   314 $app->helper('paste.load_p' => sub { _load_p($dir, @_) });
  12         572  
16 7     3   2222 $app->helper('paste.save_p' => sub { _save_p($dir, @_) });
  3         149  
17             }
18              
19             sub _load_p {
20 12     12   30 my ($dir, $c, $id) = @_;
21 12         34 my @res = ('', '');
22              
23             eval {
24 12 100 66     111 die "Hacking attempt! paste_id=($id)" if !$id or $id =~ m!\W!;
25 11         95 return Mojo::Promise->new->resolve(decode 'UTF-8', path($dir, $id)->slurp);
26 12 100       18 } or do {
27 4   50     1934 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         38 my $id = substr Mojo::Util::md5_sum($$ . time . $ID++), 0, 12;
34 3         24 my @res = ('', '');
35              
36             eval {
37 3         14 path($dir, $id)->spurt(encode 'UTF-8', $text);
38 3         751 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   2878 use Mojolicious::Lite;
  7         313818  
  7         44  
46              
47 7     7   130085 use Mojo::JSON 'true';
  7         15  
  7         10241  
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             sub {
116             my $c = shift;
117             my $format = $c->stash('format') || '';
118              
119             $c->render_later->paste->load_p($c->stash('paste_id'))->then(sub {
120             my $paste = shift;
121             if (!$paste) {
122             $c->no_such_paste('Could not find paste');
123             }
124             elsif ($c->param('raw') or $format eq 'txt') {
125             $c->res->headers->content_type('text/plain; charset=utf-8');
126             $c->render(text => $paste);
127             }
128             else {
129             $c->set_title(substr($paste, 0, 80));
130             $c->res->headers->header('X-Plain-Text-URL' => $c->url_for(format => 'txt')->userinfo(undef)->to_abs);
131             $c->stash(embed => $c->param('embed')) if $c->param('embed');
132             $c->render(layout => 'mojopaste', paste => $paste);
133             }
134             })->catch(sub { $c->no_such_paste(shift) });
135             },
136             'show'
137             );
138              
139             app->defaults('enable_charts') and get(
140             '/:paste_id/chart' => {layout => 'mojopaste'},
141             sub {
142             my $c = shift;
143             my $chart = {element => 'chart', data => [], hideHover => true, resize => true};
144             my ($heading, $description, $error) = ('', '', '');
145              
146             $c->render_later->paste->load_p($c->stash('paste_id'))->then(sub {
147             return $c->no_such_paste('Could not find paste') unless my $paste = shift;
148              
149             while ($paste =~ s!^\s*(?://|\#)(.*)!!m) {
150             $description .= $1 if $heading;
151             $heading ||= $1;
152             }
153              
154             eval {
155             _chart($chart, grep { $_ =~ /\S/ } split /\r?\n/, $paste);
156             } or do {
157             $error = $@ || 'Unknown error';
158             $error =~ s!\s*at .*? line \d+.*!!s;
159             };
160              
161             $c->set_title($heading || $description || substr($paste, 0, 80), 'graph');
162             $c->stash(embed => $c->param('embed')) if $c->param('embed');
163             $c->render(chart => $chart, description => $description // '', error => $error, heading => $heading);
164             })->catch(sub { $c->no_such_paste(shift) });
165             },
166             'chart'
167             );
168              
169             app->start;
170              
171             sub _chart {
172 1     1   3 my $chart = shift;
173 1         8 my $csv = Text::CSV->new;
174              
175 1         149 $csv->parse(shift @_); # heading
176 1         40 $chart->{ykeys} = [$csv->fields];
177 1         9 $chart->{xkey} = shift @{$chart->{ykeys}};
  1         10  
178 1         3 $chart->{labels} = $chart->{ykeys};
179 1         3 $chart->{pointStrokeColors} = '#222';
180              
181 1         4 while (@_) {
182 3 50       8 die $csv->error_input unless $csv->parse(shift @_);
183 3 50       48 my @row = $csv->fields or next;
184 3         17 push @{$chart->{data}}, {$chart->{xkey} => shift(@row), map { ($_ => 0 + shift @row) } @{$chart->{ykeys}}};
  3         7  
  6         20  
  3         4  
185             }
186              
187 1 50       1 die 'Could not parse CSV data.' unless @{$chart->{data}};
  1         3  
188 1         12 return $chart;
189             }
190              
191             =pod
192              
193             =encoding utf8
194              
195             =head1 NAME
196              
197             mojopaste - Pastebin application
198              
199             =head1 DESCRIPTION
200              
201             See L.
202              
203             =head1 AUTHOR
204              
205             Jan Henning Thorsen - C
206              
207             =cut
208              
209             __DATA__