From de074342de0bdc3604a0610a0c5f9cce5338bb85 Mon Sep 17 00:00:00 2001
From: Birte Kristina Friesel
Date: Sun, 24 Sep 2023 18:19:17 +0200
Subject: [PATCH] add support for HAFAS connection suggestions; drop manual
destination list
Still TODO: handle stations that have several EVAs
---
lib/Travelynx/Command/database.pm | 14 +++
lib/Travelynx/Controller/Account.pm | 30 +----
lib/Travelynx/Controller/Traveling.pm | 146 ++++++++++++-------------
lib/Travelynx/Model/Journeys.pm | 3 +-
lib/Travelynx/Model/Users.pm | 27 +----
templates/_cancelled_departure.html.ep | 2 +-
templates/_checked_in.html.ep | 14 +--
templates/_checked_out.html.ep | 11 +-
templates/_connections.html.ep | 6 +-
templates/_connections_hafas.html.ep | 59 ++++++++++
templates/_transit_fyi.html.ep | 22 ----
templates/account.html.ep | 2 +-
templates/departures.html.ep | 9 +-
templates/use_history.html.ep | 24 ----
14 files changed, 177 insertions(+), 192 deletions(-)
create mode 100644 templates/_connections_hafas.html.ep
delete mode 100644 templates/_transit_fyi.html.ep
diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm
index c6880d0..b9074bc 100644
--- a/lib/Travelynx/Command/database.pm
+++ b/lib/Travelynx/Command/database.pm
@@ -1915,6 +1915,20 @@ my @migrations = (
}
);
},
+
+ # v49 -> v50
+ # travelynx 2.0 introduced proper HAFAS support, so there is no need for
+ # the 'FYI, here is some hAFAS data' kludge anymore.
+ sub {
+ my ($db) = @_;
+ $db->query(
+ qq{
+ drop view user_transit;
+ drop table localtransit;
+ update schema_version set version = 50;
+ }
+ );
+ },
);
sub sync_stations {
diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm
index 2664329..0d12fb8 100644
--- a/lib/Travelynx/Controller/Account.pm
+++ b/lib/Travelynx/Controller/Account.pm
@@ -799,11 +799,8 @@ sub profile {
sub insight {
my ($self) = @_;
- my $user = $self->current_user;
- my ( $use_history, $destinations ) = $self->users->use_history(
- uid => $user->{id},
- with_local_transit => 1
- );
+ my $user = $self->current_user;
+ my $use_history = $self->users->use_history( uid => $user->{id} );
if ( $self->param('action') and $self->param('action') eq 'save' ) {
if ( $self->param('on_departure') ) {
@@ -820,31 +817,16 @@ sub insight {
$use_history &= ~0x02;
}
- if ( $self->param('local_transit') ) {
- $use_history |= 0x04;
- }
- else {
- $use_history &= ~0x04;
- }
-
- if ( $self->param('destinations') ) {
- $destinations
- = [ split( qr{\r?\n\r?}, $self->param('destinations') ) ];
- }
-
$self->users->use_history(
- uid => $user->{id},
- set => $use_history,
- destinations => $destinations
+ uid => $user->{id},
+ set => $use_history
);
$self->flash( success => 'use_history' );
$self->redirect_to('account');
}
- $self->param( on_departure => $use_history & 0x01 ? 1 : 0 );
- $self->param( on_arrival => $use_history & 0x02 ? 1 : 0 );
- $self->param( local_transit => $use_history & 0x04 ? 1 : 0 );
- $self->param( destinations => join( "\n", @{$destinations} ) );
+ $self->param( on_departure => $use_history & 0x01 ? 1 : 0 );
+ $self->param( on_arrival => $use_history & 0x02 ? 1 : 0 );
$self->render('use_history');
}
diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm
index 28427ad..35e8222 100755
--- a/lib/Travelynx/Controller/Traveling.pm
+++ b/lib/Travelynx/Controller/Traveling.pm
@@ -27,11 +27,8 @@ sub has_str_in_list {
sub get_connecting_trains_p {
my ( $self, %opt ) = @_;
- my $uid = $opt{uid} //= $self->current_user->{id};
- my ( $use_history, $lt_stops ) = $self->users->use_history(
- uid => $uid,
- with_local_transit => 1
- );
+ my $uid = $opt{uid} //= $self->current_user->{id};
+ my $use_history = $self->users->use_history( uid => $uid );
my ( $eva, $exclude_via, $exclude_train_id, $exclude_before );
my $now = $self->now->epoch;
@@ -68,13 +65,14 @@ sub get_connecting_trains_p {
return $promise->reject;
}
- my @destinations = $self->journeys->get_connection_targets(%opt);
+ my @destinations
+ = uniq_by { $_->{name} } $self->journeys->get_connection_targets(%opt);
if ($exclude_via) {
- @destinations = grep { $_ ne $exclude_via } @destinations;
+ @destinations = grep { $_->{name} ne $exclude_via } @destinations;
}
- if ( not( @destinations or $use_history & 0x04 and @{$lt_stops} ) ) {
+ if ( not @destinations ) {
return $promise->reject;
}
@@ -83,8 +81,11 @@ sub get_connecting_trains_p {
= $can_check_in ? 40 : ( ( ${arr_countdown} // 0 ) / 60 + 40 );
my $iris_promise = Mojo::Promise->new;
+ my %via_count = map { $_->{name} => 0 } @destinations;
- if (@destinations) {
+ if ( $eva >= 8000000
+ and List::Util::any { $_->{eva} >= 8000000 } @destinations )
+ {
$self->iris->get_departures_p(
station => $eva,
lookbehind => 10,
@@ -94,7 +95,7 @@ sub get_connecting_trains_p {
sub {
my ($stationboard) = @_;
if ( $stationboard->{errstr} ) {
- $iris_promise->reject( $stationboard->{errstr} );
+ $iris_promise->resolve( [] );
return;
}
@@ -105,7 +106,6 @@ sub get_connecting_trains_p {
my @results;
my @cancellations;
my $excluded_train;
- my %via_count = map { $_ => 0 } @destinations;
for my $train ( @{ $stationboard->{results} } ) {
if ( not $train->departure ) {
next;
@@ -144,7 +144,7 @@ sub get_connecting_trains_p {
$train->sched_route_post, $train->sched_route_end
);
for my $dest (@destinations) {
- if ( has_str_in_list( $dest, @via ) ) {
+ if ( has_str_in_list( $dest->{name}, @via ) ) {
push( @cancellations, [ $train, $dest ] );
next;
}
@@ -153,8 +153,8 @@ sub get_connecting_trains_p {
else {
my @via = ( $train->route_post, $train->route_end );
for my $dest (@destinations) {
- if ( $via_count{$dest} < 2
- and has_str_in_list( $dest, @via ) )
+ if ( $via_count{ $dest->{name} } < 2
+ and has_str_in_list( $dest->{name}, @via ) )
{
push( @results, [ $train, $dest ] );
@@ -162,7 +162,7 @@ sub get_connecting_trains_p {
if ( not $train->departure
or $train->departure->epoch >= $now )
{
- $via_count{$dest}++;
+ $via_count{ $dest->{name} }++;
}
next;
}
@@ -234,7 +234,7 @@ sub get_connecting_trains_p {
}
)->catch(
sub {
- $iris_promise->reject(@_);
+ $iris_promise->resolve( [] );
return;
}
)->wait;
@@ -266,9 +266,9 @@ sub get_connecting_trains_p {
Mojo::Promise->all( $iris_promise, $hafas_promise )->then(
sub {
my ( $iris, $hafas ) = @_;
- my @iris_trains = @{ $iris->[0] };
- my @hafas_trains = @{ $hafas->[0] };
- my @transit_fyi;
+ my @iris_trains = @{ $iris->[0] };
+ my @all_hafas_trains = @{ $hafas->[0] };
+ my @hafas_trains;
# We've already got a list of connecting trains; this function
# only adds further information to them. We ignore errors, as
@@ -278,11 +278,12 @@ sub get_connecting_trains_p {
if ( $iris_train->[0]->departure_is_cancelled ) {
next;
}
- for my $hafas_train (@hafas_trains) {
+ for my $hafas_train (@all_hafas_trains) {
if ( $hafas_train->number
and $hafas_train->number
== $iris_train->[0]->train_no )
{
+ $hafas_train->{iris_seen} = 1;
if ( $hafas_train->load
and $hafas_train->load->{SECOND} )
{
@@ -290,7 +291,8 @@ sub get_connecting_trains_p {
}
for my $stop ( $hafas_train->route ) {
if ( $stop->{name}
- and $stop->{name} eq $iris_train->[1]
+ and $stop->{name} eq
+ $iris_train->[1]->{name}
and $stop->{arr} )
{
$iris_train->[2] = $stop->{arr};
@@ -308,39 +310,29 @@ sub get_connecting_trains_p {
}
}
}
- if ( $use_history & 0x04 and @{$lt_stops} ) {
- my %via_count = map { $_ => 0 } @{$lt_stops};
- for my $hafas_train (@hafas_trains) {
- for my $stop ( $hafas_train->route ) {
- for my $dest ( @{$lt_stops} ) {
- if ( $stop->{name}
- and $stop->{name} eq $dest
- and $via_count{$dest} < 2
- and $hafas_train->datetime )
+ for my $hafas_train (@all_hafas_trains) {
+ if ( $hafas_train->{iris_seen} ) {
+ next;
+ }
+ for my $stop ( $hafas_train->route ) {
+ for my $dest (@destinations) {
+ if ( $stop->{name}
+ and $stop->{name} eq $dest->{name}
+ and $via_count{ $dest->{name} } < 2
+ and $hafas_train->datetime )
+ {
+ my $departure = $hafas_train->datetime;
+ my $arrival = $stop->{arr};
+ my $delay = $hafas_train->delay;
+ if ( $delay
+ and $stop->{arr} == $stop->{sched_arr} )
{
- my $departure = $hafas_train->datetime;
- my $arrival = $stop->{arr};
- my $delay = $hafas_train->delay;
- if ( $delay
- and $stop->{arr} == $stop->{sched_arr} )
- {
- $arrival->add( minutes => $delay );
- }
- if ( $departure->epoch >= $exclude_before )
- {
- $via_count{$dest}++;
- push(
- @transit_fyi,
- [
- {
- line => $hafas_train->line,
- departure => $departure,
- departure_delay => $delay
- },
- $dest, $arrival
- ]
- );
- }
+ $arrival->add( minutes => $delay );
+ }
+ if ( $departure->epoch >= $exclude_before ) {
+ $via_count{ $dest->{name} }++;
+ push( @hafas_trains,
+ [ $hafas_train, $dest, $arrival ] );
}
}
}
@@ -353,14 +345,12 @@ sub get_connecting_trains_p {
);
}
- $promise->resolve( \@iris_trains, \@transit_fyi );
+ $promise->resolve( \@iris_trains, \@hafas_trains );
return;
}
)->catch(
sub {
my ($err) = @_;
-
- # TODO logging. HAFAS errors should never happen, IRIS errors are noteworthy too.
$promise->reject($err);
return;
}
@@ -401,13 +391,13 @@ sub homepage {
$self->render_later;
$self->get_connecting_trains_p->then(
sub {
- my ( $connecting_trains, $transit_fyi ) = @_;
+ my ( $connections_iris, $connections_hafas ) = @_;
$self->render(
'landingpage',
user_status => $status,
journey_visibility => $journey_visibility,
- connections => $connecting_trains,
- transit_fyi => $transit_fyi,
+ connections_iris => $connections_iris,
+ connections_hafas => $connections_hafas,
);
$self->users->mark_seen( uid => $uid );
}
@@ -474,13 +464,13 @@ sub status_card {
$self->render_later;
$self->get_connecting_trains_p->then(
sub {
- my ( $connecting_trains, $transit_fyi ) = @_;
+ my ( $connections_iris, $connections_hafas ) = @_;
$self->render(
'_checked_in',
journey => $status,
journey_visibility => $journey_visibility,
- connections => $connecting_trains,
- transit_fyi => $transit_fyi
+ connections_iris => $connections_iris,
+ connections_hafas => $connections_hafas,
);
}
)->catch(
@@ -510,8 +500,8 @@ sub status_card {
my ($connecting_trains) = @_;
$self->render(
'_cancelled_departure',
- journey => $status->{cancellation},
- connections => $connecting_trains
+ journey => $status->{cancellation},
+ connections_iris => $connecting_trains
);
}
)->catch(
@@ -529,11 +519,12 @@ sub status_card {
$self->render_later;
$self->get_connecting_trains_p->then(
sub {
- my ($connecting_trains) = @_;
+ my ( $connections_iris, $connections_hafas ) = @_;
$self->render(
'_checked_out',
- journey => $status,
- connections => $connecting_trains
+ journey => $status,
+ connections_iris => $connections_iris,
+ connections_hafas => $connections_hafas,
);
}
)->catch(
@@ -1028,18 +1019,19 @@ sub station {
if ($connections_p) {
$connections_p->then(
sub {
- my ($connecting_trains) = @_;
+ my ( $connections_iris, $connections_hafas ) = @_;
$self->render(
'departures',
- eva => $status->{station_eva},
- results => \@results,
- hafas => $use_hafas,
- station => $status->{station_name},
- related_stations => $status->{related_stations},
- user_status => $user_status,
- can_check_out => $can_check_out,
- connections => $connecting_trains,
- api_link => $api_link,
+ eva => $status->{station_eva},
+ results => \@results,
+ hafas => $use_hafas,
+ station => $status->{station_name},
+ related_stations => $status->{related_stations},
+ user_status => $user_status,
+ can_check_out => $can_check_out,
+ connections_iris => $connections_iris,
+ connections_hafas => $connections_hafas,
+ api_link => $api_link,
title => "travelynx: $status->{station_name}",
);
}
diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm
index 1c975f4..3fa2d96 100755
--- a/lib/Travelynx/Model/Journeys.pm
+++ b/lib/Travelynx/Model/Journeys.pm
@@ -1726,7 +1726,7 @@ sub get_connection_targets {
my $min_count = $opt{min_count} // 3;
if ( $opt{destination_name} ) {
- return ( $opt{destination_name} );
+ return ( { eva => $opt{eva}, name => $opt{destination_name} } );
}
my $dest_id = $opt{eva} // $self->get_latest_dest_id(%opt);
@@ -1755,7 +1755,6 @@ sub get_connection_targets {
= $res->hashes->grep( sub { shift->{count} >= $min_count } )
->map( sub { shift->{dest} } )->each;
@destinations = $self->{stations}->get_by_evas(@destinations);
- @destinations = map { $_->{name} } @destinations;
return @destinations;
}
diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm
index 4b108d4..4602fa2 100644
--- a/lib/Travelynx/Model/Users.pm
+++ b/lib/Travelynx/Model/Users.pm
@@ -567,7 +567,6 @@ sub delete {
$res{transit} = $db->delete( 'in_transit', { user_id => $uid } );
$res{hooks} = $db->delete( 'webhooks', { user_id => $uid } );
$res{trwl} = $db->delete( 'traewelling', { user_id => $uid } );
- $res{lt} = $db->delete( 'localtransit', { user_id => $uid } );
$res{password} = $db->delete( 'pending_passwords', { user_id => $uid } );
$res{relations} = $db->delete( 'relations',
[ { subject_id => $uid }, { object_id => $uid } ] );
@@ -651,34 +650,12 @@ sub use_history {
my $uid = $opt{uid};
my $value = $opt{set};
- if ( $opt{destinations} ) {
- $db->insert(
- 'localtransit',
- {
- user_id => $uid,
- data =>
- JSON->new->encode( { destinations => $opt{destinations} } )
- },
- { on_conflict => \'(user_id) do update set data = EXCLUDED.data' }
- );
- }
-
if ($value) {
$db->update( 'users', { use_history => $value }, { id => $uid } );
}
else {
- if ( $opt{with_local_transit} ) {
- my $res = $db->select(
- 'user_transit',
- [ 'use_history', 'data' ],
- { id => $uid }
- )->expand->hash;
- return ( $res->{use_history}, $res->{data}{destinations} // [] );
- }
- else {
- return $db->select( 'users', ['use_history'], { id => $uid } )
- ->hash->{use_history};
- }
+ return $db->select( 'users', ['use_history'], { id => $uid } )
+ ->hash->{use_history};
}
}
diff --git a/templates/_cancelled_departure.html.ep b/templates/_cancelled_departure.html.ep
index 2f7f60b..79492a5 100644
--- a/templates/_cancelled_departure.html.ep
+++ b/templates/_cancelled_departure.html.ep
@@ -5,7 +5,7 @@
in <%= $journey->{dep_name} %>
entfällt. Der Zugausfall auf der Fahrt nach <%= $journey->{arr_name} %> wurde bereits dokumentiert.
- % if (my @connections = @{stash('connections') // []}) {
+ % if (my @connections = @{stash('connections_iris') // []}) {
Alternative Reisemöglichkeiten:
%= include '_connections', connections => \@connections, checkin_from => $journey->{dep_eva};
% }
diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep
index f3ecda4..2300ddd 100644
--- a/templates/_checked_in.html.ep
+++ b/templates/_checked_in.html.ep
@@ -199,19 +199,17 @@
% }
- % if (my @connections = @{stash('connections') // []}) {
+ % if (@{stash('connections_iris') // [] } or @{stash('connections_hafas') // []}) {
Verbindungen
% if ($journey->{arrival_countdown} < 0) {
Fahrt auswählen zum Einchecken mit Zielwahl.
% }
- %= include '_connections', connections => \@connections, checkin_from => $journey->{arrival_countdown} < 0 ? $journey->{arr_eva} : undef;
- % }
- % if (my @transit_fyi = @{stash('transit_fyi') // []}) {
- Nahverkehr
- % if ($journey->{arrival_countdown} < 0) {
- Nur zur Information – kein Checkin möglich.
+ % if (@{stash('connections_iris') // [] }) {
+ %= include '_connections', connections => stash('connections_iris'), checkin_from => $journey->{arrival_countdown} < 0 ? $journey->{arr_eva} : undef;
+ % }
+ % if (@{stash('connections_hafas') // [] }) {
+ %= include '_connections_hafas', connections => stash('connections_hafas'), checkin_from => $journey->{arrival_countdown} < 0 ? $journey->{arr_eva} : undef;
% }
- %= include '_transit_fyi', transit_fyi => \@transit_fyi;
% }
% if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) {
diff --git a/templates/_checked_out.html.ep b/templates/_checked_out.html.ep
index 55ced95..98db660 100644
--- a/templates/_checked_out.html.ep
+++ b/templates/_checked_out.html.ep
@@ -3,10 +3,15 @@
Ausgecheckt
Aus <%= $journey->{train_type} %> <%= $journey->{train_no} %>
bis <%= $journey->{arr_name} %>
- % if (my @connections = @{stash('connections') // []}) {
+ % if (@{stash('connections_iris') // [] } or @{stash('connections_hafas') // []}) {
Verbindungen
- Zug auswählen zum Einchecken mit Zielwahl.
- %= include '_connections', connections => \@connections, checkin_from => $journey->{arr_eva};
+ Fahrt auswählen zum Einchecken mit Zielwahl.
+ % if (@{stash('connections_iris') // [] }) {
+ %= include '_connections', connections => stash('connections_iris'), checkin_from => $journey->{arr_eva};
+ % }
+ % if (@{stash('connections_hafas') // [] }) {
+ %= include '_connections_hafas', connections => stash('connections_hafas'), checkin_from => $journey->{arr_eva};
+ % }
% }
diff --git a/templates/_connections.html.ep b/templates/_connections.html.ep
index e4f1872..98be766 100644
--- a/templates/_connections.html.ep
+++ b/templates/_connections.html.ep
@@ -9,7 +9,7 @@
% $link_class = 'action-cancelled-from';
% }
% if ($checkin_from) {
-
+
% }
% else {
@@ -33,10 +33,10 @@
% if ($checkin_from) {
- <%= $via %>
+ <%= $via->{name} %>
% }
% else {
- %= $via
+ %= $via->{name}
% }
% if ($load) {
diff --git a/templates/_connections_hafas.html.ep b/templates/_connections_hafas.html.ep
new file mode 100644
index 0000000..9322116
--- /dev/null
+++ b/templates/_connections_hafas.html.ep
@@ -0,0 +1,59 @@
+
+ % for my $res (@{$connections}) {
+ % my ($train, $via, $via_arr) = @{$res};
+ % $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{};
+ % my $td_class = '';
+ % my $link_class = 'action-checkin';
+ % if ($train->is_cancelled) {
+ % $td_class = 'cancelled';
+ % $link_class = 'action-cancelled-from';
+ % }
+ % if ($checkin_from) {
+
+ % }
+ % else {
+
+ % }
+
+ % if ($train->platform) {
+ % if ($checkin_from) {
+ Gleis <%= $train->platform %>
+ % }
+ % else {
+ Gleis <%= $train->platform %>
+ % }
+
+ % }
+ % if ($checkin_from) {
+ <%= $train->line %>
+ % }
+ % else {
+ %= $train->line
+ % }
+
+
+ % if ($checkin_from) {
+ <%= $via->{name} %>
+ % }
+ % else {
+ %= $via->{name}
+ % }
+
+
+ % if ($train->is_cancelled) {
+ %= $train->sched_datetime->strftime('%H:%M')
+ ⊖
+ % }
+ % else {
+ %= $train->datetime->strftime('%H:%M')
+ % }
+ % if ($via_arr) {
+ → <%= $via_arr %>
+ % }
+ % if ($train->delay) {
+ %= sprintf('(%+d)', $train->delay)
+ % }
+
+
+ % }
+
diff --git a/templates/_transit_fyi.html.ep b/templates/_transit_fyi.html.ep
deleted file mode 100644
index 5951e7d..0000000
--- a/templates/_transit_fyi.html.ep
+++ /dev/null
@@ -1,22 +0,0 @@
-
- % for my $res (@{$transit_fyi}) {
- % my ($info, $via, $via_arr) = @{$res};
- % $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{};
-
-
- %= $info->{line}
-
-
- %= $via
-
-
- %= $info->{departure}->strftime('%H:%M')
- →
- %= $via_arr
- % if ($info->{departure_delay}) {
- %= sprintf('(%+d)', $info->{departure_delay})
- % }
-
-
- % }
-
diff --git a/templates/account.html.ep b/templates/account.html.ep
index fac5817..7f689c2 100644
--- a/templates/account.html.ep
+++ b/templates/account.html.ep
@@ -67,7 +67,7 @@
Verbindungen
edit
- % if ($use_history & 0x07) {
+ % if ($use_history & 0x03) {
Vorschläge aktiv
% }
% else {
diff --git a/templates/departures.html.ep b/templates/departures.html.ep
index 3a2516f..021e9ca 100644
--- a/templates/departures.html.ep
+++ b/templates/departures.html.ep
@@ -72,12 +72,17 @@
% }
-% elsif (not param('train') and my @connections = @{stash('connections') // []}) {
+% elsif (not param('train') and (@{stash('connections_iris') // []} or @{stash('connections_hafas') // []}) ) {
% $have_connections = 1;
Häufig genutzte Verbindungen – Fahrt auswählen zum Einchecken mit Zielwahl
- %= include '_connections', connections => \@connections, checkin_from => $eva;
+ % if (@{stash('connections_iris') // []}) {
+ %= include '_connections', connections => stash('connections_iris'), checkin_from => $eva;
+ % }
+ % if (@{stash('connections_hafas') // []}) {
+ %= include '_connections_hafas', connections => stash('connections_hafas'), checkin_from => $eva;
+ % }
% }
diff --git a/templates/use_history.html.ep b/templates/use_history.html.ep
index e90f17f..9b76e98 100644
--- a/templates/use_history.html.ep
+++ b/templates/use_history.html.ep
@@ -47,30 +47,6 @@
ohne Umweg über die Abfahrtstafel möglich.
-
-
-
- %= check_box local_transit => 1
- Nahverkehr
-
-
-
-
-
- Zeige beim Reisestatus zusätzlich Anschlussmöglichkeiten an den
- Nahverkehr. Diese dienen lediglich zur Information; ein Checkin ist
- nicht möglich. Es werden nur Anschlussmöglichkeiten zu Zielen
- angezeigt, die im folgenden Feld gelistet sind (ein Ziel pro
- Zeile, z.B. „Eichlinghofen H-Bahn, Dortmund“). Falls travelynx in
- Zukunft eine Möglichkeit für Checkins in Nahverkehrsmittel erhält,
- wird diese Liste ggf. gelöscht.
-
-
-
-
- %= text_area 'destinations', id => 'destinations', class => 'materialize-textarea'
-
-