|
|
|
package LDV::Comments;
|
|
|
|
|
|
|
|
use strict;
|
|
|
|
use warnings;
|
|
|
|
use utf8;
|
|
|
|
|
|
|
|
use Mojo::Base 'Mojolicious::Controller';
|
|
|
|
|
|
|
|
use File::Slurp qw(read_file write_file);
|
|
|
|
use Mojo::URL;
|
|
|
|
|
|
|
|
sub _gen_pageid {
|
|
|
|
my ($self) = @_;
|
|
|
|
my $url = $self->req->param('pageid') ||
|
|
|
|
$self->req->headers->referrer;
|
|
|
|
my $maxlen = 64;
|
|
|
|
|
|
|
|
return unless $url;
|
|
|
|
my $pageid = Mojo::URL->new($url)->path;
|
|
|
|
|
|
|
|
$pageid =~ s{^/+}{}o;
|
|
|
|
$pageid =~ s{/+$}{}o;
|
|
|
|
$pageid =~ y{/.}{-}s;
|
|
|
|
$pageid =~ s<\.[a-z0-9]{2,4}$><>io;
|
|
|
|
$pageid = substr($pageid, -$maxlen, $maxlen);
|
|
|
|
$self->app->log->debug("comments id: $pageid -- $url");
|
|
|
|
|
|
|
|
return $pageid;
|
|
|
|
}
|
|
|
|
|
|
|
|
sub add {
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
my $sectoken = $self->session('c_sectoken')
|
|
|
|
or die("missing security token\n");
|
|
|
|
my ($ip, $upto) = ($sectoken =~ m{^([0-9a-f\.:]+)-(\d+)$}io)
|
|
|
|
or die("malformed security token\n");
|
|
|
|
($upto > time())
|
|
|
|
or die("expired security token\n");
|
|
|
|
($ip eq $self->tx->remote_address)
|
|
|
|
or die("remote address mismatch\n");
|
|
|
|
my $text = $self->req->param('text')
|
|
|
|
or die("empty comment\n");
|
|
|
|
my $pageid = $self->_gen_pageid()
|
|
|
|
or die("can't get pageid\n");
|
|
|
|
|
|
|
|
my %opts = (binmode => ':bytes');
|
|
|
|
my $comments = [];
|
|
|
|
my $path = $self->app->home->rel_file("data/comments/$pageid.json");
|
|
|
|
if (-f $path) {
|
|
|
|
my $json = read_file($path, %opts);
|
|
|
|
$comments = $self->app->json->decode($json);
|
|
|
|
}
|
|
|
|
push @{ $comments }, {
|
|
|
|
text => $text, time => time(),
|
|
|
|
user => $self->session('username') || 'anonymous',
|
|
|
|
};
|
|
|
|
write_file($path, \%opts, $self->app->json->encode($comments));
|
|
|
|
|
|
|
|
$path = $self->app->home->rel_file("data/comments/$pageid.html");
|
|
|
|
$self->stash({comments => $comments});
|
|
|
|
write_file($path, {binmode => ':utf8'}, $self->render_to_string(template => 'comments/list'));
|
|
|
|
|
|
|
|
$self->render(text => 'OK');
|
|
|
|
} or do {
|
|
|
|
chomp $@;
|
|
|
|
$self->app->log->error($@);
|
|
|
|
$@ = 'internal error' if $@ =~ m{line \d+}o;
|
|
|
|
$self->res->code(400);
|
|
|
|
$self->render(text => $@);
|
|
|
|
};
|
|
|
|
|
|
|
|
$self->rendered();
|
|
|
|
}
|
|
|
|
|
|
|
|
sub get {
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
my $pageid = $self->_gen_pageid()
|
|
|
|
or die("can't get id\n");
|
|
|
|
my $path = $self->app->home->rel_file("data/comments/$pageid.html");
|
|
|
|
if (-f $path) {
|
|
|
|
my $comments = read_file($path, binmode => ':utf8');
|
|
|
|
$self->render(text => $comments);
|
|
|
|
} else {
|
|
|
|
$self->render(template => 'comments/none');
|
|
|
|
} 1;
|
|
|
|
} or do {
|
|
|
|
chomp $@;
|
|
|
|
$self->app->log->error($@);
|
|
|
|
$@ = 'internal error' if $@ =~ m{line \d+}o;
|
|
|
|
$self->res->code(400);
|
|
|
|
$self->render(text => $@);
|
|
|
|
};
|
|
|
|
|
|
|
|
$self->rendered();
|
|
|
|
}
|
|
|
|
|
|
|
|
sub create {
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
eval {
|
|
|
|
die("request error\n")
|
|
|
|
unless $self->req->is_xhr;
|
|
|
|
my $ip = $self->tx->remote_address
|
|
|
|
or die("can't find remote ip\n");
|
|
|
|
my $sectoken = sprintf "%s-%d", $ip, time() + 60 * 7;
|
|
|
|
$self->session(c_sectoken => $sectoken);
|
|
|
|
my $pageid = $self->_gen_pageid()
|
|
|
|
or die("can't get pageid\n");
|
|
|
|
$self->stash({pageid => $pageid});
|
|
|
|
$self->render(template => 'comments/new');
|
|
|
|
} or do {
|
|
|
|
chomp $@;
|
|
|
|
$self->app->log->error($@);
|
|
|
|
$@ = 'internal error' if $@ =~ m{line \d+}o;
|
|
|
|
$self->res->code(400);
|
|
|
|
$self->render(text => $@);
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
1;
|