Adding stats view.

This commit is contained in:
sergiotarxz 2022-11-17 00:44:20 +01:00
parent c152abc0e6
commit 5c5fa005e5
8 changed files with 152 additions and 0 deletions

View File

@ -1,4 +1,6 @@
{ {
"secrets": ["secret_change_for_pwgen_generated_one_with_at_least 255 chars"],
"bcrypt_pass_stats": ["change_for_bcrypted_password"],
"db": { "db": {
"database": "example" "database": "example"
} }

View File

@ -20,6 +20,7 @@ sub startup ($self) {
my $config = $self->plugin('JSONConfig'); my $config = $self->plugin('JSONConfig');
$self->config( $self->config(
hypnotoad => { proxy => 1, listen => ['http://localhost:3000'] } ); hypnotoad => { proxy => 1, listen => ['http://localhost:3000'] } );
$self->secrets($self->config->{secrets});
# Router # Router
my $r = $self->routes; my $r = $self->routes;
@ -28,10 +29,13 @@ sub startup ($self) {
$r->get('/')->to('Page#index'); $r->get('/')->to('Page#index');
# $r->get('/:post')->to('Page#post'); # $r->get('/:post')->to('Page#post');
$r->get('/stats')->to('Metrics#stats');
$r->get('/<:category>.rss')->to('Page#category_rss'); $r->get('/<:category>.rss')->to('Page#category_rss');
$r->get('/:category')->to('Page#category'); $r->get('/:category')->to('Page#category');
$r->get('/posts/<:slug>-preview.png')->to('Page#get_post_preview'); $r->get('/posts/<:slug>-preview.png')->to('Page#get_post_preview');
$r->get('/posts/:slug')->to('Page#post'); $r->get('/posts/:slug')->to('Page#post');
$r->get('/stats/login')->to('Metrics#login');
$r->post('/stats/login')->to('Metrics#submit_login');
} }
1; 1;

View File

@ -13,8 +13,11 @@ use Mojo::Base 'Mojolicious::Controller';
use DateTime::Format::ISO8601; use DateTime::Format::ISO8601;
use DateTime::Format::Mail; use DateTime::Format::Mail;
use Crypt::Bcrypt qw/bcrypt bcrypt_check/;
my $tracking; my $tracking;
my $iso8601 = DateTime::Format::ISO8601->new;
sub request { sub request {
shift; shift;
my $c = shift; my $c = shift;
@ -24,4 +27,80 @@ sub request {
} }
$tracking->register_request($c); $tracking->register_request($c);
} }
sub stats {
my $self = shift;
if (!$self->valid_login) {
$self->res->headers->location('/stats/login');
$self->render(text => 'You must login', status => 302);
return;
}
my $data = $tracking->get_global_data($self);
$self->render(tracking_data => $data);
}
sub submit_login {
my $self = shift;
if ($self->valid_login) {
$self->res->headers->location('/stats');
$self->render(text => 'Already logged in.', status => 302);
return;
}
my $password = $self->param('password');
if (!defined $password) {
$self->render(text => 'No password passed.', status => 400);
return;
}
my $bcrypted_pass = $self->config->{bcrypt_pass_stats};
if (!defined $bcrypted_pass) {
warn "No bcrypt pass.";
$self->render(text => 'Server error.', status => 500);
return;
}
say $password;
say $bcrypted_pass;
if (!bcrypt_check( $password, $bcrypted_pass )) {
$self->render(text => 'Wrong password', status => 401);
return;
}
say STDERR 'Login success.';
my $expiration_date = DateTime->now->add( days => 1);
$self->session->{login} = "date_end_login:$expiration_date";
$self->res->headers->location('/stats');
$self->render(text => 'Login success.', status => 302);
return;
}
sub valid_login {
my $self = shift;
my $login_cookie = $self->session->{login};
if (!defined $login_cookie) {
return;
}
my ($date_text) = $login_cookie =~ /^date_end_login:(.*)$/;
my $date;
eval {
$date = $iso8601->parse_datetime($date_text);
};
if ($@) {
warn "Bad date in cookie $login_cookie.";
return;
}
my $current_date = DateTime->now();
if ($current_date > $date) {
return;
}
return 1;
}
sub login {
my $self = shift;
if ($self->valid_login) {
$self->res->headers->location('/stats');
$self->render(text => 'You are already logged in.', status => 302);
return;
}
$self->render;
}
1; 1;

View File

@ -37,4 +37,35 @@ EOF
say "Registered $remote_address with user agent $user_agent visited $path with $params_json"; say "Registered $remote_address with user agent $user_agent visited $path with $params_json";
} }
sub get_global_data {
my $self = shift;
my $c = shift;
my $app = $c->app;
my $dbh = BurguillosInfo::DB->connect($app);
my $data = $dbh->selectrow_hashref(<<'EOF', undef);
SELECT
(
SELECT COUNT(DISTINCT remote_address) FROM requests
) as unique_ips,
(
SELECT COUNT(DISTINCT remote_address)
FROM requests
where date > NOW() - interval '1 day'
) as unique_ips_last_24_hours,
(
SELECT COUNT(DISTINCT remote_address)
FROM requests
where date > NOW() - interval '1 week'
) as unique_ips_last_week,
(
SELECT COUNT(DISTINCT remote_address)
FROM requests
where date > NOW() - interval '1 month'
) as unique_ips_last_month;
EOF
return $data;
}
1; 1;

View File

@ -79,6 +79,9 @@ body {
font-size: 60px; font-size: 60px;
} }
div.description { div.description {
input {
display: block;
}
word-wrap: break-word; word-wrap: break-word;
div.suscribirse-rss { div.suscribirse-rss {
img { img {

View File

@ -0,0 +1,16 @@
<!DOCTYPE html>
<html lang="es">
<head>
<link rel="stylesheet" href="/css/styles.css"/>
</head>
<body>
<div class="site-wrapper">
</div>
<div class="page-contents">
<nav class="desktop">
<a href="/stats"><img class="index-image-menu" src="/img/burguillos.png"</img></a>
</nav>
<%= content %>
</div>
</body>
</html>

View File

@ -0,0 +1,8 @@
% layout 'stats';
<div class="description">
<h2>Login</h2>
<form enctype="application/json" method="post" action="/stats/login">
<input name="password" placeholder="Password" type="password"/>
<input type="submit" value="login">
</form>
</div>

View File

@ -0,0 +1,9 @@
% layout 'stats';
<div class="description">
<h2>Stats</h2>
<p>Unique visitors <%=$tracking_data->{unique_ips}%></p>
<p>Unique visitors last 24 hours <%=$tracking_data->{unique_ips_last_24_hours}%></p>
<p>Unique visitors last week <%=$tracking_data->{unique_ips_last_week}%></p>
<p>Unique visitors last month <%=$tracking_data->{unique_ips_last_month}%></p>
</div>