From f79d7c1e91c57959b55b698cf8ce24da133160dc Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Thu, 16 Jan 2025 18:11:02 +0100 Subject: InTransit: _epoch: turn undef into undef --- lib/Travelynx/Model/InTransit.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 62e60f1..43ecb90 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -30,7 +30,7 @@ my %visibility_atoi = ( sub _epoch { my ($dt) = @_; - return $dt ? $dt->epoch : 0; + return $dt ? $dt->epoch : undef; } sub epoch_to_dt { -- cgit v1.2.3 From a9b5a18943c3e2070703e745cd1131a02fd20365 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sun, 23 Mar 2025 18:07:50 +0100 Subject: Preliminary DBRIS support (not user-accessible yet) working: * checkin * checkout * realtime data * polylines * carriage formation (long-distance only) to do: * geolocation * redirects after checkout / undo * traewelling sync * use dbris by default --- lib/Travelynx.pm | 170 +++++++++++++++++++++++++++++++++- lib/Travelynx/Command/database.pm | 153 ++++++++++++++++++++++++++++++ lib/Travelynx/Command/work.pm | 105 +++++++++++++++++++++ lib/Travelynx/Controller/Account.pm | 19 ++-- lib/Travelynx/Controller/Traveling.pm | 103 +++++++++++++++++--- lib/Travelynx/Helper/DBRIS.pm | 138 +++++++++++++++++++++++++++ lib/Travelynx/Model/InTransit.pm | 132 +++++++++++++++++++++++++- lib/Travelynx/Model/Journeys.pm | 11 ++- lib/Travelynx/Model/Stations.pm | 82 ++++++++++++---- lib/Travelynx/Model/Users.pm | 9 +- public/static/js/travelynx-actions.js | 4 + templates/_departures_dbris.html.ep | 54 +++++++++++ templates/departures.html.ep | 18 ++-- templates/landingpage.html.ep | 1 + 14 files changed, 945 insertions(+), 54 deletions(-) create mode 100644 lib/Travelynx/Helper/DBRIS.pm create mode 100644 templates/_departures_dbris.html.ep (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 2b7fdf5..98ba4aa 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -21,6 +21,7 @@ use List::UtilsBy qw(uniq_by); use List::MoreUtils qw(first_index); use Travel::Status::DE::DBRIS::Formation; use Travelynx::Helper::DBDB; +use Travelynx::Helper::DBRIS; use Travelynx::Helper::HAFAS; use Travelynx::Helper::IRIS; use Travelynx::Helper::Sendmail; @@ -216,6 +217,19 @@ sub startup { } ); + $self->helper( + dbris => sub { + my ($self) = @_; + state $dbris = Travelynx::Helper::DBRIS->new( + log => $self->app->log, + cache => $self->app->cache_iris_rt, + root_url => $self->base_url_for('/')->to_abs, + user_agent => $self->ua, + version => $self->app->config->{version}, + ); + } + ); + $self->helper( hafas => sub { my ($self) = @_; @@ -452,6 +466,9 @@ sub startup { return Mojo::Promise->reject('You are already checked in'); } + if ( $opt{dbris} ) { + return $self->_checkin_dbris_p(%opt); + } if ( $opt{hafas} ) { return $self->_checkin_hafas_p(%opt); } @@ -530,6 +547,146 @@ sub startup { } ); + $self->helper( + '_checkin_dbris_p' => sub { + my ( $self, %opt ) = @_; + + my $station = $opt{station}; + my $train_id = $opt{train_id}; + my $ts = $opt{ts}; + my $uid = $opt{uid} // $self->current_user->{id}; + my $db = $opt{db} // $self->pg->db; + my $hafas; + + my $promise = Mojo::Promise->new; + + $self->dbris->get_journey_p( + trip_id => $train_id, + with_polyline => 1 + )->then( + sub { + my ($journey) = @_; + my $found; + for my $stop ( $journey->route ) { + if ( $stop->eva eq $station ) { + $found = $stop; + + # Lines may serve the same stop several times. + # Keep looking until the scheduled departure + # matches the one passed while checking in. + if ( $ts and $stop->sched_dep->epoch == $ts ) { + last; + } + } + } + if ( not $found ) { + $promise->reject( +"Did not find stop '$station' within journey '$train_id'" + ); + return; + } + for my $stop ( $journey->route ) { + $self->stations->add_or_update( + stop => $stop, + db => $db, + dbris => 'bahn.de', + ); + } + eval { + $self->in_transit->add( + uid => $uid, + db => $db, + journey => $journey, + stop => $found, + data => { trip_id => $train_id }, + backend_id => $self->stations->get_backend_id( + dbris => 'bahn.de' + ), + ); + }; + if ($@) { + $self->app->log->error( + "Checkin($uid): INSERT failed: $@"); + $promise->reject( 'INSERT failed: ' . $@ ); + return; + } + + my $polyline; + if ( $journey->polyline ) { + my @station_list; + my @coordinate_list; + for my $coord ( $journey->polyline ) { + if ( $coord->{stop} ) { + push( + @coordinate_list, + [ + $coord->{lon}, $coord->{lat}, + $coord->{stop}->eva + ] + ); + push( @station_list, $coord->{stop}->name ); + } + else { + push( @coordinate_list, + [ $coord->{lon}, $coord->{lat} ] ); + } + } + + # equal length → polyline only consists of straight + # lines between stops. that's not helpful. + if ( @station_list == @coordinate_list ) { + $self->log->debug( 'Ignoring polyline for ' + . $journey->train + . ' as it only consists of straight lines between stops.' + ); + } + else { + $polyline = { + from_eva => ( $journey->route )[0]->eva, + to_eva => ( $journey->route )[-1]->eva, + coords => \@coordinate_list, + }; + } + } + + if ($polyline) { + $self->in_transit->set_polyline( + uid => $uid, + db => $db, + polyline => $polyline, + ); + } + + # mustn't be called during a transaction + if ( not $opt{in_transaction} ) { + $self->run_hook( $uid, 'checkin' ); + $self->add_wagonorder( + uid => $uid, + train_id => $train_id, + is_departure => 1, + eva => $found->eva, + datetime => $found->sched_dep, + train_type => $journey->type, + train_no => $journey->number + ); + $self->add_stationinfo( $uid, 1, $train_id, + $found->eva ); + } + + $promise->resolve($journey); + } + )->catch( + sub { + my ($err) = @_; + $promise->reject($err); + return; + } + )->wait; + + return $promise; + } + ); + $self->helper( '_checkin_hafas_p' => sub { my ( $self, %opt ) = @_; @@ -799,8 +956,8 @@ sub startup { return $promise->resolve( 0, 'race condition' ); } - if ( $user->{is_hafas} ) { - return $self->_checkout_hafas_p(%opt); + if ( $user->{is_dbris} or $user->{is_hafas} ) { + return $self->_checkout_journey_p(%opt); } my $now = DateTime->now( time_zone => 'Europe/Berlin' ); @@ -1049,7 +1206,7 @@ sub startup { ); $self->helper( - '_checkout_hafas_p' => sub { + '_checkout_journey_p' => sub { my ( $self, %opt ) = @_; my $station = $opt{station}; @@ -1840,6 +1997,7 @@ sub startup { cancellation => $latest_cancellation, backend_id => $latest->{backend_id}, backend_name => $latest->{backend_name}, + is_dbris => $latest->{is_dbris}, is_iris => $latest->{is_iris}, is_hafas => $latest->{is_hafas}, journey_id => $latest->{journey_id}, @@ -1901,8 +2059,10 @@ sub startup { ) ? \1 : \0, comment => $status->{comment}, backend => { - id => $status->{backend_id}, - type => $status->{is_hafas} ? 'HAFAS' : 'IRIS-TTS', + id => $status->{backend_id}, + type => $status->{ds_dbris} ? 'DBRIS' + : $status->{is_hafas} ? 'HAFAS' + : 'IRIS-TTS', name => $status->{backend_name}, }, fromStation => { diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index 6ba80a3..f72a38c 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -2701,6 +2701,159 @@ qq{select distinct checkout_station_id from in_transit where backend_id = 0;} } ); }, + + # v59 -> v60 + # Add bahn.de / DBRIS backend + sub { + my ($db) = @_; + $db->insert( + 'backends', + { + iris => 0, + hafas => 0, + efa => 0, + ris => 1, + name => 'bahn.de', + }, + ); + $db->query( + qq{ + update schema_version set version = 60; + } + ); + }, + + # v60 -> v61 + # Rename "ris" / "is_ris" to "dbris" / "is_dbris", as it is DB-specific + sub { + my ($db) = @_; + $db->query( + qq{ + drop view in_transit_str; + drop view journeys_str; + drop view users_with_backend; + drop view follows_in_transit; + alter table backends rename column ris to dbris; + create view in_transit_str as select + user_id, + backend.iris as is_iris, backend.hafas as is_hafas, + backend.efa as is_efa, backend.dbris as is_dbris, + backend.name as backend_name, in_transit.backend_id as backend_id, + train_type, train_line, train_no, train_id, + extract(epoch from checkin_time) as checkin_ts, + extract(epoch from sched_departure) as sched_dep_ts, + extract(epoch from real_departure) as real_dep_ts, + checkin_station_id as dep_eva, + dep_station.ds100 as dep_ds100, + dep_station.name as dep_name, + dep_station.lat as dep_lat, + dep_station.lon as dep_lon, + extract(epoch from checkout_time) as checkout_ts, + extract(epoch from sched_arrival) as sched_arr_ts, + extract(epoch from real_arrival) as real_arr_ts, + checkout_station_id as arr_eva, + arr_station.ds100 as arr_ds100, + arr_station.name as arr_name, + arr_station.lat as arr_lat, + arr_station.lon as arr_lon, + polyline_id, + polylines.polyline as polyline, + visibility, + coalesce(visibility, users.public_level & 127) as effective_visibility, + cancelled, route, messages, user_data, + dep_platform, arr_platform, data + from in_transit + left join polylines on polylines.id = polyline_id + left join users on users.id = user_id + left join stations as dep_station on checkin_station_id = dep_station.eva and in_transit.backend_id = dep_station.source + left join stations as arr_station on checkout_station_id = arr_station.eva and in_transit.backend_id = arr_station.source + left join backends as backend on in_transit.backend_id = backend.id + ; + create view journeys_str as select + journeys.id as journey_id, user_id, + backend.iris as is_iris, backend.hafas as is_hafas, + backend.efa as is_efa, backend.dbris as is_dbris, + backend.name as backend_name, journeys.backend_id as backend_id, + train_type, train_line, train_no, train_id, + extract(epoch from checkin_time) as checkin_ts, + extract(epoch from sched_departure) as sched_dep_ts, + extract(epoch from real_departure) as real_dep_ts, + checkin_station_id as dep_eva, + dep_station.ds100 as dep_ds100, + dep_station.name as dep_name, + dep_station.lat as dep_lat, + dep_station.lon as dep_lon, + extract(epoch from checkout_time) as checkout_ts, + extract(epoch from sched_arrival) as sched_arr_ts, + extract(epoch from real_arrival) as real_arr_ts, + checkout_station_id as arr_eva, + arr_station.ds100 as arr_ds100, + arr_station.name as arr_name, + arr_station.lat as arr_lat, + arr_station.lon as arr_lon, + polylines.polyline as polyline, + visibility, + coalesce(visibility, users.public_level & 127) as effective_visibility, + cancelled, edited, route, messages, user_data, + dep_platform, arr_platform + from journeys + left join polylines on polylines.id = polyline_id + left join users on users.id = user_id + left join stations as dep_station on checkin_station_id = dep_station.eva and journeys.backend_id = dep_station.source + left join stations as arr_station on checkout_station_id = arr_station.eva and journeys.backend_id = arr_station.source + left join backends as backend on journeys.backend_id = backend.id + ; + create view users_with_backend as select + users.id as id, users.name as name, status, public_level, + email, password, registered_at, last_seen, + deletion_requested, deletion_notified, use_history, + accept_follows, notifications, profile, backend_id, iris, + hafas, efa, dbris, backend.name as backend_name + from users + left join backends as backend on users.backend_id = backend.id + ; + create view follows_in_transit as select + r1.subject_id as follower_id, user_id as followee_id, + users.name as followee_name, + train_type, train_line, train_no, train_id, + backend.iris as is_iris, backend.hafas as is_hafas, + backend.efa as is_efa, backend.dbris as is_dbris, + backend.name as backend_name, in_transit.backend_id as backend_id, + extract(epoch from checkin_time) as checkin_ts, + extract(epoch from sched_departure) as sched_dep_ts, + extract(epoch from real_departure) as real_dep_ts, + checkin_station_id as dep_eva, + dep_station.ds100 as dep_ds100, + dep_station.name as dep_name, + dep_station.lat as dep_lat, + dep_station.lon as dep_lon, + extract(epoch from checkout_time) as checkout_ts, + extract(epoch from sched_arrival) as sched_arr_ts, + extract(epoch from real_arrival) as real_arr_ts, + checkout_station_id as arr_eva, + arr_station.ds100 as arr_ds100, + arr_station.name as arr_name, + arr_station.lat as arr_lat, + arr_station.lon as arr_lon, + polyline_id, + polylines.polyline as polyline, + visibility, + coalesce(visibility, users.public_level & 127) as effective_visibility, + cancelled, route, messages, user_data, + dep_platform, arr_platform, data + from in_transit + left join polylines on polylines.id = polyline_id + left join users on users.id = user_id + left join relations as r1 on r1.predicate = 1 and r1.object_id = user_id + left join stations as dep_station on checkin_station_id = dep_station.eva and in_transit.backend_id = dep_station.source + left join stations as arr_station on checkout_station_id = arr_station.eva and in_transit.backend_id = arr_station.source + left join backends as backend on in_transit.backend_id = backend.id + order by checkin_time desc + ; + update schema_version set version = 61; + } + ); + }, ); sub sync_stations { diff --git a/lib/Travelynx/Command/work.pm b/lib/Travelynx/Command/work.pm index 5385e9b..55c2005 100644 --- a/lib/Travelynx/Command/work.pm +++ b/lib/Travelynx/Command/work.pm @@ -49,6 +49,111 @@ sub run { my $arr = $entry->{arr_eva}; my $train_id = $entry->{train_id}; + if ( $entry->{is_dbris} ) { + + eval { + + $self->app->dbris->get_journey_p( trip_id => $train_id )->then( + sub { + my ($journey) = @_; + + my $found_dep; + my $found_arr; + for my $stop ( $journey->route ) { + if ( $stop->eva == $dep ) { + $found_dep = $stop; + } + if ( $arr and $stop->eva == $arr ) { + $found_arr = $stop; + last; + } + } + if ( not $found_dep ) { + $self->app->log->debug( + "Did not find $dep within journey $train_id"); + return; + } + + if ( $found_dep->rt_dep ) { + $self->app->in_transit->update_departure_dbris( + uid => $uid, + journey => $journey, + stop => $found_dep, + dep_eva => $dep, + arr_eva => $arr, + train_id => $train_id, + ); + } + if ( $found_dep->sched_dep + and $found_dep->dep->epoch > $now->epoch ) + { + $self->app->add_wagonorder( + uid => $uid, + train_id => $train_id, + is_departure => 1, + eva => $dep, + datetime => $found_dep->sched_dep, + train_type => $journey->type, + train_no => $journey->number, + ); + $self->app->add_stationinfo( $uid, 1, + $train_id, $found_dep->eva ); + } + + if ( $found_arr and $found_arr->rt_arr ) { + $self->app->in_transit->update_arrival_dbris( + uid => $uid, + journey => $journey, + stop => $found_arr, + dep_eva => $dep, + arr_eva => $arr + ); + if ( $found_arr->arr->epoch - $now->epoch < 600 ) { + $self->app->add_wagonorder( + uid => $uid, + train_id => $train_id, + is_arrival => 1, + eva => $arr, + datetime => $found_arr->sched_dep, + train_type => $journey->type, + train_no => $journey->number, + ); + $self->app->add_stationinfo( $uid, 0, + $train_id, $found_dep->eva, + $found_arr->eva ); + } + } + } + )->catch( + sub { + my ($err) = @_; + $self->app->log->error( +"work($uid) @ DBRIS $entry->{backend_name}: journey: $err" + ); + } + )->wait; + + if ( $arr + and $entry->{real_arr_ts} + and $now->epoch - $entry->{real_arr_ts} > 600 ) + { + $self->app->checkout_p( + station => $arr, + force => 2, + dep_eva => $dep, + arr_eva => $arr, + uid => $uid + )->wait; + } + }; + if ($@) { + $errors += 1; + $self->app->log->error( + "work($uid) @ DBRIS $entry->{backend_name}: $@"); + } + next; + } + if ( $entry->{is_hafas} ) { eval { diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index 9cd0edb..43b0683 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -1066,9 +1066,17 @@ sub backend_form { if ( $backend->{iris} ) { $type = 'IRIS-TTS'; $backend->{name} = 'IRIS'; - $backend->{longname} = 'Deutsche Bahn (IRIS-TTS)'; + $backend->{longname} = 'Deutsche Bahn: IRIS-TTS'; $backend->{homepage} = 'https://www.bahn.de'; } + elsif ( $backend->{dbris} ) { + $type = 'DBRIS'; + $backend->{longname} = 'Deutsche Bahn: bahn.de'; + $backend->{homepage} = 'https://www.bahn.de'; + + # not ready for production yet + $type = undef; + } elsif ( $backend->{hafas} ) { # These backends lack a journey endpoint or are no longer @@ -1135,14 +1143,11 @@ sub backend_form { $backend->{type} = $type; } - # These backends lack a journey endpoint and are useless for travelynx - @backends - = grep { $_->{name} ne 'Resrobot' and $_->{name} ne 'TPG' } @backends; - my $iris = shift @backends; - @backends - = sort { $a->{name} cmp $b->{name} } grep { $_->{type} } @backends; + @backends = map { $_->[1] } + sort { $a->[0] cmp $b->[0] } + map { [ lc( $_->{name} ), $_ ] } grep { $_->{type} } @backends; unshift( @backends, $iris ); diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 1ca9d4a..a6e56b9 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -42,6 +42,13 @@ sub get_connecting_trains_p { my $promise = Mojo::Promise->new; + if ( $user->{backend_dbris} ) { + + # We do get a little bit of via information, so this might work in some + # cases. But not reliably. Probably best to leave it out entirely then. + return $promise->reject; + } + if ( $opt{eva} ) { if ( $use_history & 0x01 ) { $eva = $opt{eva}; @@ -106,6 +113,8 @@ sub get_connecting_trains_p { my $iris_promise = Mojo::Promise->new; my %via_count = map { $_->{name} => 0 } @destinations; + my $backend + = $self->stations->get_backend( backend_id => $opt{backend_id} ); if ( $opt{backend_id} == 0 ) { $self->iris->get_departures_p( station => $eva, @@ -260,9 +269,11 @@ sub get_connecting_trains_p { } )->wait; } - else { - my $hafas_service - = $self->stations->get_hafas_name( backend_id => $opt{backend_id} ); + elsif ( $backend->{dbris} ) { + ...; + } + elsif ( $backend->{hafas} ) { + my $hafas_service = $backend->{name}; $self->hafas->get_departures_p( service => $hafas_service, eva => $eva, @@ -524,10 +535,19 @@ sub geolocation { return; } - my $hafas_service - = $self->stations->get_hafas_name( backend_id => $backend_id ); + my ( $dbris_service, $hafas_service ); + my $backend = $self->stations->get_backend( backend_id => $backend_id ); + if ( $backend->{dbris} ) { + $dbris_service = $backend->{name}; + } + elsif ( $backend->{hafas} ) { + $hafas_service = $backend->{name}; + } - if ($hafas_service) { + if ($dbris_service) { + ...; + } + elsif ($hafas_service) { $self->render_later; my $agent = $self->ua; @@ -588,6 +608,7 @@ sub geolocation { lon => $_->[0][3], lat => $_->[0][4], distance => $_->[1], + dbris => 0, hafas => 0, } } Travel::Status::DE::IRIS::Stations::get_station_by_location( $lon, @@ -656,6 +677,7 @@ sub travel_action { $promise->then( sub { return $self->checkin_p( + dbris => $params->{dbris}, hafas => $params->{hafas}, station => $params->{station}, train_id => $params->{train}, @@ -687,7 +709,10 @@ sub travel_action { my ( $still_checked_in, undef ) = @_; if ( my $destination = $params->{dest} ) { my $station_link = '/s/' . $destination; - if ( $status->{is_hafas} ) { + if ( $status->{is_dbris} ) { + $station_link .= '?dbris=' . $status->{backend_name}; + } + elsif ( $status->{is_hafas} ) { $station_link .= '?hafas=' . $status->{backend_name}; } $self->render( @@ -723,7 +748,10 @@ sub travel_action { sub { my ( $still_checked_in, $error ) = @_; my $station_link = '/s/' . $params->{station}; - if ( $status->{is_hafas} ) { + if ( $status->{is_dbris} ) { + $station_link .= '?dbris=' . $status->{backend_name}; + } + elsif ( $status->{is_hafas} ) { $station_link .= '?hafas=' . $status->{backend_name}; } @@ -774,7 +802,14 @@ sub travel_action { else { my $redir = '/'; if ( $status->{checked_in} or $status->{cancelled} ) { - if ( $status->{is_hafas} ) { + if ( $status->{is_dbris} ) { + $redir + = '/s/' + . $status->{dep_eva} + . '?dbris=' + . $status->{backend_name}; + } + elsif ( $status->{is_hafas} ) { $redir = '/s/' . $status->{dep_eva} @@ -796,6 +831,7 @@ sub travel_action { elsif ( $params->{action} eq 'cancelled_from' ) { $self->render_later; $self->checkin_p( + dbris => $params->{dbris}, hafas => $params->{hafas}, station => $params->{station}, train_id => $params->{train}, @@ -925,10 +961,19 @@ sub station { $timestamp = DateTime->now( time_zone => 'Europe/Berlin' ); } + my $dbris_service = $self->param('dbris') + // ( $user->{backend_dbris} ? $user->{backend_name} : undef ); my $hafas_service = $self->param('hafas') // ( $user->{backend_hafas} ? $user->{backend_name} : undef ); my $promise; - if ($hafas_service) { + if ($dbris_service) { + $promise = $self->dbris->get_departures_p( + station => $station, + timestamp => $timestamp, + lookbehind => 30, + ); + } + elsif ($hafas_service) { $promise = $self->hafas->get_departures_p( service => $hafas_service, eva => $station, @@ -954,7 +999,22 @@ sub station { my $now_within_range = abs( $timestamp->epoch - $now ) < 1800 ? 1 : 0; - if ($hafas_service) { + if ($dbris_service) { + + @results = map { $_->[0] } + sort { $b->[1] <=> $a->[1] } + map { [ $_, $_->dep->epoch ] } $status->results; + + $status = { + station_eva => $station, + related_stations => [], + }; + + if ( $station =~ m{ [@] O = (? [^@]+ ) [@] }x ) { + $status->{station_name} = $+{name}; + } + } + elsif ($hafas_service) { @results = map { $_->[0] } sort { $b->[1] <=> $a->[1] } @@ -1039,6 +1099,7 @@ sub station { $self->render( 'departures', user => $user, + dbris => $dbris_service, hafas => $hafas_service, eva => $status->{station_eva}, datetime => $timestamp, @@ -1058,6 +1119,7 @@ sub station { $self->render( 'departures', user => $user, + dbris => $dbris_service, hafas => $hafas_service, eva => $status->{station_eva}, datetime => $timestamp, @@ -1076,6 +1138,7 @@ sub station { $self->render( 'departures', user => $user, + dbris => $dbris_service, hafas => $hafas_service, eva => $status->{station_eva}, datetime => $timestamp, @@ -1174,7 +1237,23 @@ sub redirect_to_station { my ($self) = @_; my $station = $self->param('station'); - $self->redirect_to("/s/${station}"); + if ( $self->param('backend_dbris') ) { + $self->render_later; + $self->dbris->get_station_id_p($station)->then( + sub { + my ($dbris_station) = @_; + $self->redirect_to( '/s/' . $dbris_station->{id} ); + } + )->catch( + sub { + my ($err) = @_; + $self->redirect_to('/'); + } + )->wait; + } + else { + $self->redirect_to("/s/${station}"); + } } sub cancelled { diff --git a/lib/Travelynx/Helper/DBRIS.pm b/lib/Travelynx/Helper/DBRIS.pm new file mode 100644 index 0000000..e647cc5 --- /dev/null +++ b/lib/Travelynx/Helper/DBRIS.pm @@ -0,0 +1,138 @@ +package Travelynx::Helper::DBRIS; + +# Copyright (C) 2025 Birte Kristina Friesel +# +# SPDX-License-Identifier: AGPL-3.0-or-later + +use strict; +use warnings; +use 5.020; +use utf8; + +use DateTime; +use Encode qw(decode); +use JSON; +use Mojo::Promise; +use Mojo::UserAgent; +use Travel::Status::DE::DBRIS; + +sub new { + my ( $class, %opt ) = @_; + + my $version = $opt{version}; + + $opt{header} + = { 'User-Agent' => +"travelynx/${version} on $opt{root_url} +https://finalrewind.org/projects/travelynx" + }; + + return bless( \%opt, $class ); +} + +sub get_station_id_p { + my ( $self, $station_name ) = @_; + my $promise = Mojo::Promise->new; + Travel::Status::DE::DBRIS->new_p( + locationSearch => $station_name, + cache => $self->{cache}, + lwp_options => { + timeout => 10, + agent => $self->{header}{'User-Agent'}, + }, + promise => 'Mojo::Promise', + user_agent => Mojo::UserAgent->new, + )->then( + sub { + my ($dbris) = @_; + my $found; + for my $result ( $dbris->results ) { + if ( defined $result->eva ) { + $promise->resolve($result); + return; + } + } + $promise->reject("Unable to find station '$station_name'"); + return; + } + )->catch( + sub { + my ($err) = @_; + $promise->reject("'$err' while trying to look up '$station_name'"); + return; + } + )->wait; + return $promise; +} + +sub get_departures_p { + my ( $self, %opt ) = @_; + + my $agent = $self->{user_agent}; + + if ( $opt{station} =~ m{ [@] L = (? \d+ ) [@] }x ) { + $opt{station} = { + eva => $+{eva}, + id => $opt{station}, + }; + } + + my $when = ( + $opt{timestamp} + ? $opt{timestamp}->clone + : DateTime->now( time_zone => 'Europe/Berlin' ) + )->subtract( minutes => $opt{lookbehind} ); + return Travel::Status::DE::DBRIS->new_p( + station => $opt{station}, + datetime => $when, + cache => $self->{cache}, + promise => 'Mojo::Promise', + user_agent => $agent->request_timeout(10), + ); +} + +sub get_journey_p { + my ( $self, %opt ) = @_; + + my $promise = Mojo::Promise->new; + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); + + my $agent = $self->{user_agent}; + if ( my $proxy = $self->{service_config}{dbris}{proxy} ) { + $agent = Mojo::UserAgent->new; + $agent->proxy->http($proxy); + $agent->proxy->https($proxy); + } + + Travel::Status::DE::DBRIS->new_p( + journey => $opt{trip_id}, + with_polyline => $opt{with_polyline}, + cache => $self->{realtime_cache}, + promise => 'Mojo::Promise', + user_agent => $agent->request_timeout(10), + )->then( + sub { + my ($dbris) = @_; + my $journey = $dbris->result; + + if ($journey) { + $self->{log}->debug("get_journey_p($opt{trip_id}): success"); + $promise->resolve($journey); + return; + } + $self->{log}->debug("get_journey_p($opt{trip_id}): no journey"); + $promise->reject('no journey'); + return; + } + )->catch( + sub { + my ($err) = @_; + $self->{log}->debug("get_journey_p($opt{trip_id}): error $err"); + $promise->reject($err); + return; + } + )->wait; + + return $promise; +} + +1; diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 43ecb90..2b9832c 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -104,6 +104,8 @@ sub add { my $json = JSON->new; if ($train) { + + # IRIS $db->insert( 'in_transit', { @@ -134,7 +136,9 @@ sub add { } ); } - elsif ( $journey and $stop ) { + elsif ( $journey and $stop and $journey->can('id') ) { + + # HAFAS my @route; my $product = $journey->product_at( $stop->loc->eva ) // $journey->product; @@ -188,6 +192,56 @@ sub add { } ); } + elsif ( $journey and $stop ) { + + # DBRIS + my @route; + for my $j_stop ( $journey->route ) { + push( + @route, + [ + $j_stop->name, + $j_stop->eva, + { + sched_arr => _epoch( $j_stop->sched_arr ), + sched_dep => _epoch( $j_stop->sched_dep ), + rt_arr => _epoch( $j_stop->rt_arr ), + rt_dep => _epoch( $j_stop->rt_dep ), + arr_delay => $j_stop->arr_delay, + dep_delay => $j_stop->dep_delay, + load => undef, + lat => $j_stop->lat, + lon => $j_stop->lon, + } + ] + ); + } + $db->insert( + 'in_transit', + { + user_id => $uid, + cancelled => $stop->{dep_cancelled} + ? 1 + : 0, + checkin_station_id => $stop->eva, + checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), + dep_platform => $stop->platform, + train_type => $journey->type, + train_no => $journey->number, + train_id => $data->{trip_id}, + sched_departure => $stop->sched_dep, + real_departure => $stop->rt_dep // $stop->sched_dep, + route => $json->encode( \@route ), + data => JSON->new->encode( + { + rt => $stop->{rt_dep} ? 1 : 0, + %{ $data // {} } + } + ), + backend_id => $backend_id, + } + ); + } else { die('neither train nor journey specified'); } @@ -731,6 +785,33 @@ sub update_departure_cancelled { return $rows; } +sub update_departure_dbris { + my ( $self, %opt ) = @_; + my $uid = $opt{uid}; + my $db = $opt{db} // $self->{pg}->db; + my $dep_eva = $opt{dep_eva}; + my $arr_eva = $opt{arr_eva}; + my $journey = $opt{journey}; + my $stop = $opt{stop}; + my $json = JSON->new; + + # selecting on user_id and train_no avoids a race condition if a user checks + # into a new train while we are fetching data for their previous journey. In + # this case, the new train would receive data from the previous journey. + $db->update( + 'in_transit', + { + real_departure => $stop->{rt_dep}, + }, + { + user_id => $uid, + train_id => $opt{train_id}, + checkin_station_id => $dep_eva, + checkout_station_id => $arr_eva, + } + ); +} + sub update_departure_hafas { my ( $self, %opt ) = @_; my $uid = $opt{uid}; @@ -800,6 +881,55 @@ sub update_arrival { return $rows; } +sub update_arrival_dbris { + my ( $self, %opt ) = @_; + my $uid = $opt{uid}; + my $db = $opt{db} // $self->{pg}->db; + my $dep_eva = $opt{dep_eva}; + my $arr_eva = $opt{arr_eva}; + my $journey = $opt{journey}; + my $stop = $opt{stop}; + my $json = JSON->new; + + my @route; + for my $j_stop ( $journey->route ) { + push( + @route, + [ + $j_stop->name, + $j_stop->eva, + { + sched_arr => _epoch( $j_stop->sched_arr ), + sched_dep => _epoch( $j_stop->sched_dep ), + rt_arr => _epoch( $j_stop->rt_arr ), + rt_dep => _epoch( $j_stop->rt_dep ), + arr_delay => $j_stop->arr_delay, + dep_delay => $j_stop->dep_delay, + lat => $j_stop->lat, + lon => $j_stop->lon, + } + ] + ); + } + + # selecting on user_id and train_no avoids a race condition if a user checks + # into a new train while we are fetching data for their previous journey. In + # this case, the new train would receive data from the previous journey. + $db->update( + 'in_transit', + { + real_arrival => $stop->{rt_arr}, + route => $json->encode( [@route] ), + }, + { + user_id => $uid, + train_id => $opt{train_id}, + checkin_station_id => $dep_eva, + checkout_station_id => $arr_eva, + } + ); +} + sub update_arrival_hafas { my ( $self, %opt ) = @_; my $uid = $opt{uid}; diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm index 905c426..f5bc9f1 100755 --- a/lib/Travelynx/Model/Journeys.pm +++ b/lib/Travelynx/Model/Journeys.pm @@ -549,7 +549,7 @@ sub get { my @select = ( - qw(journey_id is_iris is_hafas backend_name backend_id train_type train_line train_no checkin_ts sched_dep_ts real_dep_ts dep_eva dep_ds100 dep_name dep_lat dep_lon checkout_ts sched_arr_ts real_arr_ts arr_eva arr_ds100 arr_name arr_lat arr_lon cancelled edited route messages user_data visibility effective_visibility) + qw(journey_id is_dbris is_iris is_hafas backend_name backend_id train_type train_line train_no checkin_ts sched_dep_ts real_dep_ts dep_eva dep_ds100 dep_name dep_lat dep_lon checkout_ts sched_arr_ts real_arr_ts arr_eva arr_ds100 arr_name arr_lat arr_lon cancelled edited route messages user_data visibility effective_visibility) ); my %where = ( user_id => $uid, @@ -607,6 +607,7 @@ sub get { my $ref = { id => $entry->{journey_id}, + is_dbris => $entry->{is_dbris}, is_iris => $entry->{is_iris}, is_hafas => $entry->{is_hafas}, backend_name => $entry->{backend_name}, @@ -870,8 +871,8 @@ sub get_latest_checkout_stations { my $res = $db->select( 'journeys_str', [ - 'arr_name', 'arr_eva', 'train_id', 'backend_id', - 'backend_name', 'is_hafas' + 'arr_name', 'arr_eva', 'train_id', 'backend_id', + 'backend_name', 'is_dbris', 'is_hafas' ], { user_id => $uid, @@ -895,6 +896,7 @@ sub get_latest_checkout_stations { { name => $row->{arr_name}, eva => $row->{arr_eva}, + dbris => $row->{is_dbris} ? $row->{backend_name} : 0, hafas => $row->{is_hafas} ? $row->{backend_name} : 0, backend_id => $row->{backend_id}, } @@ -1883,7 +1885,8 @@ sub get_connection_targets { ); my @destinations = $res->hashes->grep( sub { shift->{count} >= $min_count } ) - ->map( sub { shift->{dest} } )->each; + ->map( sub { shift->{dest} } ) + ->each; @destinations = $self->{stations}->get_by_evas( backend_id => $opt{backend_id}, evas => [@destinations] diff --git a/lib/Travelynx/Model/Stations.pm b/lib/Travelynx/Model/Stations.pm index 76fd452..3d6549f 100644 --- a/lib/Travelynx/Model/Stations.pm +++ b/lib/Travelynx/Model/Stations.pm @@ -25,11 +25,25 @@ sub get_backend_id { if ( $opt{hafas} and $self->{backend_id}{hafas}{ $opt{hafas} } ) { return $self->{backend_id}{hafas}{ $opt{hafas} }; } + if ( $opt{dbris} and $self->{backend_id}{dbris}{ $opt{dbris} } ) { + return $self->{backend_id}{dbris}{ $opt{dbris} }; + } my $db = $opt{db} // $self->{pg}->db; my $backend_id = 0; - if ( $opt{hafas} ) { + if ( $opt{dbris} ) { + $backend_id = $db->select( + 'backends', + ['id'], + { + dbris => 1, + name => $opt{dbris} + } + )->hash->{id}; + $self->{backend_id}{dbris}{ $opt{dbris} } = $backend_id; + } + elsif ( $opt{hafas} ) { $backend_id = $db->select( 'backends', ['id'], @@ -44,31 +58,25 @@ sub get_backend_id { return $backend_id; } -sub get_hafas_name { +sub get_backend { my ( $self, %opt ) = @_; - if ( exists $self->{hafas_name}{ $opt{backend_id} } ) { - return $self->{hafas_name}{ $opt{backend_id} }; + if ( $self->{backend_cache}{ $opt{backend_id} } ) { + return $self->{backend_cache}{ $opt{backend_id} }; } - my $db = $opt{db} // $self->{pg}->db; - my $hafas_name; + my $db = $opt{db} // $self->{pg}->db; my $ret = $db->select( 'backends', - ['name'], + '*', { - hafas => 1, - id => $opt{backend_id}, + id => $opt{backend_id}, } )->hash; - if ($ret) { - $hafas_name = $ret->{name}; - } - - $self->{hafas_name}{ $opt{backend_id} } = $hafas_name; + $self->{backend_cache}{ $opt{backend_id} } = $ret; - return $hafas_name; + return $ret; } sub get_backends { @@ -76,7 +84,8 @@ sub get_backends { $opt{db} //= $self->{pg}->db; - my $res = $opt{db}->select( 'backends', [ 'id', 'name', 'iris', 'hafas' ] ); + my $res = $opt{db} + ->select( 'backends', [ 'id', 'name', 'iris', 'hafas', 'dbris' ] ); my @ret; while ( my $row = $res->hash ) { @@ -86,6 +95,7 @@ sub get_backends { id => $row->{id}, name => $row->{name}, iris => $row->{iris}, + dbris => $row->{dbris}, hafas => $row->{hafas}, } ); @@ -97,11 +107,49 @@ sub get_backends { sub add_or_update { my ( $self, %opt ) = @_; my $stop = $opt{stop}; - my $loc = $stop->loc; $opt{db} //= $self->{pg}->db; $opt{backend_id} //= $self->get_backend_id(%opt); + if ( $opt{dbris} ) { + if ( + my $s = $self->get_by_eva( + $stop->eva, + db => $opt{db}, + backend_id => $opt{backend_id} + ) + ) + { + $opt{db}->update( + 'stations', + { + name => $stop->name, + lat => $stop->lat, + lon => $stop->lon, + archived => 0 + }, + { + eva => $stop->eva, + source => $opt{backend_id} + } + ); + return; + } + $opt{db}->insert( + 'stations', + { + eva => $stop->eva, + name => $stop->name, + lat => $stop->lat, + lon => $stop->lon, + source => $opt{backend_id}, + archived => 0 + } + ); + return; + } + + my $loc = $stop->loc; if ( my $s = $self->get_by_eva( $loc->eva, diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm index 7d3777b..e3d6f7a 100644 --- a/lib/Travelynx/Model/Users.pm +++ b/lib/Travelynx/Model/Users.pm @@ -209,7 +209,11 @@ sub set_backend { my ( $self, %opt ) = @_; $opt{db} //= $self->{pg}->db; - $opt{db}->update('users', {backend_id => $opt{backend_id}}, {id => $opt{uid}}); + $opt{db}->update( + 'users', + { backend_id => $opt{backend_id} }, + { id => $opt{uid} } + ); } sub set_privacy { @@ -414,7 +418,7 @@ sub get { . 'extract(epoch from registered_at) as registered_at_ts, ' . 'extract(epoch from last_seen) as last_seen_ts, ' . 'extract(epoch from deletion_requested) as deletion_requested_ts, ' - . 'backend_id, backend_name, hafas', + . 'backend_id, backend_name, hafas, dbris', { id => $uid } )->hash; if ($user) { @@ -453,6 +457,7 @@ sub get { : undef, backend_id => $user->{backend_id}, backend_name => $user->{backend_name}, + backend_dbris => $user->{dbris}, backend_hafas => $user->{hafas}, }; } diff --git a/public/static/js/travelynx-actions.js b/public/static/js/travelynx-actions.js index d4ddf45..0d2de5a 100644 --- a/public/static/js/travelynx-actions.js +++ b/public/static/js/travelynx-actions.js @@ -194,6 +194,7 @@ function tvly_reg_handlers() { var link = $(this); var req = { action: 'checkin', + dbris: link.data('dbris'), hafas: link.data('hafas'), station: link.data('station'), train: link.data('train'), @@ -206,6 +207,7 @@ function tvly_reg_handlers() { var link = $(this); var req = { action: 'checkout', + dbris: link.data('dbris'), hafas: link.data('hafas'), station: link.data('station'), force: link.data('force'), @@ -237,6 +239,7 @@ function tvly_reg_handlers() { var link = $(this); var req = { action: 'cancelled_from', + dbris: link.data('dbris'), hafas: link.data('hafas'), station: link.data('station'), ts: link.data('ts'), @@ -248,6 +251,7 @@ function tvly_reg_handlers() { var link = $(this); var req = { action: 'cancelled_to', + dbris: link.data('dbris'), hafas: link.data('hafas'), station: link.data('station'), force: true, diff --git a/templates/_departures_dbris.html.ep b/templates/_departures_dbris.html.ep new file mode 100644 index 0000000..14426e8 --- /dev/null +++ b/templates/_departures_dbris.html.ep @@ -0,0 +1,54 @@ + diff --git a/templates/departures.html.ep b/templates/departures.html.ep index a86a7b5..6e2a98a 100644 --- a/templates/departures.html.ep +++ b/templates/departures.html.ep @@ -9,7 +9,10 @@
% my $self_link = url_for('sstation', station => $station // param('station')); - % if (param('hafas')) { + % if (param('dbris')) { + <%= param('dbris') %> + % } + % elsif (param('hafas')) { <%= param('hafas') %> % } % else { @@ -93,8 +96,8 @@
- % if ($hafas) { - früher + % if ($dbris or $hafas) { + früher % }
@@ -103,8 +106,8 @@ % }
- % if ($hafas) { - später + % if ($dbris or $hafas) { + später % }
@@ -139,7 +142,10 @@ % }

% if (not $user_status->{checked_in} or ($can_check_out and $user_status->{arr_eva} and $user_status->{arrival_countdown} <= 0)) { - % if ($hafas) { + % if ($dbris) { + %= include '_departures_dbris', results => $results, dbris => $dbris; + % } + % elsif ($hafas) { %= include '_departures_hafas', results => $results, hafas => $hafas; % } % else { diff --git a/templates/landingpage.html.ep b/templates/landingpage.html.ep index 8b6eb3f..856fdef 100644 --- a/templates/landingpage.html.ep +++ b/templates/landingpage.html.ep @@ -60,6 +60,7 @@ + %= hidden_field backend_dbris => $user->{backend_dbris}
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', autocomplete => 'off', required => undef -- cgit v1.2.3 From a3c628d1642d35bb1b46b3e372dfb1fcca4b8e15 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sun, 23 Mar 2025 18:47:21 +0100 Subject: DBRIS: Add load/occupancy data --- lib/Travelynx.pm | 8 ++++++++ lib/Travelynx/Model/InTransit.pm | 17 ++++++++++++----- 2 files changed, 20 insertions(+), 5 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 98ba4aa..cdfc84c 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -419,6 +419,14 @@ sub startup { my $first = $load->{FIRST} // 0; my $second = $load->{SECOND} // 0; + # DBRIS + if ( $first == 99 ) { + $first = 4; + } + if ( $second == 99 ) { + $second = 4; + } + my @symbols = ( qw(help_outline person_outline people priority_high not_interested) diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 2b9832c..9f02aba 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -209,9 +209,12 @@ sub add { rt_dep => _epoch( $j_stop->rt_dep ), arr_delay => $j_stop->arr_delay, dep_delay => $j_stop->dep_delay, - load => undef, - lat => $j_stop->lat, - lon => $j_stop->lon, + load => { + FIRST => $j_stop->occupancy_first, + SECOND => $j_stop->occupancy_second + }, + lat => $j_stop->lat, + lon => $j_stop->lon, } ] ); @@ -905,8 +908,12 @@ sub update_arrival_dbris { rt_dep => _epoch( $j_stop->rt_dep ), arr_delay => $j_stop->arr_delay, dep_delay => $j_stop->dep_delay, - lat => $j_stop->lat, - lon => $j_stop->lon, + load => { + FIRST => $j_stop->occupancy_first, + SECOND => $j_stop->occupancy_second + }, + lat => $j_stop->lat, + lon => $j_stop->lon, } ] ); -- cgit v1.2.3 From 67d1cf52674102da4edb87a874f033a3124fc5c6 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 26 Mar 2025 18:47:50 +0100 Subject: InTransit->add: update HAFAS/DBRIS switch --- lib/Travelynx/Model/InTransit.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 9f02aba..5d9bc58 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -136,7 +136,7 @@ sub add { } ); } - elsif ( $journey and $stop and $journey->can('id') ) { + elsif ( $journey and $stop and $journey->can('product') ) { # HAFAS my @route; -- cgit v1.2.3 From 84d6e23c494eea178cfe55c215ecec2b7c547195 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Fri, 28 Mar 2025 20:21:07 +0100 Subject: dbris: journey stops: store cancellation state --- lib/Travelynx/Model/InTransit.pm | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 5d9bc58..34c78f7 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -203,13 +203,14 @@ sub add { $j_stop->name, $j_stop->eva, { - sched_arr => _epoch( $j_stop->sched_arr ), - sched_dep => _epoch( $j_stop->sched_dep ), - rt_arr => _epoch( $j_stop->rt_arr ), - rt_dep => _epoch( $j_stop->rt_dep ), - arr_delay => $j_stop->arr_delay, - dep_delay => $j_stop->dep_delay, - load => { + sched_arr => _epoch( $j_stop->sched_arr ), + sched_dep => _epoch( $j_stop->sched_dep ), + rt_arr => _epoch( $j_stop->rt_arr ), + rt_dep => _epoch( $j_stop->rt_dep ), + isCancelled => $j_stop->is_cancelled, + arr_delay => $j_stop->arr_delay, + dep_delay => $j_stop->dep_delay, + load => { FIRST => $j_stop->occupancy_first, SECOND => $j_stop->occupancy_second }, @@ -902,13 +903,14 @@ sub update_arrival_dbris { $j_stop->name, $j_stop->eva, { - sched_arr => _epoch( $j_stop->sched_arr ), - sched_dep => _epoch( $j_stop->sched_dep ), - rt_arr => _epoch( $j_stop->rt_arr ), - rt_dep => _epoch( $j_stop->rt_dep ), - arr_delay => $j_stop->arr_delay, - dep_delay => $j_stop->dep_delay, - load => { + sched_arr => _epoch( $j_stop->sched_arr ), + sched_dep => _epoch( $j_stop->sched_dep ), + rt_arr => _epoch( $j_stop->rt_arr ), + rt_dep => _epoch( $j_stop->rt_dep ), + isCancelled => $j_stop->is_cancelled, + arr_delay => $j_stop->arr_delay, + dep_delay => $j_stop->dep_delay, + load => { FIRST => $j_stop->occupancy_first, SECOND => $j_stop->occupancy_second }, -- cgit v1.2.3 From 0252ff2697d80c10c2932893995f0e77f85a38ec Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sat, 29 Mar 2025 16:42:24 +0100 Subject: pass train suffix (which is sometimes line ID) on to InTransit->add Closes #217 --- lib/Travelynx.pm | 12 +++++++----- lib/Travelynx/Controller/Traveling.pm | 11 ++++++----- lib/Travelynx/Model/InTransit.pm | 10 ++++++++++ public/static/js/travelynx-actions.js | 1 + templates/_departures_dbris.html.ep | 1 + 5 files changed, 25 insertions(+), 10 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index ac64390..50f07de 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -559,11 +559,12 @@ sub startup { '_checkin_dbris_p' => sub { my ( $self, %opt ) = @_; - my $station = $opt{station}; - my $train_id = $opt{train_id}; - my $ts = $opt{ts}; - my $uid = $opt{uid} // $self->current_user->{id}; - my $db = $opt{db} // $self->pg->db; + my $station = $opt{station}; + my $train_id = $opt{train_id}; + my $train_suffix = $opt{train_suffix}; + my $ts = $opt{ts}; + my $uid = $opt{uid} // $self->current_user->{id}; + my $db = $opt{db} // $self->pg->db; my $hafas; my $promise = Mojo::Promise->new; @@ -610,6 +611,7 @@ sub startup { backend_id => $self->stations->get_backend_id( dbris => 'bahn.de' ), + train_suffix => $train_suffix, ); }; if ($@) { diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 6a91f0e..cba28cf 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -717,11 +717,12 @@ sub travel_action { $promise->then( sub { return $self->checkin_p( - dbris => $params->{dbris}, - hafas => $params->{hafas}, - station => $params->{station}, - train_id => $params->{train}, - ts => $params->{ts}, + dbris => $params->{dbris}, + hafas => $params->{hafas}, + station => $params->{station}, + train_id => $params->{train}, + train_suffix => $params->{suffix}, + ts => $params->{ts}, ); } )->then( diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 34c78f7..bf117bf 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -95,6 +95,7 @@ sub add { my $db = $opt{db} // $self->{pg}->db; my $backend_id = $opt{backend_id}; my $train = $opt{train}; + my $train_suffix = $opt{train_suffix}; my $journey = $opt{journey}; my $stop = $opt{stop}; my $checkin_station_id = $opt{departure_eva}; @@ -194,6 +195,14 @@ sub add { } elsif ( $journey and $stop ) { + my $line; + if ( $train_suffix + and $journey->number + and $train_suffix ne $journey->number ) + { + $line = $train_suffix; + } + # DBRIS my @route; for my $j_stop ( $journey->route ) { @@ -231,6 +240,7 @@ sub add { checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), dep_platform => $stop->platform, train_type => $journey->type, + train_line => $line, train_no => $journey->number, train_id => $data->{trip_id}, sched_departure => $stop->sched_dep, diff --git a/public/static/js/travelynx-actions.js b/public/static/js/travelynx-actions.js index 0d2de5a..3e02283 100644 --- a/public/static/js/travelynx-actions.js +++ b/public/static/js/travelynx-actions.js @@ -198,6 +198,7 @@ function tvly_reg_handlers() { hafas: link.data('hafas'), station: link.data('station'), train: link.data('train'), + suffix: link.data('suffix'), dest: link.data('dest'), ts: link.data('ts'), }; diff --git a/templates/_departures_dbris.html.ep b/templates/_departures_dbris.html.ep index 14426e8..06f2ee9 100644 --- a/templates/_departures_dbris.html.ep +++ b/templates/_departures_dbris.html.ep @@ -21,6 +21,7 @@ data-dbris="<%= $dbris %>" data-station="<%= $result->stop_eva %>" data-train="<%= $result->id %>" + data-suffix="<%= $result->maybe_line_no %>" data-ts="<%= ($result->sched_dep // $result->dep)->epoch %>" > -- cgit v1.2.3 From 31d7ba0f7b9098505bcf91246933a50e6c2e89d5 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 2 Apr 2025 17:35:10 +0200 Subject: dbris: handle checkins into cancelled departures --- lib/Travelynx/Model/InTransit.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index bf117bf..65ab9dd 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -233,7 +233,7 @@ sub add { 'in_transit', { user_id => $uid, - cancelled => $stop->{dep_cancelled} + cancelled => $stop->is_cancelled ? 1 : 0, checkin_station_id => $stop->eva, -- cgit v1.2.3 From deb6683f637bbfe27f7c7dfce27233def228aadb Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 2 Apr 2025 19:05:39 +0200 Subject: DBRIS trains may come without a type Closes #221 --- lib/Travelynx/Model/InTransit.pm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 65ab9dd..1028d59 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -239,7 +239,7 @@ sub add { checkin_station_id => $stop->eva, checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), dep_platform => $stop->platform, - train_type => $journey->type, + train_type => $journey->type // q{}, train_line => $line, train_no => $journey->number, train_id => $data->{trip_id}, -- cgit v1.2.3 From e605ed389de964e6fc0f494f732b607a5ff6bdc6 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 16 Apr 2025 20:27:58 +0200 Subject: Show DBRIS messages (disruptions and infos) in checked_in view --- lib/Travelynx/Model/InTransit.pm | 38 ++++++++++++++++++++++++++++++++++++++ templates/_checked_in.html.ep | 2 +- 2 files changed, 39 insertions(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 1028d59..e8495b8 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -809,6 +809,24 @@ sub update_departure_dbris { my $stop = $opt{stop}; my $json = JSON->new; + my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) + ->expand->hash; + my $data = $res_h ? $res_h->{data} : {}; + + $data->{him_msg} = []; + for my $msg ( $journey->messages ) { + if ( not $msg->{ueberschrift} ) { + push( + @{ $data->{him_msg} }, + { + header => q{}, + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); + } + } + # selecting on user_id and train_no avoids a race condition if a user checks # into a new train while we are fetching data for their previous journey. In # this case, the new train would receive data from the previous journey. @@ -816,6 +834,7 @@ sub update_departure_dbris { 'in_transit', { real_departure => $stop->{rt_dep}, + data => $json->encode($data), }, { user_id => $uid, @@ -905,6 +924,24 @@ sub update_arrival_dbris { my $stop = $opt{stop}; my $json = JSON->new; + my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) + ->expand->hash; + my $data = $res_h ? $res_h->{data} : {}; + + $data->{him_msg} = []; + for my $msg ( $journey->messages ) { + if ( not $msg->{ueberschrift} ) { + push( + @{ $data->{him_msg} }, + { + header => q{}, + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); + } + } + my @route; for my $j_stop ( $journey->route ) { push( @@ -939,6 +976,7 @@ sub update_arrival_dbris { { real_arrival => $stop->{rt_arr}, route => $json->encode( [@route] ), + data => $json->encode($data), }, { user_id => $uid, diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep index b625388..f9a199b 100644 --- a/templates/_checked_in.html.ep +++ b/templates/_checked_in.html.ep @@ -335,7 +335,7 @@

    % for my $message (@{$journey->{extra_data}{him_msg} // []}) { -
  • info <%= $message->{header} %> <%= $message->{lead} %>
  • +
  • <%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %> <%= $message->{header} %> <%= $message->{lead} %>
  • % }

-- cgit v1.2.3 From 51b0080bcf939139554bbb730445fb2572d0f26e Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 16 Apr 2025 20:38:31 +0200 Subject: dbris: store him messages upon checkin as well --- lib/Travelynx/Model/InTransit.pm | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index e8495b8..0215cb8 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -195,6 +195,7 @@ sub add { } elsif ( $journey and $stop ) { + # DBRIS my $line; if ( $train_suffix and $journey->number @@ -203,7 +204,6 @@ sub add { $line = $train_suffix; } - # DBRIS my @route; for my $j_stop ( $journey->route ) { push( @@ -229,6 +229,19 @@ sub add { ] ); } + my @messages; + for my $msg ( $journey->messages ) { + if ( not $msg->{ueberschrift} ) { + push( + @{ $data->{him_msg} }, + { + header => q{}, + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); + } + } $db->insert( 'in_transit', { -- cgit v1.2.3 From 6e50e9026c457a2f694c1a2dd7072948d5c9ec3e Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sat, 19 Apr 2025 17:06:30 +0200 Subject: Use train_no / line_no accessors provided by DBRIS 0.10 --- cpanfile | 2 +- lib/Travelynx.pm | 2 +- lib/Travelynx/Model/InTransit.pm | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/cpanfile b/cpanfile index ccf9451..85ef852 100644 --- a/cpanfile +++ b/cpanfile @@ -17,7 +17,7 @@ requires 'Mojolicious::Plugin::OAuth2'; requires 'Mojo::Pg'; requires 'Text::CSV'; requires 'Text::Markdown'; -requires 'Travel::Status::DE::DBRIS', '>= 0.08'; +requires 'Travel::Status::DE::DBRIS', '>= 0.10'; requires 'Travel::Status::DE::HAFAS', '>= 6.20'; requires 'Travel::Status::DE::IRIS'; requires 'UUID::Tiny'; diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index c1992b6..0eee5dc 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -678,7 +678,7 @@ sub startup { eva => $found->eva, datetime => $found->sched_dep, train_type => $journey->type, - train_no => $journey->number + train_no => $journey->train_no, ); $self->add_stationinfo( $uid, 1, $train_id, $found->eva ); diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 0215cb8..9f9dd9b 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -197,10 +197,10 @@ sub add { # DBRIS my $line; - if ( $train_suffix - and $journey->number - and $train_suffix ne $journey->number ) - { + if ( $journey->line_no ne $journey->train_no ) { + $line = $journey->line_no; + } + elsif ( $train_suffix ne $journey->train_no ) { $line = $train_suffix; } @@ -254,7 +254,7 @@ sub add { dep_platform => $stop->platform, train_type => $journey->type // q{}, train_line => $line, - train_no => $journey->number, + train_no => $journey->train_no, train_id => $data->{trip_id}, sched_departure => $stop->sched_dep, real_departure => $stop->rt_dep // $stop->sched_dep, -- cgit v1.2.3 From c90ae4cf579870a4bd2c6b3e9b2048b0acfced19 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Mon, 21 Apr 2025 19:35:30 +0200 Subject: InTransit->add: dbris: ensure that train_no is always set --- lib/Travelynx/Model/InTransit.pm | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 9f9dd9b..0795179 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -196,11 +196,13 @@ sub add { elsif ( $journey and $stop ) { # DBRIS + my $number = $journey->train_no // $journey->number // $train_suffix; + my $line; - if ( $journey->line_no ne $journey->train_no ) { + if ( defined $journey->line_no and $journey->line_no ne $number ) { $line = $journey->line_no; } - elsif ( $train_suffix ne $journey->train_no ) { + elsif ( defined $train_suffix and $train_suffix ne $number ) { $line = $train_suffix; } @@ -254,7 +256,7 @@ sub add { dep_platform => $stop->platform, train_type => $journey->type // q{}, train_line => $line, - train_no => $journey->train_no, + train_no => $number, train_id => $data->{trip_id}, sched_departure => $stop->sched_dep, real_departure => $stop->rt_dep // $stop->sched_dep, -- cgit v1.2.3 From ebb6b76a32d1bb4651ca757a5e5aa8ef7756e8c5 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sat, 17 May 2025 11:25:35 +0200 Subject: dbris: persist backend messages and show them in journey view --- lib/Travelynx/Model/InTransit.pm | 53 +++++++++++++++++++++++++++++++--------- templates/journey.html.ep | 10 ++++++++ 2 files changed, 51 insertions(+), 12 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 0795179..08b7fbb 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -101,6 +101,7 @@ sub add { my $checkin_station_id = $opt{departure_eva}; my $route = $opt{route}; my $data = $opt{data}; + my $persistent_data; my $json = JSON->new; @@ -242,6 +243,13 @@ sub add { lead => $msg->{text} } ); + push( + @{ $persistent_data->{him_msg} }, + { + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); } } $db->insert( @@ -267,6 +275,7 @@ sub add { %{ $data // {} } } ), + user_data => JSON->new->encode($persistent_data), backend_id => $backend_id, } ); @@ -824,21 +833,30 @@ sub update_departure_dbris { my $stop = $opt{stop}; my $json = JSON->new; - my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) - ->expand->hash; - my $data = $res_h ? $res_h->{data} : {}; + my $res_h = $db->select( 'in_transit', [ 'data', 'user_data' ], + { user_id => $uid } )->expand->hash; + my $ephemeral_data = $res_h ? $res_h->{data} : {}; + my $persistent_data = $res_h ? $res_h->{user_data} : {}; - $data->{him_msg} = []; + $ephemeral_data->{him_msg} = []; + $persistent_data->{him_msg} = []; for my $msg ( $journey->messages ) { if ( not $msg->{ueberschrift} ) { push( - @{ $data->{him_msg} }, + @{ $ephemeral_data->{him_msg} }, { header => q{}, prio => $msg->{prioritaet}, lead => $msg->{text} } ); + push( + @{ $persistent_data->{him_msg} }, + { + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); } } @@ -849,7 +867,8 @@ sub update_departure_dbris { 'in_transit', { real_departure => $stop->{rt_dep}, - data => $json->encode($data), + data => $json->encode($ephemeral_data), + user_data => $json->encode($persistent_data), }, { user_id => $uid, @@ -939,21 +958,30 @@ sub update_arrival_dbris { my $stop = $opt{stop}; my $json = JSON->new; - my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) - ->expand->hash; - my $data = $res_h ? $res_h->{data} : {}; + my $res_h = $db->select( 'in_transit', [ 'data', 'user_data' ], + { user_id => $uid } )->expand->hash; + my $ephemeral_data = $res_h ? $res_h->{data} : {}; + my $persistent_data = $res_h ? $res_h->{user_data} : {}; - $data->{him_msg} = []; + $ephemeral_data->{him_msg} = []; + $persistent_data->{him_msg} = []; for my $msg ( $journey->messages ) { if ( not $msg->{ueberschrift} ) { push( - @{ $data->{him_msg} }, + @{ $ephemeral_data->{him_msg} }, { header => q{}, prio => $msg->{prioritaet}, lead => $msg->{text} } ); + push( + @{ $persistent_data->{him_msg} }, + { + prio => $msg->{prioritaet}, + lead => $msg->{text} + } + ); } } @@ -991,7 +1019,8 @@ sub update_arrival_dbris { { real_arrival => $stop->{rt_arr}, route => $json->encode( [@route] ), - data => $json->encode($data), + data => $json->encode($ephemeral_data), + user_data => $json->encode($persistent_data), }, { user_id => $uid, diff --git a/templates/journey.html.ep b/templates/journey.html.ep index c052190..e97c729 100644 --- a/templates/journey.html.ep +++ b/templates/journey.html.ep @@ -177,6 +177,16 @@ % } + % if ($journey->{user_data}{him_msg} and @{$journey->{user_data}{him_msg}}) { + + Meldungen + + % for my $message (@{$journey->{user_data}{him_msg} // []}) { + <%= ($message->{prio} and $message->{prio} eq 'HOCH') ? 'warning' : 'info' %> <%= $message->{header} %> <%= $message->{lead} %>
+ % } + + + % } % if ($journey->{user_data} and $journey->{user_data}{comment}) { Kommentar -- cgit v1.2.3 From 3ab1089570912e70c52233a1151b15ceeb1a7e61 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Thu, 22 May 2025 18:04:49 +0200 Subject: InTransit: store arr_platform for DBRIS checkins --- lib/Travelynx/Model/InTransit.pm | 2 ++ 1 file changed, 2 insertions(+) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 08b7fbb..2733631 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -997,6 +997,7 @@ sub update_arrival_dbris { sched_dep => _epoch( $j_stop->sched_dep ), rt_arr => _epoch( $j_stop->rt_arr ), rt_dep => _epoch( $j_stop->rt_dep ), + platform => $j_stop->platform, isCancelled => $j_stop->is_cancelled, arr_delay => $j_stop->arr_delay, dep_delay => $j_stop->dep_delay, @@ -1018,6 +1019,7 @@ sub update_arrival_dbris { 'in_transit', { real_arrival => $stop->{rt_arr}, + arr_platform => $stop->{platform}, route => $json->encode( [@route] ), data => $json->encode($ephemeral_data), user_data => $json->encode($persistent_data), -- cgit v1.2.3 From 69a27390fe57dff2da44cc489539cecba213b8a5 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sun, 25 May 2025 10:36:36 +0200 Subject: status card: show carriage formation --- lib/Travelynx/Model/InTransit.pm | 1 + templates/_public_status_card.html.ep | 5 +++++ 2 files changed, 6 insertions(+) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 2733631..1ec7137 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -356,6 +356,7 @@ sub postprocess { $ret->{route_after} = \@route_after; $ret->{extra_data} = $ret->{data}; $ret->{comment} = $ret->{user_data}{comment}; + $ret->{wagongroups} = $ret->{user_data}{wagongroups}; $ret->{platform_type} = 'Gleis'; if ( $ret->{train_type} =~ m{ ast | bus | ruf }ix ) { diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep index 11ef85b..bf5656b 100644 --- a/templates/_public_status_card.html.ep +++ b/templates/_public_status_card.html.ep @@ -197,6 +197,11 @@

% } + % if ( $journey->{wagongroups} and @{$journey->{wagongroups}} and not stash('from_timeline')) { +
+ %= include '_wagons', wagongroups => $journey->{wagongroups}; +
+ % }
% if (not stash('from_timeline')) {
-- cgit v1.2.3 From 08d77279a5af8a600f2938794aa2019b59f6e3e5 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Sun, 25 May 2025 11:01:30 +0200 Subject: status card: show complete route and expected load --- lib/Travelynx/Model/InTransit.pm | 2 +- templates/_public_status_card.html.ep | 55 +++++++++++++++++++++++++++++++++-- 2 files changed, 53 insertions(+), 4 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 1ec7137..2bd3dad 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -392,7 +392,7 @@ sub postprocess { = $dep_info->{rt_arr}->epoch - $epoch; } - for my $station (@route_after) { + for my $station (@route) { if ( @{$station} > 1 ) { # Note: $station->[2]{sched_arr} may already have been diff --git a/templates/_public_status_card.html.ep b/templates/_public_status_card.html.ep index 280d4dd..e8b6fbb 100644 --- a/templates/_public_status_card.html.ep +++ b/templates/_public_status_card.html.ep @@ -197,13 +197,62 @@
% } - % if ( $journey->{wagongroups} and @{$journey->{wagongroups}} and not stash('from_timeline')) { -
+ % if ( @{$journey->{wagongroups} // []} and not stash('from_timeline')) { +
+ Wagen:
%= include '_wagons', wagongroups => $journey->{wagongroups};
% } + % if (not stash('from_timeline')) { +
+ Zuglauf:
+ % my $before = 1; + % my $within = 0; + % my $at_startstop = 0; + % for my $station (@{$journey->{route}}) { + % if (($station->[1] and $station->[1] == $journey->{dep_eva}) or $station->[0] eq $journey->{dep_name}) { + % $within = 1; $at_startstop = 1; + % } + % elsif (($station->[1] and $station->[1] == $journey->{arr_eva}) or $station->[0] eq $journey->{arr_name}) { + % $within = 0; $at_startstop = 1; + % } + % else { + % $at_startstop = 0; + % } + + % if ($before and $station->[2]{sched_dep}) { + %= $station->[2]{sched_dep}->strftime('%H:%M') + % } + % elsif (not $before and $station->[2]{sched_arr}) { + %= $station->[2]{sched_arr}->strftime('%H:%M') + % } + + % if ($at_startstop or $within) { + %= $station->[0] + % } + % else { + <%= $station->[0] %> + % } + + %= include '_show_load_icons', station => $station + + + % if ($before and $station->[2]{rt_dep} and $station->[2]{dep_delay}) { + %= sprintf('%+d', $station->[2]{dep_delay} / 60) + % } + % elsif (not $before and $station->[2]{rt_arr} and $station->[2]{arr_delay}) { + %= sprintf('%+d', $station->[2]{arr_delay} / 60) + % } + + % if (($station->[1] and $station->[1] == $journey->{dep_eva}) or $station->[0] eq $journey->{dep_name}) { + % $before = 0; + % } +
+ % } +
+ % }
- % if (not stash('from_timeline')) { + % if (0 and not stash('from_timeline')) {
% if ($journey->{traewelling_url}) { timeline Träwelling -- cgit v1.2.3 From 19d3f4afa84d7c237c8673f6555467ea5f7ae899 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Wed, 28 May 2025 19:04:21 +0200 Subject: InTransit->add: Use a global $now object --- lib/Travelynx/Model/InTransit.pm | 61 ++++++++++++++++++++-------------------- 1 file changed, 31 insertions(+), 30 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 2bd3dad..b2be995 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -104,6 +104,7 @@ sub add { my $persistent_data; my $json = JSON->new; + my $now = DateTime->now( time_zone => 'Europe/Berlin' ); if ($train) { @@ -115,16 +116,16 @@ sub add { cancelled => $train->departure_is_cancelled ? 1 : 0, checkin_station_id => $checkin_station_id, - checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), - dep_platform => $train->platform, - train_type => $train->type, - train_line => $train->line_no, - train_no => $train->train_no, - train_id => $train->train_id, - sched_departure => $train->sched_departure, - real_departure => $train->departure, - route => $json->encode($route), - messages => $json->encode( + checkin_time => $now, + dep_platform => $train->platform, + train_type => $train->type, + train_line => $train->line_no, + train_no => $train->train_no, + train_id => $train->train_id, + sched_departure => $train->sched_departure, + real_departure => $train->departure, + route => $json->encode($route), + messages => $json->encode( [ map { [ $_->[0]->epoch, $_->[1] ] } $train->messages ] ), data => JSON->new->encode( @@ -175,16 +176,16 @@ sub add { ? 1 : 0, checkin_station_id => $stop->loc->eva, - checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), - dep_platform => $stop->{platform}, - train_type => $product->type // q{}, - train_line => $product->line_no, - train_no => $product->number // q{}, - train_id => $journey->id, - sched_departure => $stop->{sched_dep}, - real_departure => $stop->{rt_dep} // $stop->{sched_dep}, - route => $json->encode( \@route ), - data => JSON->new->encode( + checkin_time => $now, + dep_platform => $stop->{platform}, + train_type => $product->type // q{}, + train_line => $product->line_no, + train_no => $product->number // q{}, + train_id => $journey->id, + sched_departure => $stop->{sched_dep}, + real_departure => $stop->{rt_dep} // $stop->{sched_dep}, + route => $json->encode( \@route ), + data => JSON->new->encode( { rt => $stop->{rt_dep} ? 1 : 0, %{ $data // {} } @@ -260,16 +261,16 @@ sub add { ? 1 : 0, checkin_station_id => $stop->eva, - checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ), - dep_platform => $stop->platform, - train_type => $journey->type // q{}, - train_line => $line, - train_no => $number, - train_id => $data->{trip_id}, - sched_departure => $stop->sched_dep, - real_departure => $stop->rt_dep // $stop->sched_dep, - route => $json->encode( \@route ), - data => JSON->new->encode( + checkin_time => $now, + dep_platform => $stop->platform, + train_type => $journey->type // q{}, + train_line => $line, + train_no => $number, + train_id => $data->{trip_id}, + sched_departure => $stop->sched_dep, + real_departure => $stop->rt_dep // $stop->sched_dep, + route => $json->encode( \@route ), + data => JSON->new->encode( { rt => $stop->{rt_dep} ? 1 : 0, %{ $data // {} } -- cgit v1.2.3 From 646a88c72667c8b68432a7316a9c5980f53107b6 Mon Sep 17 00:00:00 2001 From: Birte Kristina Friesel Date: Fri, 30 May 2025 10:38:12 +0200 Subject: Show train route in checked-in view and profile / status card --- lib/Travelynx.pm | 38 +++++++++++++++++++++-------------- lib/Travelynx/Controller/Profile.pm | 28 +++++++++++++++++++++++++- lib/Travelynx/Controller/Traveling.pm | 15 ++++++++++++++ lib/Travelynx/Model/InTransit.pm | 32 +++++++++++++++-------------- templates/_checked_in.html.ep | 12 +++++++++-- templates/_map.html.ep | 20 +++++++++--------- templates/_public_status_card.html.ep | 5 +++++ templates/profile.html.ep | 2 +- templates/user_status.html.ep | 2 +- 9 files changed, 110 insertions(+), 44 deletions(-) (limited to 'lib/Travelynx/Model/InTransit.pm') diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 521ea2c..f9723c1 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -1890,6 +1890,7 @@ sub startup { uid => $uid, db => $db, with_data => 1, + with_polyline => 1, with_timestamps => 1, with_visibility => 1, postprocess => 1, @@ -2320,12 +2321,12 @@ sub startup { my @stations = uniq_by { $_->{name} } map { { - name => $_->{to_name}, - latlon => $_->{to_latlon} + name => $_->{to_name} // $_->{arr_name}, + latlon => $_->{to_latlon} // $_->{arr_latlon}, }, { - name => $_->{from_name}, - latlon => $_->{from_latlon} + name => $_->{from_name} // $_->{dep_name}, + latlon => $_->{from_latlon} // $_->{dep_latlon} } } @journeys; @@ -2350,8 +2351,8 @@ sub startup { for my $journey (@polyline_journeys) { my @polyline = @{ $journey->{polyline} }; - my $from_eva = $journey->{from_eva}; - my $to_eva = $journey->{to_eva}; + my $from_eva = $journey->{from_eva} // $journey->{dep_eva}; + my $to_eva = $journey->{to_eva} // $journey->{arr_eva}; my $from_index = first_index { $_->[2] and $_->[2] == $from_eva } @polyline; @@ -2387,7 +2388,7 @@ sub startup { or $to_index == -1 ) { # Fall back to route - delete $journey->{polyline}; + push( @beeline_journeys, $journey ); next; } @@ -2422,13 +2423,19 @@ sub startup { my @route = @{ $journey->{route} }; my $from_index = first_index { - ( $_->[1] and $_->[1] == $journey->{from_eva} ) - or $_->[0] eq $journey->{from_name} + ( $_->[1] + and $_->[1] + == ( $journey->{from_eva} // $journey->{dep_eva} ) ) + or $_->[0] eq + ( $journey->{from_name} // $journey->{dep_name} ) } @route; my $to_index = first_index { - ( $_->[1] and $_->[1] == $journey->{to_eva} ) - or $_->[0] eq $journey->{to_name} + ( $_->[1] + and $_->[1] + == ( $journey->{to_eva} // $journey->{arr_eva} ) ) + or $_->[0] eq + ( $journey->{to_name} // $journey->{arr_name} ) } @route; @@ -2436,15 +2443,15 @@ sub startup { my $rename = $self->app->renamed_station; $from_index = first_index { ( $rename->{ $_->[0] } // $_->[0] ) eq - $journey->{from_name} + ( $journey->{from_name} // $journey->{dep_name} ) } @route; } if ( $to_index == -1 ) { my $rename = $self->app->renamed_station; $to_index = first_index { - ( $rename->{ $_->[0] } // $_->[0] ) eq - $journey->{to_name} + ( $rename->{ $_->[0] } // $_->[0] ) eq + ( $journey->{to_name} // $journey->{arr_name} ) } @route; } @@ -2467,7 +2474,8 @@ sub startup { # and entered manually (-> beeline also shown on map, typically # significantly differs from detailed route) -- unless the user # sets include_manual, of course. - if ( $journey->{edited} & 0x0010 + if ( $journey->{edited} + and $journey->{edited} & 0x0010 and @route <= 2 and not $include_manual ) { diff --git a/lib/Travelynx/Controller/Profile.pm b/lib/Travelynx/Controller/Profile.pm index c35642d..db30d36 100755 --- a/lib/Travelynx/Controller/Profile.pm +++ b/lib/Travelynx/Controller/Profile.pm @@ -111,6 +111,13 @@ sub profile { $status->{arr_name} = undef; } + my $map_data = {}; + if ( $status->{checked_in} ) { + $map_data = $self->journeys_to_map_data( + journeys => [$status], + ); + } + my @journeys; if ( @@ -190,6 +197,8 @@ sub profile { : 0, journey => $status, journeys => [@journeys], + with_map => 1, + %{$map_data}, } ); } @@ -494,6 +503,13 @@ sub user_status { $og_data{description} = $tw_data{description} = q{}; } + my $map_data = {}; + if ( $status->{checked_in} ) { + $map_data = $self->journeys_to_map_data( + journeys => [$status], + ); + } + $self->respond_to( json => { json => { @@ -516,7 +532,9 @@ sub user_status { journey => $status, twitter => \%tw_data, opengraph => \%og_data, - version => $self->app->config->{version} // 'UNKNOWN', + with_map => 1, + %{$map_data}, + version => $self->app->config->{version} // 'UNKNOWN', }, ); } @@ -555,6 +573,7 @@ sub status_card { my $status = $self->get_user_status( $user->{id} ); my $visibility; + my $map_data = {}; if ( $status->{checked_in} or $status->{arr_name} ) { my $visibility = $status->{effective_visibility}; if ( @@ -579,12 +598,19 @@ sub status_card { $status->{arr_name} = undef; } + if ( $status->{checked_in} ) { + $map_data = $self->journeys_to_map_data( + journeys => [$status], + ); + } + $self->render( '_public_status_card', name => $name, privacy => $user, journey => $status, from_profile => $self->param('profile') ? 1 : 0, + %{$map_data}, ); } diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 4653043..0d89fb9 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -353,6 +353,9 @@ sub homepage { $self->stash( timeline => [@timeline] ); my @recent_targets; if ( $status->{checked_in} ) { + my $map_data = $self->journeys_to_map_data( + journeys => [$status], + ); my $journey_visibility = $self->compute_effective_visibility( $user->{default_visibility_str}, @@ -371,6 +374,8 @@ sub homepage { journey_visibility => $journey_visibility, connections_iris => $connections_iris, connections_hafas => $connections_hafas, + with_map => 1, + %{$map_data}, ); $self->users->mark_seen( uid => $uid ); } @@ -381,6 +386,8 @@ sub homepage { user => $user, user_status => $status, journey_visibility => $journey_visibility, + with_map => 1, + %{$map_data}, ); $self->users->mark_seen( uid => $uid ); } @@ -393,6 +400,8 @@ sub homepage { user => $user, user_status => $status, journey_visibility => $journey_visibility, + with_map => 1, + %{$map_data}, ); $self->users->mark_seen( uid => $uid ); return; @@ -431,6 +440,9 @@ sub status_card { $self->stash( timeline => [@timeline] ); if ( $status->{checked_in} ) { + my $map_data = $self->journeys_to_map_data( + journeys => [$status], + ); my $journey_visibility = $self->compute_effective_visibility( $self->current_user->{default_visibility_str}, @@ -448,6 +460,7 @@ sub status_card { journey_visibility => $journey_visibility, connections_iris => $connections_iris, connections_hafas => $connections_hafas, + %{$map_data}, ); } )->catch( @@ -456,6 +469,7 @@ sub status_card { '_checked_in', journey => $status, journey_visibility => $journey_visibility, + %{$map_data}, ); } )->wait; @@ -465,6 +479,7 @@ sub status_card { '_checked_in', journey => $status, journey_visibility => $journey_visibility, + %{$map_data}, ); } elsif ( $status->{cancellation} ) { diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index b2be995..a90cd08 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -12,11 +12,12 @@ use DateTime; use JSON; my %visibility_itoa = ( - 100 => 'public', - 80 => 'travelynx', - 60 => 'followers', - 30 => 'unlisted', - 10 => 'private', + 100 => 'public', + 80 => 'travelynx', + 60 => 'followers', + 30 => 'unlisted', + 10 => 'private', + default => 'default', ); my %visibility_atoi = ( @@ -360,16 +361,14 @@ sub postprocess { $ret->{wagongroups} = $ret->{user_data}{wagongroups}; $ret->{platform_type} = 'Gleis'; - if ( $ret->{train_type} =~ m{ ast | bus | ruf }ix ) { + if ( $ret->{train_type} and $ret->{train_type} =~ m{ ast | bus | ruf }ix ) { $ret->{platform_type} = 'Steig'; } $ret->{visibility_str} - = $ret->{visibility} - ? $visibility_itoa{ $ret->{visibility} } - : 'default'; + = $visibility_itoa{ $ret->{visibility} // 'default' }; $ret->{effective_visibility_str} - = $visibility_itoa{ $ret->{effective_visibility} }; + = $visibility_itoa{ $ret->{effective_visibility} // 'default' }; my @parsed_messages; for my $message ( @{ $ret->{messages} // [] } ) { @@ -461,7 +460,7 @@ sub get { my $table = 'in_transit'; - if ( $opt{with_timestamps} ) { + if ( $opt{with_timestamps} or $opt{with_polyline} ) { $table = 'in_transit_str'; } @@ -475,13 +474,16 @@ sub get { $ret = $res->hash; } + if ( $opt{with_polyline} and $ret ) { + $ret->{dep_latlon} = [ $ret->{dep_lat}, $ret->{dep_lon} ]; + $ret->{arr_latlon} = [ $ret->{arr_lat}, $ret->{arr_lon} ]; + } + if ( $opt{with_visibility} and $ret ) { $ret->{visibility_str} - = $ret->{visibility} - ? $visibility_itoa{ $ret->{visibility} } - : 'default'; + = $visibility_itoa{ $ret->{visibility} // 'default' }; $ret->{effective_visibility_str} - = $visibility_itoa{ $ret->{effective_visibility} }; + = $visibility_itoa{ $ret->{effective_visibility} // 'default' }; } if ( $opt{postprocess} and $ret ) { diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep index 3fd226b..155f75d 100644 --- a/templates/_checked_in.html.ep +++ b/templates/_checked_in.html.ep @@ -324,6 +324,7 @@ % if ($journey->{arr_name}) {
+ Meldungen % if (@{$journey->{extra_data}{him_msg} // []}) {

@@ -371,8 +372,15 @@ % }

- % } - % if ($journey->{arr_name}) { +
+
+ + Karte +
+
+ %= include '_map', with_map_header => 0, station_coordinates => stash('station_coordinates'), polyline_groups => stash('polyline_groups') +
+
diff --git a/templates/_map.html.ep b/templates/_map.html.ep index daa16f0..223bd68 100644 --- a/templates/_map.html.ep +++ b/templates/_map.html.ep @@ -1,16 +1,18 @@ -
-
-
+% if (stash('with_map_header') // 1) { +
+
+
+
-
-
-
- Ein-/Ausstiegsstation
- Streckenverlauf oder Luftlinie +
+
+ Ein-/Ausstiegsstation
+ Streckenverlauf oder Luftlinie +
-
+% }