From e07063c52c51569b5f252a202f5d71b5f70a73e7 Mon Sep 17 00:00:00 2001 From: Daniel Friesel Date: Fri, 26 Apr 2019 19:53:01 +0200 Subject: [PATCH] Add manual journey entry Closes #3 --- lib/Travelynx.pm | 134 +++++++++++++------------- lib/Travelynx/Controller/Traveling.pm | 65 +++++++++---- templates/_history_trains.html.ep | 2 +- templates/add_journey.html.ep | 40 ++++++-- templates/cancelled.html.ep | 2 +- templates/history.html.ep | 34 +++++-- templates/history_by_month.html.ep | 4 +- templates/history_by_year.html.ep | 4 +- templates/journey.html.ep | 31 ++++-- templates/landingpage.html.ep | 2 +- 10 files changed, 198 insertions(+), 120 deletions(-) diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 569b65f..017a2d4 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -220,27 +220,16 @@ sub startup { } ); - # Returns (checkin id, checkout id, error) + # Returns (journey id, error) # Must be called during a transaction. # Must perform a rollback on error. $self->helper( 'add_journey' => sub { my ( $self, %opt ) = @_; - $self->app->log->error( - "add_journey is not implemented at the moment"); - return ( undef, undef, 'not implemented' ); - - my $user_status = $self->get_user_status; - if ( $user_status->{checked_in} or $user_status->{cancelled} ) { - - # TODO: change database schema to one row per journey instead of two - return ( undef, undef, -'Während einer Zugfahrt können momentan keine manuellen Einträge vorgenommen werden. Klingt komisch, ist aber so.' - ); - } - + my $db = $opt{db}; my $uid = $self->current_user->{id}; + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); my $dep_station = get_station( $opt{dep_station} ); my $arr_station = get_station( $opt{arr_station} ); @@ -251,66 +240,48 @@ sub startup { return ( undef, undef, 'Unbekannter Zielbahnhof' ); } - my $checkin_id; - my $checkout_id; + my $entry = { + user_id => $uid, + train_type => $opt{train_type}, + train_line => $opt{train_line}, + train_no => $opt{train_no}, + train_id => 'manual', + checkin_station_id => $self->get_station_id( + ds100 => $dep_station->[0], + name => $dep_station->[1], + ), + checkin_time => $now, + sched_departure => $opt{sched_departure}, + real_departure => $opt{rt_departure}, + checkout_station_id => $self->get_station_id( + ds100 => $arr_station->[0], + name => $arr_station->[1], + ), + sched_arrival => $opt{sched_arrival}, + real_arrival => $opt{rt_arrival}, + checkout_time => $now, + edited => 0x3fff, + cancelled => $opt{cancelled} ? 1 : 0, + route => $dep_station->[1] . '|' . $arr_station->[1], + }; + if ( $opt{comment} ) { + $entry->{messages} = '0:' . $opt{comment}; + } + + my $journey_id = undef; eval { - $checkin_id = $self->pg->db->insert( - 'user_actions', - { - user_id => $uid, - action_id => 'checkin', - station_id => $self->get_station_id( - ds100 => $dep_station->[0], - name => $dep_station->[1], - ), - action_time => - DateTime->now( time_zone => 'Europe/Berlin' ), - edited => 0x0f, - train_type => $opt{train_type}, - train_line => $opt{train_line}, - train_no => $opt{train_no}, - sched_time => $opt{sched_departure}, - real_time => $opt{rt_departure}, - }, - { returning => 'id' } - )->hash->{id}; + $journey_id + = $db->insert( 'journeys', $entry, { returning => 'id' } ) + ->hash->{id}; }; if ($@) { - $self->app->log->error( - "add_journey($uid, checkin): INSERT failed: $@"); - return ( undef, undef, 'INSERT failed: ' . $@ ); + $self->app->log->error("add_journey($uid): $@"); + return ( undef, 'add_journey failed: ' . $@ ); } - eval { - $checkout_id = $self->pg->db->insert( - 'user_actions', - { - user_id => $uid, - action_id => 'checkout', - station_id => $self->get_station_id( - ds100 => $arr_station->[0], - name => $arr_station->[1], - ), - action_time => - DateTime->now( time_zone => 'Europe/Berlin' ), - edited => 0x0f, - train_type => $opt{train_type}, - train_line => $opt{train_line}, - train_no => $opt{train_no}, - sched_time => $opt{sched_arrival}, - real_time => $opt{rt_arrival}, - }, - { returnning => 'id' } - )->hash->{id}; - }; - if ($@) { - $self->app->log->error( - "add_journey($uid, checkout): INSERT failed: $@"); - return ( undef, undef, 'INSERT failed: ' . $@ ); - } - return ( $checkin_id, $checkout_id, undef ); + return ( $journey_id, undef ); } ); @@ -1096,6 +1067,31 @@ sub startup { } ); + $self->helper( + 'get_oldest_journey_ts' => sub { + my ($self) = @_; + + my $res_h = $self->pg->db->select( + 'journeys_str', + ['sched_dep_ts'], + { + user_id => $self->current_user->{id}, + }, + { + limit => 1, + order_by => { + -asc => 'real_dep_ts', + }, + } + )->hash; + + if ($res_h) { + return epoch_to_dt( $res_h->{sched_dep_ts} ); + } + return undef; + } + ); + $self->helper( 'get_user_travels' => sub { my ( $self, %opt ) = @_; @@ -1171,12 +1167,12 @@ sub startup { } $ref->{messages} = [ reverse @parsed_messages ]; $ref->{sched_duration} - = $ref->{sched_arrival} + = $ref->{sched_arrival}->epoch ? $ref->{sched_arrival}->epoch - $ref->{sched_departure}->epoch : undef; $ref->{rt_duration} - = $ref->{rt_arrival} + = $ref->{rt_arrival}->epoch ? $ref->{rt_arrival}->epoch - $ref->{rt_departure}->epoch : undef; my ( $km, $skip ) diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 5282d9a..ee8d27d 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -141,7 +141,7 @@ sub log_action { } elsif ( $params->{action} eq 'undo' ) { my $status = $self->get_user_status; - my $error = $self->undo( $params->{undo_id} ); + my $error = $self->undo( $params->{undo_id} ); if ($error) { $self->render( json => { @@ -152,7 +152,7 @@ sub log_action { } else { my $redir = '/'; - if ($status->{checked_in} or $status->{cancelled}) { + if ( $status->{checked_in} or $status->{cancelled} ) { $redir = '/s/' . $status->{dep_ds100}; } $self->render( @@ -562,37 +562,60 @@ sub add_journey_form { for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival)) { - my $datetime = $parser->parse_datetime( $self->param($key) ); - if ( not $datetime ) { - $self->render( - 'add_journey', - with_autocomplete => 1, - error => "${key}: Ungültiges Datums-/Zeitformat" - ); - return; + if ( $self->param($key) ) { + my $datetime = $parser->parse_datetime( $self->param($key) ); + if ( not $datetime ) { + $self->render( + 'add_journey', + with_autocomplete => 1, + error => "${key}: Ungültiges Datums-/Zeitformat" + ); + return; + } + $opt{$key} = $datetime; } - $opt{$key} = $datetime; } - for my $key (qw(dep_station arr_station)) { + for my $key (qw(dep_station arr_station cancelled comment)) { $opt{$key} = $self->param($key); } - #my ( $checkin_id, $checkout_id, $error ) = $self->add_journey(%opt); + my $db = $self->pg->db; + my $tx = $db->begin; + $opt{db} = $db; + + my ( $journey_id, $error ) = $self->add_journey(%opt); + + if ( not $error ) { + my $journey = $self->get_journey( + uid => $self->current_user->{id}, + db => $db, + journey_id => $journey_id, + verbose => 1 + ); + $error = $self->journey_sanity_check($journey); + } + + if ($error) { + $self->render( + 'add_journey', + with_autocomplete => 1, + error => $error, + ); + } + else { + $tx->commit; + $self->redirect_to("/journey/${journey_id}"); + } + } + else { $self->render( 'add_journey', with_autocomplete => 1, - error => 'not implemented', + error => undef ); - return; } - - $self->render( - 'add_journey', - with_autocomplete => 1, - error => undef - ); } 1; diff --git a/templates/_history_trains.html.ep b/templates/_history_trains.html.ep index 2328285..d422165 100644 --- a/templates/_history_trains.html.ep +++ b/templates/_history_trains.html.ep @@ -13,7 +13,7 @@ % for my $travel (@{$journeys}) { % my $detail_link = '/journey/' . $travel->{id}; - <%= $travel->{sched_departure}->strftime('%d.%m.') %> + <%= $travel->{sched_departure}->strftime($date_format) %> <%= $travel->{type} %> <%= $travel->{line} // $travel->{no} %> diff --git a/templates/add_journey.html.ep b/templates/add_journey.html.ep index e07f78f..10e74eb 100644 --- a/templates/add_journey.html.ep +++ b/templates/add_journey.html.ep @@ -1,4 +1,18 @@

Zugfahrt eingeben

+% if (not get_oldest_journey_ts()) { +
+
+
+
+ Hinweis +

travelynx ist darauf ausgelegt, über die Hauptseite in + Echtzeit in Züge ein- und auszuchecken. Die manuelle + Eingabe von Zugfahrten ist nur als Notlösung vorgesehen.

+
+
+
+
+% } % if ($error) {
@@ -23,37 +37,49 @@ %= form_for '/journey/add' => (method => 'POST') => begin %= csrf_field
-
+
%= text_field 'train', id => 'train', class => 'validate', required => undef, pattern => '[0-9a-zA-Z]+ +[0-9a-zA-Z]* *[0-9]+'
+
+ +
%= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', required => undef - +
%= text_field 'sched_departure', id => 'sched_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- %= text_field 'rt_departure', id => 'rt_departure', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]' - + %= text_field 'rt_departure', id => 'rt_departure', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]' +
%= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', required => undef - +
%= text_field 'sched_arrival', id => 'sched_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'
- %= text_field 'rt_arrival', id => 'rt_arrival', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]' - + %= text_field 'rt_arrival', id => 'rt_arrival', class => 'validate', required => undef, pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]' + +
+
+
+
+ %= text_field 'comment' +
diff --git a/templates/cancelled.html.ep b/templates/cancelled.html.ep index 88380ce..4fab434 100644 --- a/templates/cancelled.html.ep +++ b/templates/cancelled.html.ep @@ -17,4 +17,4 @@
-%= include '_history_trains', journeys => stash('journeys'); +%= include '_history_trains', date_format => '%d.%m.%Y', journeys => stash('journeys'); diff --git a/templates/history.html.ep b/templates/history.html.ep index 05f4777..246d6af 100644 --- a/templates/history.html.ep +++ b/templates/history.html.ep @@ -8,24 +8,44 @@
-

Nach Jahr

-% my $since = get_user_data()->{registered_at}; +% my $since = get_oldest_journey_ts(); % my $now = DateTime->now(time_zone => 'Europe/Berlin'); -%= include '_history_years', current => '', since => $since->clone, now => $now; +% if ($since) { + %= include '_history_years', current => '', since => $since->clone, now => $now; +% } +% else { +
+
+ Noch keine Fahrten. +
+
+% }

Nach Monat

-%= include '_history_months', current => '', since => $since->clone, now => $now; +% if ($since) { + %= include '_history_months', current => '', since => $since->clone, now => $now; +% } +% else { +
+
+ Noch keine Fahrten. +
+
+% } % if (stash('statistics')) { %= include '_history_stats', stats => stash('statistics'); diff --git a/templates/history_by_month.html.ep b/templates/history_by_month.html.ep index 3794858..64d42c6 100644 --- a/templates/history_by_month.html.ep +++ b/templates/history_by_month.html.ep @@ -1,4 +1,4 @@ -% my $since = get_user_data()->{registered_at}; +% my $since = get_oldest_journey_ts(); % my $now = DateTime->now(time_zone => 'Europe/Berlin'); %= include '_history_months', current => "${year}/${month}", since => $since, now => $now; @@ -9,5 +9,5 @@ % } % if (stash('journeys')) { - %= include '_history_trains', journeys => stash('journeys'); + %= include '_history_trains', date_format => '%d.%m.', journeys => stash('journeys'); % } diff --git a/templates/history_by_year.html.ep b/templates/history_by_year.html.ep index 97c223f..f73d7ec 100644 --- a/templates/history_by_year.html.ep +++ b/templates/history_by_year.html.ep @@ -1,4 +1,4 @@ -% my $since = get_user_data()->{registered_at}; +% my $since = get_oldest_journey_ts(); % my $now = DateTime->now(time_zone => 'Europe/Berlin'); %= include '_history_years', current => $year, since => $since, now => $now; @@ -9,5 +9,5 @@ % } % if (stash('journeys')) { - %= include '_history_trains', journeys => stash('journeys'); + %= include '_history_trains', date_format => '%d.%m.', journeys => stash('journeys'); % } diff --git a/templates/journey.html.ep b/templates/journey.html.ep index 4af9694..4d0f3fd 100644 --- a/templates/journey.html.ep +++ b/templates/journey.html.ep @@ -121,15 +121,27 @@ % } - - Meldungen - - % for my $message (@{$journey->{messages} // []}) { - % my ($ts, $msg) = @{$message}; - <%= $ts->strftime('%d.%m.%Y %H:%M') %> : <%= $msg %>
- % } - - + % if ($journey->{edited} == 0x3fff) { + + Kommentar + + % for my $message (@{$journey->{messages} // []}) { + <%= $message->[1] %>
+ % } + + + % } + % else { + + Meldungen + + % for my $message (@{$journey->{messages} // []}) { + % my ($ts, $msg) = @{$message}; + <%= $ts->strftime('%d.%m.%Y %H:%M') %> : <%= $msg %>
+ % } + + + % } Route @@ -172,6 +184,7 @@ %= form_for '/journey/edit' => (method => 'POST') => begin %= hidden_field 'journey_id' => param('journey_id') %= end diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep index e694229..c6551ec 100644 --- a/templates/landingpage.html.ep +++ b/templates/landingpage.html.ep @@ -73,7 +73,7 @@

Letzte Fahrten

- %= include '_history_trains', journeys => [get_user_travels(limit => 5)]; + %= include '_history_trains', date_format => '%d.%m', journeys => [get_user_travels(limit => 5)]; % } % else {