From 5c5fa005e5830bb13b688cd8e42ff470092b0c94 Mon Sep 17 00:00:00 2001 From: sergiotarxz Date: Thu, 17 Nov 2022 00:44:20 +0100 Subject: [PATCH] Adding stats view. --- burguillos_info.json.example | 2 + lib/BurguillosInfo.pm | 4 ++ lib/BurguillosInfo/Controller/Metrics.pm | 79 ++++++++++++++++++++++++ lib/BurguillosInfo/Tracking.pm | 31 ++++++++++ public/css/styles.scss | 3 + templates/layouts/stats.html.ep | 16 +++++ templates/metrics/login.html.ep | 8 +++ templates/metrics/stats.html.ep | 9 +++ 8 files changed, 152 insertions(+) create mode 100644 templates/layouts/stats.html.ep create mode 100644 templates/metrics/login.html.ep create mode 100644 templates/metrics/stats.html.ep diff --git a/burguillos_info.json.example b/burguillos_info.json.example index aef7a35..bf65a22 100644 --- a/burguillos_info.json.example +++ b/burguillos_info.json.example @@ -1,4 +1,6 @@ { + "secrets": ["secret_change_for_pwgen_generated_one_with_at_least 255 chars"], + "bcrypt_pass_stats": ["change_for_bcrypted_password"], "db": { "database": "example" } diff --git a/lib/BurguillosInfo.pm b/lib/BurguillosInfo.pm index aab0027..2c1d4c2 100644 --- a/lib/BurguillosInfo.pm +++ b/lib/BurguillosInfo.pm @@ -20,6 +20,7 @@ sub startup ($self) { my $config = $self->plugin('JSONConfig'); $self->config( hypnotoad => { proxy => 1, listen => ['http://localhost:3000'] } ); + $self->secrets($self->config->{secrets}); # Router my $r = $self->routes; @@ -28,10 +29,13 @@ sub startup ($self) { $r->get('/')->to('Page#index'); # $r->get('/:post')->to('Page#post'); + $r->get('/stats')->to('Metrics#stats'); $r->get('/<:category>.rss')->to('Page#category_rss'); $r->get('/:category')->to('Page#category'); $r->get('/posts/<:slug>-preview.png')->to('Page#get_post_preview'); $r->get('/posts/:slug')->to('Page#post'); + $r->get('/stats/login')->to('Metrics#login'); + $r->post('/stats/login')->to('Metrics#submit_login'); } 1; diff --git a/lib/BurguillosInfo/Controller/Metrics.pm b/lib/BurguillosInfo/Controller/Metrics.pm index 50baa76..db53fe5 100644 --- a/lib/BurguillosInfo/Controller/Metrics.pm +++ b/lib/BurguillosInfo/Controller/Metrics.pm @@ -13,8 +13,11 @@ use Mojo::Base 'Mojolicious::Controller'; use DateTime::Format::ISO8601; use DateTime::Format::Mail; +use Crypt::Bcrypt qw/bcrypt bcrypt_check/; my $tracking; + +my $iso8601 = DateTime::Format::ISO8601->new; sub request { shift; my $c = shift; @@ -24,4 +27,80 @@ sub request { } $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; diff --git a/lib/BurguillosInfo/Tracking.pm b/lib/BurguillosInfo/Tracking.pm index 74a277b..9e6ad58 100644 --- a/lib/BurguillosInfo/Tracking.pm +++ b/lib/BurguillosInfo/Tracking.pm @@ -37,4 +37,35 @@ EOF 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; diff --git a/public/css/styles.scss b/public/css/styles.scss index a76648a..30933b0 100644 --- a/public/css/styles.scss +++ b/public/css/styles.scss @@ -79,6 +79,9 @@ body { font-size: 60px; } div.description { + input { + display: block; + } word-wrap: break-word; div.suscribirse-rss { img { diff --git a/templates/layouts/stats.html.ep b/templates/layouts/stats.html.ep new file mode 100644 index 0000000..ec8a666 --- /dev/null +++ b/templates/layouts/stats.html.ep @@ -0,0 +1,16 @@ + + + + + + +
+
+
+ + <%= content %> +
+ + diff --git a/templates/metrics/login.html.ep b/templates/metrics/login.html.ep new file mode 100644 index 0000000..e946c85 --- /dev/null +++ b/templates/metrics/login.html.ep @@ -0,0 +1,8 @@ +% layout 'stats'; +
+

Login

+
+ + +
+
diff --git a/templates/metrics/stats.html.ep b/templates/metrics/stats.html.ep new file mode 100644 index 0000000..97dfa2a --- /dev/null +++ b/templates/metrics/stats.html.ep @@ -0,0 +1,9 @@ +% layout 'stats'; +
+

Stats

+ +

Unique visitors <%=$tracking_data->{unique_ips}%>

+

Unique visitors last 24 hours <%=$tracking_data->{unique_ips_last_24_hours}%>

+

Unique visitors last week <%=$tracking_data->{unique_ips_last_week}%>

+

Unique visitors last month <%=$tracking_data->{unique_ips_last_month}%>

+