summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xlib/Travelynx.pm132
-rwxr-xr-xlib/Travelynx/Controller/Traveling.pm65
-rw-r--r--templates/_history_trains.html.ep2
-rw-r--r--templates/add_journey.html.ep40
-rw-r--r--templates/cancelled.html.ep2
-rw-r--r--templates/history.html.ep34
-rw-r--r--templates/history_by_month.html.ep4
-rw-r--r--templates/history_by_year.html.ep4
-rw-r--r--templates/journey.html.ep31
-rw-r--r--templates/landingpage.html.ep2
10 files changed, 197 insertions, 119 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;
-
- 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};
+ 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 ($@) {
- $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 );
}
);
@@ -1097,6 +1068,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};
<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">
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 @@
<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">
@@ -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">
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 @@
</div>
</div>
-%= 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 @@
</div>
<div class="row">
- <div class="col s12 m12 l4 center-align">
+ <div class="col s12 m12 l3 center-align">
<a href="/cancelled" class="waves-effect waves-light btn"><i class="material-icons left">cancel</i> Zugausfälle</a>
</div>
- <div class="col s12 m12 l4">
- &nbsp;
- </div>
+ <div class="col s12 m12 l1">&nbsp;</div>
<div class="col s12 m12 l4 center-align">
+ <a href="/journey/add" class="waves-effect waves-light btn"><i class="material-icons left">add</i> Neue Fahrt</a>
+ </div>
+ <div class="col s12 m12 l1">&nbsp;</div>
+ <div class="col s12 m12 l3 center-align">
<a href="/history.json" class="waves-effect waves-light btn"><i class="material-icons left">cloud</i> JSON-Export</a>
</div>
</div>
<h2>Nach Jahr</h2>
-% 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 {
+ <div class="row">
+ <div class="col s12">
+ Noch keine Fahrten.
+ </div>
+ </div>
+% }
<h2>Nach Monat</h2>
-%= include '_history_months', current => '', since => $since->clone, now => $now;
+% if ($since) {
+ %= include '_history_months', current => '', since => $since->clone, now => $now;
+% }
+% else {
+ <div class="row">
+ <div class="col s12">
+ Noch keine Fahrten.
+ </div>
+ </div>
+% }
% 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 @@
% }
</td>
</tr>
- <tr>
- <th scope="row">Meldungen</th>
- <td>
- % for my $message (@{$journey->{messages} // []}) {
- % my ($ts, $msg) = @{$message};
- <%= $ts->strftime('%d.%m.%Y %H:%M') %> : <%= $msg %><br/>
- % }
- </td>
- </tr>
+ % if ($journey->{edited} == 0x3fff) {
+ <tr>
+ <th scope="row">Kommentar</th>
+ <td>
+ % for my $message (@{$journey->{messages} // []}) {
+ <%= $message->[1] %><br/>
+ % }
+ </td>
+ </tr>
+ % }
+ % else {
+ <tr>
+ <th scope="row">Meldungen</th>
+ <td>
+ % for my $message (@{$journey->{messages} // []}) {
+ % my ($ts, $msg) = @{$message};
+ <%= $ts->strftime('%d.%m.%Y %H:%M') %> : <%= $msg %><br/>
+ % }
+ </td>
+ </tr>
+ % }
<tr>
<th scope="row">Route</th>
<td>
@@ -172,6 +184,7 @@
%= form_for '/journey/edit' => (method => 'POST') => begin
%= hidden_field 'journey_id' => param('journey_id')
<button class="btn waves-effect waves-light" type="submit" name="action" value="edit">
+ <i class="material-icons left">edit</i>
Bearbeiten
</button>
%= 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 @@
</div>
</div>
<h1>Letzte Fahrten</h1>
- %= include '_history_trains', journeys => [get_user_travels(limit => 5)];
+ %= include '_history_trains', date_format => '%d.%m', journeys => [get_user_travels(limit => 5)];
% }
% else {
<div class="row">