summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2019-04-23 21:30:31 +0200
committerDaniel Friesel <derf@finalrewind.org>2019-04-23 21:30:31 +0200
commitffaa0c44a78bb4bab632fcb76b668215da4c0a82 (patch)
treee4379158253dbdfbc0b6217e351da5a410ad1074
parent5af134ef1ec968597a8fb9feb44372657d178bb8 (diff)
Automatic checkout \o/
-rwxr-xr-xlib/Travelynx.pm44
-rw-r--r--lib/Travelynx/Command/work.pm111
-rw-r--r--templates/landingpage.html.ep46
3 files changed, 171 insertions, 30 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm
index da10a9a..c11f175 100755
--- a/lib/Travelynx.pm
+++ b/lib/Travelynx.pm
@@ -474,10 +474,10 @@ sub startup {
# called twice: once with the old and once with the new value.
$self->helper(
'invalidate_stats_cache' => sub {
- my ( $self, $ts, $db ) = @_;
+ my ( $self, $ts, $db, $uid ) = @_;
- my $uid = $self->current_user->{id};
- $db //= $self->pg->db;
+ $uid //= $self->current_user->{id};
+ $db //= $self->pg->db;
$self->pg->db->delete(
'journey_stats',
@@ -500,12 +500,12 @@ sub startup {
$self->helper(
'checkout' => sub {
- my ( $self, $station, $force ) = @_;
+ my ( $self, $station, $force, $uid ) = @_;
- my $db = $self->pg->db;
- my $uid = $self->current_user->{id};
- my $status = $self->get_departures( $station, 120, 120 );
- my $user = $self->get_user_status;
+ my $db = $self->pg->db;
+ my $status = $self->get_departures( $station, 120, 120 );
+ $uid //= $self->current_user->{id};
+ my $user = $self->get_user_status($uid);
my $train_id = $user->{train_id};
if ( not $user->{checked_in} and not $user->{cancelled} ) {
@@ -602,7 +602,7 @@ sub startup {
month => $+{month}
);
}
- $self->invalidate_stats_cache( $cache_ts, $db );
+ $self->invalidate_stats_cache( $cache_ts, $db, $uid );
}
$tx->commit;
@@ -1268,7 +1268,7 @@ sub startup {
// $in_transit->{checkin_ts};
my $action_time = epoch_to_dt($ts);
- return {
+ my $ret = {
checked_in => !$in_transit->{cancelled},
cancelled => $in_transit->{cancelled},
timestamp => $action_time,
@@ -1288,6 +1288,30 @@ sub startup {
arr_name => $in_transit->{arr_name},
route_after => \@route_after,
};
+
+ $ret->{departure_countdown}
+ = $ret->{real_departure}->epoch - $now->epoch;
+ if ( $in_transit->{real_arr_ts} ) {
+ $ret->{arrival_countdown}
+ = $ret->{real_arrival}->epoch - $now->epoch;
+ $ret->{journey_duration} = $ret->{real_arrival}->epoch
+ - $ret->{real_departure}->epoch;
+ $ret->{journey_completion} = 1 - (
+ $ret->{arrival_countdown} / $ret->{journey_duration} );
+ if ( $ret->{journey_completion} > 1 ) {
+ $ret->{journey_completion} = 1;
+ }
+ elsif ( $ret->{journey_completion} < 0 ) {
+ $ret->{journey_completion} = 0;
+ }
+ }
+ else {
+ $ret->{arrival_countdown} = undef;
+ $ret->{journey_duration} = undef;
+ $ret->{journey_completion} = undef;
+ }
+
+ return $ret;
}
my $latest = $db->select(
diff --git a/lib/Travelynx/Command/work.pm b/lib/Travelynx/Command/work.pm
new file mode 100644
index 0000000..b8f8e52
--- /dev/null
+++ b/lib/Travelynx/Command/work.pm
@@ -0,0 +1,111 @@
+package Travelynx::Command::work;
+use Mojo::Base 'Mojolicious::Command';
+
+use DateTime;
+use List::Util qw(first);
+
+has description =>
+ 'Perform automatic checkout when users arrive at their destination';
+
+has usage => sub { shift->extract_usage };
+
+sub run {
+ my ($self) = @_;
+
+ my $now = DateTime->now( time_zone => 'Europe/Berlin' );
+
+ my $db = $self->app->pg->db;
+
+ for my $entry (
+ $db->select( 'in_transit_str', '*', { cancelled => 0 } )->hashes->each )
+ {
+
+ my $uid = $entry->{user_id};
+ my $dep = $entry->{dep_ds100};
+ my $arr = $entry->{arr_ds100};
+ my $train = $entry->{train_id};
+
+ $self->app->log->debug("Processing $uid");
+
+ eval {
+ if ( $now->epoch - $entry->{real_dep_ts} < 300 ) {
+ $self->app->log->debug(" - updating departure");
+ my $status = $self->app->get_departures( $dep, 30, 30 );
+ if ( $status->{errstr} ) {
+ die("get_departures($dep): $status->{errstr}\n");
+ }
+
+ my ($train)
+ = first { $_->train_id eq $train } @{ $status->{results} };
+
+ if ( not $train ) {
+ die("could not find train $train at $dep\n");
+ }
+
+ $db->update(
+ 'in_transit',
+ { real_departure => $train->departure },
+ { user_id => $uid }
+ );
+ }
+ };
+ if ($@) {
+ $self->app->log->error("work($uid)/departure: $@");
+ }
+
+ eval {
+ if (
+ $entry->{arr_name}
+ and ( not $entry->{real_arr_ts}
+ or $now->epoch - $entry->{real_arr_ts} < 60 )
+ )
+ {
+ $self->app->log->debug(" - updating arrival");
+ my $status = $self->app->get_departures( $arr, 20, 220 );
+ if ( $status->{errstr} ) {
+ die("get_departures($arr): $status->{errstr}\n");
+ }
+
+ my ($train)
+ = first { $_->train_id eq $train } @{ $status->{results} };
+
+ if ( not $train ) {
+ die("could not find train $train at $arr\n");
+ }
+
+ $db->update(
+ 'in_transit',
+ {
+ sched_arrival => $train->sched_arrival,
+ real_arrival => $train->arrival,
+ },
+ { user_id => $uid }
+ );
+ }
+ elsif ( $entry->{real_arr_ts} ) {
+ $self->app->log->debug(" - checking out");
+ my ( undef, $error ) = $self->app->checkout( $arr, 1, $uid );
+ if ($error) {
+ die("${error}\n");
+ }
+ }
+ };
+ if ($@) {
+ $self->app->log->error("work($uid)/arrival: $@");
+ }
+
+ eval { }
+ }
+}
+
+1;
+
+__END__
+
+=head1 SYNOPSIS
+
+ Usage: index.pl work
+
+ Work Work Work.
+
+ Should be called from a cronjob every three minutes or so.
diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep
index 26bae8d..84514c5 100644
--- a/templates/landingpage.html.ep
+++ b/templates/landingpage.html.ep
@@ -14,12 +14,6 @@
<div class="row">
<div class="col s12">
% my $status = get_user_status();
- % my $now = DateTime->now(time_zone => 'Europe/Berlin');
- % my $dep_wait = ($status->{real_departure}->epoch - $now->epoch)/60;
- % my $arr_wait = undef;
- % if ($status->{real_arrival}->epoch) {
- % $arr_wait = ($status->{real_arrival}->epoch - $now->epoch)/60;
- % }
% if ($status->{checked_in}) {
<div class="card green darken-4">
<div class="card-content white-text">
@@ -34,30 +28,42 @@
% }
</p>
<p>
- Abfahrt
- % if ($dep_wait > 0) {
- in <%= int(($status->{real_departure}->epoch - $now->epoch)/60) %> Minute<%= $dep_wait == 1 ? '' : 'n' %>
- % }
- um <b><%= $status->{real_departure}->strftime('%H:%M') %></b>
+ <b><%= $status->{real_departure}->strftime('%H:%M') %></b>
% if ($status->{real_departure}->epoch != $status->{sched_departure}->epoch) {
- (+<%= int(($status->{real_departure}->epoch - $status->{sched_departure}->epoch)/60) %>)
+ (<%= sprintf('%+d', ($status->{real_departure}->epoch - $status->{sched_departure}->epoch)/60) %>)
% }
- </p>
- <p>
+ →
% if ($status->{real_arrival}->epoch) {
- Voraussichtliche Ankunft um <b><%= $status->{real_arrival}->strftime('%H:%M') %></b>
+ <b><%= $status->{real_arrival}->strftime('%H:%M') %></b>
% if ($status->{real_arrival}->epoch != $status->{sched_arrival}->epoch) {
- (+<%= int(($status->{real_arrival}->epoch - $status->{sched_arrival}->epoch)/60) %>)
+ (<%= sprintf('%+d', ($status->{real_arrival}->epoch - $status->{sched_arrival}->epoch)/60) %>)
% }
% }
% else {
- Ankunft: noch nicht bekannt
+ unbekannt
% }
</p>
<p>
- <b>Achtung:</b> Automatischer Checkout ist noch nicht
- implementiert. Bitte spätestens eine Stunde nach Ankunft
- am Ziel manuell auschecken.
+ <div class="center">
+ % if ($status->{departure_countdown} > 120) {
+ Abfahrt in <%= int($status->{departure_countdown} / 60) %> Minuten
+ % }
+ % elsif ($status->{arrival_countdown}) {
+ % if ($status->{arrival_countdown} > 0) {
+ Ankunft in <%= int($status->{arrival_countdown} / 60) %>
+ Minute<%= int($status->{arrival_countdown} / 60) == 1 ? '' : 'n' %>
+ % }
+ % else {
+ Ziel erreicht
+ % }
+ % }
+ % elsif ($status->{arr_name}) {
+ Ankunft in mehr als zwei Stunden
+ % }
+ </div>
+ <div class="progress green darken-3" style="height: 1ex;">
+ <div class="determinate white" style="width: <%= sprintf('%.2f', 100 * $status->{journey_completion}); %>%;"></div>
+ </div>
</p>
% if ($status->{arr_name}) {
<p>Zielstation ändern?</p>