Loading lib/Travelynx.pm +64 −68 Original line number Diff line number Diff line Loading @@ -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} ); Loading @@ -251,66 +240,48 @@ sub startup { return ( undef, undef, 'Unbekannter Zielbahnhof' ); } my $checkin_id; my $checkout_id; eval { $checkin_id = $self->pg->db->insert( 'user_actions', { my $entry = { 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}; 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 ($@) { $self->app->log->error( "add_journey($uid, checkin): INSERT failed: $@"); return ( undef, undef, 'INSERT failed: ' . $@ ); if ( $opt{comment} ) { $entry->{messages} = '0:' . $opt{comment}; } my $journey_id = undef; 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}; $journey_id = $db->insert( 'journeys', $entry, { returning => 'id' } ) ->hash->{id}; }; if ($@) { $self->app->log->error( "add_journey($uid, checkout): INSERT failed: $@"); return ( undef, undef, 'INSERT failed: ' . $@ ); $self->app->log->error("add_journey($uid): $@"); return ( undef, 'add_journey failed: ' . $@ ); } return ( $checkin_id, $checkout_id, undef ); return ( $journey_id, undef ); } ); Loading Loading @@ -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 ) = @_; Loading Loading @@ -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 ) Loading lib/Travelynx/Controller/Traveling.pm +44 −21 Original line number Diff line number Diff line Loading @@ -562,6 +562,7 @@ sub add_journey_form { for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival)) { if ( $self->param($key) ) { my $datetime = $parser->parse_datetime( $self->param($key) ); if ( not $datetime ) { $self->render( Loading @@ -573,26 +574,48 @@ sub add_journey_form { } $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 => 'not implemented', error => $error, ); return; } else { $tx->commit; $self->redirect_to("/journey/${journey_id}"); } } else { $self->render( 'add_journey', with_autocomplete => 1, error => undef ); } } 1; templates/_history_trains.html.ep +1 −1 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ % for my $travel (@{$journeys}) { % my $detail_link = '/journey/' . $travel->{id}; <tr> <td><%= $travel->{sched_departure}->strftime('%d.%m.') %></td> <td><%= $travel->{sched_departure}->strftime($date_format) %></td> <td><a href="<%= $detail_link %>"><%= $travel->{type} %> <%= $travel->{line} // $travel->{no} %></a></td> <td> <a href="<%= $detail_link %>" class="unmarked"> Loading templates/add_journey.html.ep +33 −7 Original line number Diff line number Diff line <h1>Zugfahrt eingeben</h1> % if (not get_oldest_journey_ts()) { <div class="row"> <div class="col s12"> <div class="card yellow lighten-4"> <div class="card-content"> <span class="card-title">Hinweis</span> <p>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.</p> </div> </div> </div> </div> % } % if ($error) { <div class="row"> <div class="col s12"> Loading @@ -23,37 +37,49 @@ %= form_for '/journey/add' => (method => 'POST') => begin %= csrf_field <div class="row"> <div class="input-field col s12"> <div class="input-field col s12 m6 l6"> %= text_field 'train', id => 'train', class => 'validate', required => undef, pattern => '[0-9a-zA-Z]+ +[0-9a-zA-Z]* *[0-9]+' <label for="train">Zug (Typ Linie Nummer)</label> </div> <div class="input-field col s12 m6 l6"> <label> %= check_box cancelled => 1 <span>Fahrt ist ausgefallen</span> </label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', required => undef <label for="dep_station">Startbahnhof (Name oder DS100)</label> <label for="dep_station">Start (Name oder DS100)</label> </div> <div class="input-field col s12"> %= 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]' <label for="sched_departure">Geplante Abfahrt</label> </div> <div class="input-field col s12"> %= 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]' <label for="rt_departure">Tatsächliche Abfahrt (optional)</label> %= 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]' <label for="rt_departure">Tatsächliche Abfahrt</label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', required => undef <label for="arr_station">Zielbahnhof (Name oder DS100)</label> <label for="arr_station">Ziel (Name oder DS100)</label> </div> <div class="input-field col s12"> %= 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]' <label for="sched_arrival">Geplante Ankunft</label> </div> <div class="input-field col s12"> %= 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]' <label for="rt_arrival">Tatsächliche Ankunft (optional)</label> %= 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]' <label for="rt_arrival">Tatsächliche Ankunft</label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'comment' <label for="comment">Kommentar</label> </div> </div> <div class="row"> Loading templates/cancelled.html.ep +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ </div> </div> %= include '_history_trains', journeys => stash('journeys'); %= include '_history_trains', date_format => '%d.%m.%Y', journeys => stash('journeys'); Loading
lib/Travelynx.pm +64 −68 Original line number Diff line number Diff line Loading @@ -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} ); Loading @@ -251,66 +240,48 @@ sub startup { return ( undef, undef, 'Unbekannter Zielbahnhof' ); } my $checkin_id; my $checkout_id; eval { $checkin_id = $self->pg->db->insert( 'user_actions', { my $entry = { 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}; 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 ($@) { $self->app->log->error( "add_journey($uid, checkin): INSERT failed: $@"); return ( undef, undef, 'INSERT failed: ' . $@ ); if ( $opt{comment} ) { $entry->{messages} = '0:' . $opt{comment}; } my $journey_id = undef; 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}; $journey_id = $db->insert( 'journeys', $entry, { returning => 'id' } ) ->hash->{id}; }; if ($@) { $self->app->log->error( "add_journey($uid, checkout): INSERT failed: $@"); return ( undef, undef, 'INSERT failed: ' . $@ ); $self->app->log->error("add_journey($uid): $@"); return ( undef, 'add_journey failed: ' . $@ ); } return ( $checkin_id, $checkout_id, undef ); return ( $journey_id, undef ); } ); Loading Loading @@ -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 ) = @_; Loading Loading @@ -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 ) Loading
lib/Travelynx/Controller/Traveling.pm +44 −21 Original line number Diff line number Diff line Loading @@ -562,6 +562,7 @@ sub add_journey_form { for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival)) { if ( $self->param($key) ) { my $datetime = $parser->parse_datetime( $self->param($key) ); if ( not $datetime ) { $self->render( Loading @@ -573,26 +574,48 @@ sub add_journey_form { } $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 => 'not implemented', error => $error, ); return; } else { $tx->commit; $self->redirect_to("/journey/${journey_id}"); } } else { $self->render( 'add_journey', with_autocomplete => 1, error => undef ); } } 1;
templates/_history_trains.html.ep +1 −1 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ % for my $travel (@{$journeys}) { % my $detail_link = '/journey/' . $travel->{id}; <tr> <td><%= $travel->{sched_departure}->strftime('%d.%m.') %></td> <td><%= $travel->{sched_departure}->strftime($date_format) %></td> <td><a href="<%= $detail_link %>"><%= $travel->{type} %> <%= $travel->{line} // $travel->{no} %></a></td> <td> <a href="<%= $detail_link %>" class="unmarked"> Loading
templates/add_journey.html.ep +33 −7 Original line number Diff line number Diff line <h1>Zugfahrt eingeben</h1> % if (not get_oldest_journey_ts()) { <div class="row"> <div class="col s12"> <div class="card yellow lighten-4"> <div class="card-content"> <span class="card-title">Hinweis</span> <p>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.</p> </div> </div> </div> </div> % } % if ($error) { <div class="row"> <div class="col s12"> Loading @@ -23,37 +37,49 @@ %= form_for '/journey/add' => (method => 'POST') => begin %= csrf_field <div class="row"> <div class="input-field col s12"> <div class="input-field col s12 m6 l6"> %= text_field 'train', id => 'train', class => 'validate', required => undef, pattern => '[0-9a-zA-Z]+ +[0-9a-zA-Z]* *[0-9]+' <label for="train">Zug (Typ Linie Nummer)</label> </div> <div class="input-field col s12 m6 l6"> <label> %= check_box cancelled => 1 <span>Fahrt ist ausgefallen</span> </label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'dep_station', id => 'dep_station', class => 'autocomplete validate', required => undef <label for="dep_station">Startbahnhof (Name oder DS100)</label> <label for="dep_station">Start (Name oder DS100)</label> </div> <div class="input-field col s12"> %= 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]' <label for="sched_departure">Geplante Abfahrt</label> </div> <div class="input-field col s12"> %= 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]' <label for="rt_departure">Tatsächliche Abfahrt (optional)</label> %= 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]' <label for="rt_departure">Tatsächliche Abfahrt</label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'arr_station', id => 'arr_station', class => 'autocomplete validate', required => undef <label for="arr_station">Zielbahnhof (Name oder DS100)</label> <label for="arr_station">Ziel (Name oder DS100)</label> </div> <div class="input-field col s12"> %= 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]' <label for="sched_arrival">Geplante Ankunft</label> </div> <div class="input-field col s12"> %= 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]' <label for="rt_arrival">Tatsächliche Ankunft (optional)</label> %= 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]' <label for="rt_arrival">Tatsächliche Ankunft</label> </div> </div> <div class="row"> <div class="input-field col s12"> %= text_field 'comment' <label for="comment">Kommentar</label> </div> </div> <div class="row"> Loading
templates/cancelled.html.ep +1 −1 Original line number Diff line number Diff line Loading @@ -17,4 +17,4 @@ </div> </div> %= include '_history_trains', journeys => stash('journeys'); %= include '_history_trains', date_format => '%d.%m.%Y', journeys => stash('journeys');