#!/usr/bin/perl

use Mojolicious::Lite -signatures;
use Mojo::File qw(curfile);

plugin NotYAMLConfig => { file => 'config.yml',
	default => {
		appname => 'Paste Bin',
	} };

my $datadir = curfile->sibling('data');
if (app->config->{datadir}) {
	$datadir = Mojo::File->new(app->config->{datadir});
}

chdir curfile->dirname;

get '/' => sub ($c) {
	$c->render(template => 'forbidden', status => 403)
		if !length app->config->{password};
} => 'index';

post '/' => sub ($c) {
	# print STDERR "pass=" . $c->param('password') . "\n";
	return $c->render(template => 'forbidden', status => 403)
		if !defined app->config->{password}
			|| !length $c->param('password')
			|| $c->param('password') ne app->config->{password};

	my $file_content = $c->param('text');
	my $filename = $c->param('filename');
	my $upload = $c->param('file');

	if (defined $upload && $upload->size) {
		# print STDERR "FILENAME = " . $upload->filename . "\n";
		$filename = $upload->filename;
		$file_content = $upload->slurp;
	}

	if ($filename !~ /\A\w[\w-\.]*\.\w+\z/) {
		# print STDERR "FILENAME2 = " . $upload->filename . "\n";
		return $c->render(template => 'forbidden', status => 403);
	}

	$datadir->child($filename)->spurt($file_content);
	$c->redirect_to($c->req->url->base . "$filename");
};

get '/<filename>.<ext>'
	=> [ filename => qr/\w[\w-\.]*/, ext => qr/\w+/ ]
	=> sub ($c) {
	my $fullname = $c->param('filename').'.'.$c->param('ext');
	my $file = $datadir->child($fullname);
	my $stat = $file->stat;
	
	return $c->reply->not_found
		if !defined $stat;

	$c->stash(mtime => POSIX::strftime('%Y-%m-%d %H:%M:%S',
		localtime($stat->mtime)));
	$c->stash(file_content => $file->slurp);
	my $lang = $c->param('ext');

	$c->stash(language => "language-$lang");
	$c->render;
} => 'default';

app->mode(app->config->{mode});
app->start;

__DATA__
@@ index.html.ep
% layout 'default';
<h1><%= config->{appname} %></h1>
<form method="POST" enctype="multipart/form-data">
<label for="text">Enter some text or source code here:</label>
<textarea name="text" id="input_text">
</textarea>
<label for="file">Or select a file to upload:</label>
<input type="file" name="file"/>
<label for="filename">Name the file:</label>
<input type="text" name="filename"/>
<label for="password">Password:</label>
<input type="password" name="password" />
<input type="submit" value="Submit"/>
</form>


@@ default.html.ep
% layout 'default';

%= content_for header => begin
    <base href="<%= config->{base} %>/">
    <link rel="stylesheet" href="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/styles/qtcreator-dark.min.css">
    <script src="//cdnjs.cloudflare.com/ajax/libs/highlight.js/11.3.1/highlight.min.js"></script>
    <script>hljs.highlightAll();</script>
% end

<h1><tt><%= $filename%>.<%= $ext %></tt>
   <span class="unimportant">— <%= config->{appname} %></span><br/>
<small class="unimportant">Created: <%= $mtime %></small></h1>
<pre><code class="<%= $language %>"><%= $file_content %></code></pre>


@@ forbidden.html.ep
% layout 'default';

<h1>Forbidden</h1>

@@ not_found.html.ep
% layout 'default';

<h1>Not found!</h1>

@@ layouts/default.html.ep
<html>
  <head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" name="viewport" />
    <meta name="viewport" content="width=device-width" />

<!--    <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,300italic,700,700italic">-->
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.1/normalize.css">
    <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/milligram/1.4.1/milligram.css">
    <link rel="icon" href="favicon.svg" />
    <%= content 'header' %>
    <style>
      body {
        background: #1c1f24;
        color: #f2f2f2;
      }
      .wrapper {
        max-width: 90rem;
        margin: 0 auto;
        margin-top: 1.5rem;
      }
      #input_text {
        height: 40%;
      }
      .button, input[type="submit"] {
        background-color: #0030c0;
        border-color: #202080;
      }
      input {
        color: #f2f2f2;
      }
      input[type="text"], input[type="password"] {
        background-color: black;
      }
      textarea {
        color: #f2f2f2;
        background-color: black;
        font-family: monospace;
      }
      h1 small {
        font-size: 2.0rem;
      }
      .unimportant {
        color: #999;
      }
      pre {
        border: 0.1rem solid #d1d1d1;
        border-radius: .4rem;
      }
      pre code {
        padding: 0;
        margin-left: 0;
        margin-right: 0;
      }
      div.footer {
        color: #999;
        text-align: right;
      } 
      a {
        color: #90c0ff;
      }
    </style>
    <title><%= config->{appname} %></title>
  </head>
  <body><div class="wrapper">
    <%= content %>
    <div class="footer">
      <a href="https://www.fi.muni.cz/~kas/">Yenya</a>'s Paste Bin,
      <a href="https://www.fi.muni.cz/~kas/git/paste.git/">www.fi.muni.cz/~kas/git/paste.git/</a>
    </div>
  </div></body>
</html>

@@ favicon.svg (base64)
PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+Cjwh
LS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoK
PHN2ZwogICB3aWR0aD0iMTkuOTc3NzIybW0iCiAgIGhlaWdodD0iMTkuOTc3NzIybW0iCiAgIHZp
ZXdCb3g9IjAgMCAxOS45Nzc3MjEgMTkuOTc3NzIxIgogICB2ZXJzaW9uPSIxLjEiCiAgIGlkPSJz
dmc1IgogICBpbmtzY2FwZTp2ZXJzaW9uPSIxLjEgKGM2OGUyMmMzODcsIDIwMjEtMDUtMjMpIgog
ICBzb2RpcG9kaTpkb2NuYW1lPSJzaGViYW5nLWZhdmljb24uc3ZnIgogICB4bWxuczppbmtzY2Fw
ZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgeG1sbnM6
c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAu
ZHRkIgogICB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciCiAgIHhtbG5zOnN2Zz0i
aHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogIDxzb2RpcG9kaTpuYW1lZHZpZXcKICAgICBp
ZD0ibmFtZWR2aWV3NyIKICAgICBwYWdlY29sb3I9IiNmZmZmZmYiCiAgICAgYm9yZGVyY29sb3I9
IiM2NjY2NjYiCiAgICAgYm9yZGVyb3BhY2l0eT0iMS4wIgogICAgIGlua3NjYXBlOnBhZ2VzaGFk
b3c9IjIiCiAgICAgaW5rc2NhcGU6cGFnZW9wYWNpdHk9IjAuMCIKICAgICBpbmtzY2FwZTpwYWdl
Y2hlY2tlcmJvYXJkPSIwIgogICAgIGlua3NjYXBlOmRvY3VtZW50LXVuaXRzPSJtbSIKICAgICBz
aG93Z3JpZD0iZmFsc2UiCiAgICAgZml0LW1hcmdpbi10b3A9IjAiCiAgICAgZml0LW1hcmdpbi1s
ZWZ0PSIwIgogICAgIGZpdC1tYXJnaW4tcmlnaHQ9IjAiCiAgICAgZml0LW1hcmdpbi1ib3R0b209
IjAiCiAgICAgaW5rc2NhcGU6em9vbT0iMi42ODMyNDkyIgogICAgIGlua3NjYXBlOmN4PSIzMS4x
MTg5ODgiCiAgICAgaW5rc2NhcGU6Y3k9IjMwLjkzMjY0NyIKICAgICBpbmtzY2FwZTp3aW5kb3ct
d2lkdGg9IjE4MzUiCiAgICAgaW5rc2NhcGU6d2luZG93LWhlaWdodD0iMTA1MCIKICAgICBpbmtz
Y2FwZTp3aW5kb3cteD0iNjUiCiAgICAgaW5rc2NhcGU6d2luZG93LXk9IjAiCiAgICAgaW5rc2Nh
cGU6d2luZG93LW1heGltaXplZD0iMSIKICAgICBpbmtzY2FwZTpjdXJyZW50LWxheWVyPSJsYXll
cjEiCiAgICAgaW5rc2NhcGU6c25hcC1wYWdlPSJ0cnVlIiAvPgogIDxkZWZzCiAgICAgaWQ9ImRl
ZnMyIiAvPgogIDxnCiAgICAgaW5rc2NhcGU6bGFiZWw9IkxheWVyIDEiCiAgICAgaW5rc2NhcGU6
Z3JvdXBtb2RlPSJsYXllciIKICAgICBpZD0ibGF5ZXIxIgogICAgIHRyYW5zZm9ybT0idHJhbnNs
YXRlKC01NC41NjY5OTQsLTk3Ljk1MDE2NSkiPgogICAgPHJlY3QKICAgICAgIHN0eWxlPSJmaWxs
OiMwMDAwMDA7ZmlsbC1vcGFjaXR5OjE7c3Ryb2tlOm5vbmU7c3Ryb2tlLXdpZHRoOjIuMDI5MDQ7
c3Ryb2tlLW1pdGVybGltaXQ6NDtzdHJva2UtZGFzaGFycmF5Om5vbmU7c3Ryb2tlLWRhc2hvZmZz
ZXQ6MDtzdHJva2Utb3BhY2l0eToxIgogICAgICAgaWQ9InJlY3QxMjk0OSIKICAgICAgIHdpZHRo
PSIxOS45Nzc3MjIiCiAgICAgICBoZWlnaHQ9IjE5Ljk3NzcyMiIKICAgICAgIHg9IjU0LjU2Njk5
NCIKICAgICAgIHk9Ijk3Ljk1MDE2NSIKICAgICAgIHJ5PSIwLjUzNjg1NTI4IiAvPgogICAgPHRl
eHQKICAgICAgIHhtbDpzcGFjZT0icHJlc2VydmUiCiAgICAgICBzdHlsZT0iZm9udC1zdHlsZTpu
b3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xkO2ZvbnQtc3RyZXRjaDpu
b3JtYWw7Zm9udC1zaXplOjE3LjE3OTJweDtsaW5lLWhlaWdodDoxMjUlO2ZvbnQtZmFtaWx5OidE
ZWphVnUgU2FucyBNb25vJzstaW5rc2NhcGUtZm9udC1zcGVjaWZpY2F0aW9uOidEZWphVnUgU2Fu
cyBNb25vIEJvbGQnO3RleHQtYWxpZ246c3RhcnQ7bGV0dGVyLXNwYWNpbmc6MHB4O3dvcmQtc3Bh
Y2luZzowcHg7dGV4dC1hbmNob3I6c3RhcnQ7ZmlsbDojMDBmZmZmO2ZpbGwtb3BhY2l0eToxO3N0
cm9rZTpub25lO3N0cm9rZS13aWR0aDowLjUzNjg0OXB4O3N0cm9rZS1saW5lY2FwOmJ1dHQ7c3Ry
b2tlLWxpbmVqb2luOm1pdGVyO3N0cm9rZS1vcGFjaXR5OjEiCiAgICAgICB4PSI1NS44NTM0MDki
CiAgICAgICB5PSIxMTQuMTE5OSIKICAgICAgIGlkPSJ0ZXh0NzgxIj48dHNwYW4KICAgICAgICAg
c29kaXBvZGk6cm9sZT0ibGluZSIKICAgICAgICAgaWQ9InRzcGFuNzc5IgogICAgICAgICBzdHls
ZT0iZm9udC1zdHlsZTpub3JtYWw7Zm9udC12YXJpYW50Om5vcm1hbDtmb250LXdlaWdodDpib2xk
O2ZvbnQtc3RyZXRjaDpub3JtYWw7Zm9udC1zaXplOjE3LjE3OTJweDtmb250LWZhbWlseTonRGVq
YVZ1IFNhbnMgTW9ubyc7LWlua3NjYXBlLWZvbnQtc3BlY2lmaWNhdGlvbjonRGVqYVZ1IFNhbnMg
TW9ubyBCb2xkJztmaWxsOiMwMGZmZmY7c3Ryb2tlLXdpZHRoOjAuNTM2ODQ5cHgiCiAgICAgICAg
IHg9IjU1Ljg1MzQwOSIKICAgICAgICAgeT0iMTE0LjExOTkiPiMhPC90c3Bhbj48L3RleHQ+CiAg
PC9nPgo8L3N2Zz4K

