diff options
Diffstat (limited to 'lib/Travelynx')
-rw-r--r-- | lib/Travelynx/Command/database.pm | 220 | ||||
-rw-r--r-- | lib/Travelynx/Command/dumpstops.pm | 2 | ||||
-rw-r--r-- | lib/Travelynx/Command/traewelling.pm | 34 | ||||
-rw-r--r-- | lib/Travelynx/Command/work.pm | 38 | ||||
-rw-r--r-- | lib/Travelynx/Controller/Account.pm | 23 | ||||
-rwxr-xr-x | lib/Travelynx/Controller/Profile.pm | 100 | ||||
-rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 25 | ||||
-rw-r--r-- | lib/Travelynx/Helper/DBDB.pm | 29 | ||||
-rw-r--r-- | lib/Travelynx/Helper/HAFAS.pm | 22 | ||||
-rw-r--r-- | lib/Travelynx/Model/InTransit.pm | 128 | ||||
-rwxr-xr-x | lib/Travelynx/Model/Journeys.pm | 8 | ||||
-rw-r--r-- | lib/Travelynx/Model/Users.pm | 36 |
12 files changed, 505 insertions, 160 deletions
diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index d13b2a7..fb5ee80 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -1946,6 +1946,226 @@ my @migrations = ( } ); }, + + # v51 -> v52 + # Explicitly encode backend type; preparation for multiple hAFAS backends + sub { + my ($db) = @_; + $db->query( + qq{ + create table backends ( + id smallserial not null primary key, + iris bool not null, + hafas bool not null, + efa bool not null, + ris bool not null, + name varchar(32) not null, + unique (iris, hafas, efa, ris, name) + ); + insert into backends (id, iris, hafas, efa, ris, name) values (0, true, false, false, false, ''); + insert into backends (id, iris, hafas, efa, ris, name) values (1, false, true, false, false, 'DB'); + alter sequence backends_id_seq restart with 2; + alter table in_transit add column backend_id smallint references backends (id); + alter table journeys add column backend_id smallint references backends (id); + update in_transit set backend_id = 0 where train_id not like '%|%'; + update journeys set backend_id = 0 where train_id not like '%|%'; + update in_transit set backend_id = 1 where train_id like '%|%'; + update journeys set backend_id = 1 where train_id like '%|%'; + update journeys set backend_id = 1 where train_id = 'manual'; + alter table in_transit alter column backend_id set not null; + alter table journeys alter column backend_id set not null; + + drop view in_transit_str; + drop view journeys_str; + 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.ris as is_ris, + backend.name as backend_name, + 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 + left join stations as arr_station on checkout_station_id = arr_station.eva + left join backends as backend on 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.ris as is_ris, + backend.name as backend_name, + 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 + left join stations as arr_station on checkout_station_id = arr_station.eva + left join backends as backend on backend_id = backend.id + ; + update schema_version set version = 52; + } + ); + }, + sub { + my ($db) = @_; + $db->query( + qq{ + drop view in_transit_str; + drop view journeys_str; + drop view follows_in_transit; + alter table in_transit alter column train_id type varchar(384); + alter table journeys alter column train_id type varchar(384); + 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.ris as is_ris, + backend.name as backend_name, + 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 + left join stations as arr_station on checkout_station_id = arr_station.eva + left join backends as backend on 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.ris as is_ris, + backend.name as backend_name, + 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 + left join stations as arr_station on checkout_station_id = arr_station.eva + left join backends as backend on 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, + 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 + left join stations as arr_station on checkout_station_id = arr_station.eva + order by checkin_time desc + ; + update schema_version set version = 53; + } + ); + }, ); sub sync_stations { diff --git a/lib/Travelynx/Command/dumpstops.pm b/lib/Travelynx/Command/dumpstops.pm index e6740ec..c8ecd7a 100644 --- a/lib/Travelynx/Command/dumpstops.pm +++ b/lib/Travelynx/Command/dumpstops.pm @@ -8,7 +8,7 @@ use Mojo::Base 'Mojolicious::Command'; use List::Util qw(); use Text::CSV; -has description => 'Export HAFAS/IRIS stops to CSV'; +has description => 'Export known stops to CSV'; has usage => sub { shift->extract_usage }; diff --git a/lib/Travelynx/Command/traewelling.pm b/lib/Travelynx/Command/traewelling.pm index 4c47e84..ed40371 100644 --- a/lib/Travelynx/Command/traewelling.pm +++ b/lib/Travelynx/Command/traewelling.pm @@ -20,6 +20,12 @@ sub pull_sync { my $request_count = 0; for my $account_data ( $self->app->traewelling->get_pull_accounts ) { + if ( -e 'maintenance' ) { + $self->app->log->debug( + 'treawelling: "maintenance" file found, aborting'); + return; + } + my $in_transit = $self->app->in_transit->get( uid => $account_data->{user_id}, ); @@ -30,6 +36,13 @@ sub pull_sync { next; } + if ( not defined $account_data->{data}{user_name} ) { + $self->app->log->debug( +"travelynx user $account_data->{user_id} has a Traewellig connection, but no username" + ); + next; + } + # $account_data->{user_id} is the travelynx uid # $account_data->{user_name} is the Träwelling username $request_count += 1; @@ -39,7 +52,7 @@ sub pull_sync { # In 'work', the event loop is not running, # so there's no need to multiply by $request_count at the moment - Mojo::Promise->timer(1)->then( + Mojo::Promise->timer(1.5)->then( sub { return $self->app->traewelling_api->get_status_p( username => $account_data->{data}{user_name}, @@ -77,6 +90,13 @@ sub push_sync { my %push_result; for my $candidate ( $self->app->traewelling->get_pushable_accounts ) { + + if ( -e 'maintenance' ) { + $self->app->log->debug( + 'treawelling: "maintenance" file found, aborting'); + return; + } + $self->app->log->debug( "Pushing to Traewelling for UID $candidate->{uid}"); my $trip_id = $candidate->{journey_data}{trip_id}; @@ -121,6 +141,12 @@ sub run { my $push_result; my $pull_result; + if ( -e 'maintenance' ) { + $self->app->log->debug( + 'treawelling: "maintenance" file found, aborting'); + return; + } + if ( not $direction or $direction eq 'push' ) { $push_result = $self->push_sync; } @@ -133,6 +159,12 @@ sub run { my $trwl_pull_finished_at = DateTime->now( time_zone => 'Europe/Berlin' ); + if ( -e 'maintenance' ) { + $self->app->log->debug( + 'treawelling: "maintenance" file found, aborting'); + return; + } + my $trwl_push_duration = $trwl_push_finished_at->epoch - $started_at->epoch; my $trwl_pull_duration = $trwl_pull_finished_at->epoch - $trwl_push_finished_at->epoch; diff --git a/lib/Travelynx/Command/work.pm b/lib/Travelynx/Command/work.pm index 10b1b69..65fddc3 100644 --- a/lib/Travelynx/Command/work.pm +++ b/lib/Travelynx/Command/work.pm @@ -21,6 +21,11 @@ sub run { my $checkin_deadline = $now->clone->subtract( hours => 48 ); my $json = JSON->new; + if ( -e 'maintenance' ) { + $self->app->log->debug('work: "maintenance" file found, aborting'); + return; + } + my $num_incomplete = $self->app->in_transit->delete_incomplete_checkins( earlier_than => $checkin_deadline ); @@ -32,6 +37,11 @@ sub run { for my $entry ( $self->app->in_transit->get_all_active ) { + if ( -e 'maintenance' ) { + $self->app->log->debug('work: "maintenance" file found, aborting'); + return; + } + my $uid = $entry->{user_id}; my $dep = $entry->{dep_eva}; my $arr = $entry->{arr_eva}; @@ -60,7 +70,7 @@ sub run { return; } - if ( $found_dep->{rt_dep} ) { + if ( $found_dep->rt_dep ) { $self->app->in_transit->update_departure_hafas( uid => $uid, journey => $journey, @@ -68,9 +78,17 @@ sub run { dep_eva => $dep, arr_eva => $arr ); + if ( $journey->class <= 16 + and $found_dep->rt_dep->epoch > $now->epoch ) + { + $self->app->add_wagonorder( $uid, 1, $train_id, + $found_dep->sched_dep, $journey->number ); + $self->app->add_stationinfo( $uid, 1, $journey->id, + $found_dep->loc->eva ); + } } - if ( $found_arr and $found_arr->{rt_arr} ) { + if ( $found_arr and $found_arr->rt_arr ) { $self->app->in_transit->update_arrival_hafas( uid => $uid, journey => $journey, @@ -78,6 +96,14 @@ sub run { dep_eva => $dep, arr_eva => $arr ); + if ( $journey->class <= 16 + and $found_arr->rt_arr->epoch - $now->epoch < 600 ) + { + $self->app->add_wagonorder( $uid, 0, $train_id, + $found_dep->sched_dep, $journey->number ); + $self->app->add_stationinfo( $uid, 0, $journey->id, + $found_dep->loc->eva, $found_arr->loc->eva ); + } } } )->catch( @@ -171,6 +197,10 @@ sub run { } else { $self->app->add_route_timestamps( $uid, $train, 1 ); + $self->app->add_wagonorder( $uid, 1, $train->train_id, + $train->sched_departure, $train->train_no ); + $self->app->add_stationinfo( $uid, 1, $train->train_id, + $dep, $arr ); } } }; @@ -243,6 +273,10 @@ sub run { and $now->epoch > $entry->{real_arr_ts} ) ? 1 : 0 ); + $self->app->add_wagonorder( $uid, 0, $train->train_id, + $train->sched_departure, $train->train_no ); + $self->app->add_stationinfo( $uid, 0, $train->train_id, + $dep, $arr ); } } elsif ( $entry->{real_arr_ts} ) { diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index f1dc43e..5c101b1 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -831,29 +831,6 @@ sub insight { } -sub services { - my ($self) = @_; - my $user = $self->current_user; - - if ( $self->param('action') and $self->param('action') eq 'save' ) { - my $sb = $self->param('stationboard'); - my $value = 0; - if ( $sb =~ m{ ^ \d+ $ }x and $sb >= 0 and $sb <= 4 ) { - $value = int($sb); - } - $self->users->use_external_services( - uid => $user->{id}, - set => $value - ); - $self->flash( success => 'external' ); - $self->redirect_to('account'); - } - - $self->param( stationboard => - $self->users->use_external_services( uid => $user->{id} ) ); - $self->render('use_external_links'); -} - sub webhook { my ($self) = @_; diff --git a/lib/Travelynx/Controller/Profile.pm b/lib/Travelynx/Controller/Profile.pm index a063c10..a5f394f 100755 --- a/lib/Travelynx/Controller/Profile.pm +++ b/lib/Travelynx/Controller/Profile.pm @@ -152,34 +152,45 @@ sub profile { @journeys = $self->journeys->get(%opt); } - $self->render( - 'profile', - title => "travelynx: $name", - name => $name, - uid => $user->{id}, - privacy => $user, - bio => $profile->{bio}{html}, - metadata => $profile->{metadata}, - is_self => $is_self, - following => ( $relation and $relation eq 'follows' ) ? 1 : 0, - follow_requested => ( $relation and $relation eq 'requests_follow' ) - ? 1 - : 0, - can_follow => ( $my_user and $user->{accept_follows} and not $relation ) - ? 1 - : 0, - can_request_follow => - ( $my_user and $user->{accept_follow_requests} and not $relation ) - ? 1 - : 0, - follows_me => ( $inverse_relation and $inverse_relation eq 'follows' ) - ? 1 - : 0, - follow_reqs_me => - ( $inverse_relation and $inverse_relation eq 'requests_follow' ) ? 1 - : 0, - journey => $status, - journeys => [@journeys], + $self->respond_to( + json => { + json => { + name => $name, + uid => $user->{id}, + bio => $profile->{bio}{html}, + metadata => $profile->{metadata}, + } + }, + any => { + template => 'profile', + title => "travelynx: $name", + name => $name, + uid => $user->{id}, + privacy => $user, + bio => $profile->{bio}{html}, + metadata => $profile->{metadata}, + is_self => $is_self, + following => ( $relation and $relation eq 'follows' ) ? 1 : 0, + follow_requested => ( $relation and $relation eq 'requests_follow' ) + ? 1 + : 0, + can_follow => + ( $my_user and $user->{accept_follows} and not $relation ) ? 1 + : 0, + can_request_follow => ( + $my_user and $user->{accept_follow_requests} and not $relation + ) ? 1 + : 0, + follows_me => + ( $inverse_relation and $inverse_relation eq 'follows' ) ? 1 + : 0, + follow_reqs_me => ( + $inverse_relation and $inverse_relation eq 'requests_follow' + ) ? 1 + : 0, + journey => $status, + journeys => [@journeys], + } ); } @@ -334,7 +345,16 @@ sub user_status { my $user = $self->users->get_privacy_by( name => $name ); if ( not $user ) { - $self->render( 'not_found', status => 404 ); + $self->respond_to( + json => { + json => { error => 'not found' }, + status => 404, + }, + any => { + template => 'not_found', + status => 404 + } + ); return; } @@ -389,11 +409,29 @@ sub user_status { "/p/${name}/j/$journey->{id}?token=${token}-${ts}"); } else { - $self->render( 'not_found', status => 404 ); + $self->respond_to( + json => { + json => { error => 'not found' }, + status => 404, + }, + any => { + template => 'not_found', + status => 404 + } + ); } return; } - $self->render( 'not_found', status => 404 ); + $self->respond_to( + json => { + json => { error => 'not found' }, + status => 404, + }, + any => { + template => 'not_found', + status => 404 + } + ); return; } diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 89385e1..f9bc2d5 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -604,7 +604,7 @@ sub geolocation { name => $_->name, eva => $_->eva, distance => $_->distance_m / 1000, - hafas => 1 + hafas => 'DB' } } $hafas->results; if ( @hafas > 10 ) { @@ -714,7 +714,7 @@ sub travel_action { if ( my $destination = $params->{dest} ) { my $station_link = '/s/' . $destination; if ( $status->{train_id} =~ m{[|]} ) { - $station_link .= '?hafas=1'; + $station_link .= '?hafas=DB'; } $self->render( json => { @@ -750,7 +750,7 @@ sub travel_action { my ( $still_checked_in, $error ) = @_; my $station_link = '/s/' . $params->{station}; if ( $status->{train_id} =~ m{[|]} ) { - $station_link .= '?hafas=1'; + $station_link .= '?hafas=DB'; } if ($error) { @@ -801,7 +801,7 @@ sub travel_action { my $redir = '/'; if ( $status->{checked_in} or $status->{cancelled} ) { if ( $status->{train_id} =~ m{[|]} ) { - $redir = '/s/' . $status->{dep_eva} . '?hafas=1'; + $redir = '/s/' . $status->{dep_eva} . '?hafas=DB'; } else { $redir = '/s/' . $status->{dep_ds100}; @@ -999,7 +999,7 @@ sub station { } else { - $api_link = '/s/' . $status->{station_eva} . '?hafas=1'; + $api_link = '/s/' . $status->{station_eva} . '?hafas=DB'; # You can't check into a train which terminates here @results = grep { $_->departure } @{ $status->{results} }; @@ -1128,7 +1128,7 @@ sub station { my @suggestions = $hafas2->results; if ( @suggestions == 1 ) { $self->redirect_to( - '/s/' . $suggestions[0]->eva . '?hafas=1' ); + '/s/' . $suggestions[0]->eva . '?hafas=DB' ); } else { $self->render( @@ -1171,14 +1171,14 @@ sub redirect_to_station { if ( my $s = $self->app->stations->search($station) ) { if ( $s->{source} == 1 ) { - $self->redirect_to("/s/${station}?hafas=1"); + $self->redirect_to("/s/${station}?hafas=DB"); } else { $self->redirect_to("/s/${station}"); } } else { - $self->redirect_to("/s/${station}?hafas=1"); + $self->redirect_to("/s/${station}?hafas=DB"); } } @@ -1510,7 +1510,7 @@ sub year_in_review { if ( not @journeys ) { $self->render( 'not_found', - message => 'Keine Zugfahrten im angefragten Jahr gefunden.', + message => 'Keine Fahrten im angefragten Jahr gefunden.', status => 404 ); return; @@ -1583,7 +1583,7 @@ sub yearly_history { $self->render( 'not_found', status => 404, - message => 'Keine Zugfahrten im angefragten Jahr gefunden.' + message => 'Keine Fahrten im angefragten Jahr gefunden.' ); return; } @@ -1660,7 +1660,7 @@ sub monthly_history { if ( not @journeys ) { $self->render( 'not_found', - message => 'Keine Zugfahrten im angefragten Monat gefunden.', + message => 'Keine Fahrten im angefragten Monat gefunden.', status => 404 ); return; @@ -2112,6 +2112,7 @@ sub add_journey_form { $self->render( 'add_journey', with_autocomplete => 1, + status => 400, error => 'Zug muss als „Typ Nummer“ oder „Typ Linie Nummer“ eingegeben werden.' ); @@ -2126,6 +2127,7 @@ sub add_journey_form { $self->render( 'add_journey', with_autocomplete => 1, + status => 400, error => "${key}: Ungültiges Datums-/Zeitformat" ); return; @@ -2167,6 +2169,7 @@ sub add_journey_form { $self->render( 'add_journey', with_autocomplete => 1, + status => 400, error => $error, ); } diff --git a/lib/Travelynx/Helper/DBDB.pm b/lib/Travelynx/Helper/DBDB.pm index b98a372..da3bfb1 100644 --- a/lib/Travelynx/Helper/DBDB.pm +++ b/lib/Travelynx/Helper/DBDB.pm @@ -31,14 +31,18 @@ sub has_wagonorder_p { my $api_ts = $ts->strftime('%Y%m%d%H%M'); my $url = "https://ist-wr.noncd.db.de/wagenreihung/1.0/${train_no}/${api_ts}"; - my $cache = $self->{cache}; + my $cache = $self->{realtime_cache}; my $promise = Mojo::Promise->new; if ( my $content = $cache->get("HEAD $url") ) { if ( $content eq 'n' ) { + $self->{log} + ->debug("has_wagonorder_p(${train_no}/${api_ts}): n (cached)"); return $promise->reject; } else { + $self->{log} + ->debug("has_wagonorder_p(${train_no}/${api_ts}): y (cached)"); return $promise->resolve($content); } } @@ -48,10 +52,14 @@ sub has_wagonorder_p { sub { my ($tx) = @_; if ( $tx->result->is_success ) { + $self->{log} + ->debug("has_wagonorder_p(${train_no}/${api_ts}): a"); $cache->set( "HEAD $url", 'a' ); $promise->resolve('a'); } else { + $self->{log} + ->debug("has_wagonorder_p(${train_no}/${api_ts}): n"); $cache->set( "HEAD $url", 'n' ); $promise->reject; } @@ -59,6 +67,7 @@ sub has_wagonorder_p { } )->catch( sub { + $self->{log}->debug("has_wagonorder_p(${train_no}/${api_ts}): n"); $cache->set( "HEAD $url", 'n' ); $promise->reject; return; @@ -73,10 +82,12 @@ sub get_wagonorder_p { my $url = "https://ist-wr.noncd.db.de/wagenreihung/1.0/${train_no}/${api_ts}"; - my $cache = $self->{cache}; + my $cache = $self->{realtime_cache}; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { + $self->{log} + ->debug("get_wagonorder_p(${train_no}/${api_ts}): (cached)"); $promise->resolve($content); return $promise; } @@ -89,11 +100,15 @@ sub get_wagonorder_p { if ( $tx->result->is_success ) { my $body = decode( 'utf-8', $tx->res->body ); my $json = JSON->new->decode($body); + $self->{log} + ->debug("get_wagonorder_p(${train_no}/${api_ts}): success"); $cache->freeze( $url, $json ); $promise->resolve($json); } else { my $code = $tx->code; + $self->{log}->debug( + "get_wagonorder_p(${train_no}/${api_ts}): HTTP ${code}"); $promise->reject("HTTP ${code}"); } return; @@ -101,6 +116,8 @@ sub get_wagonorder_p { )->catch( sub { my ($err) = @_; + $self->{log} + ->debug("get_wagonorder_p(${train_no}/${api_ts}): error ${err}"); $promise->reject($err); return; } @@ -113,10 +130,11 @@ sub get_stationinfo_p { my $url = "https://lib.finalrewind.org/dbdb/s/${eva}.json"; - my $cache = $self->{cache}; + my $cache = $self->{main_cache}; my $promise = Mojo::Promise->new; if ( my $content = $cache->thaw($url) ) { + $self->{log}->debug("get_stationinfo_p(${eva}): (cached)"); return $promise->resolve($content); } @@ -126,12 +144,16 @@ sub get_stationinfo_p { my ($tx) = @_; if ( my $err = $tx->error ) { + $self->{log}->debug( +"get_stationinfo_p(${eva}): HTTP $err->{code} $err->{message}" + ); $cache->freeze( $url, {} ); $promise->reject("HTTP $err->{code} $err->{message}"); return; } my $json = $tx->result->json; + $self->{log}->debug("get_stationinfo_p(${eva}): success"); $cache->freeze( $url, $json ); $promise->resolve($json); return; @@ -139,6 +161,7 @@ sub get_stationinfo_p { )->catch( sub { my ($err) = @_; + $self->{log}->debug("get_stationinfo_p(${eva}): Error ${err}"); $cache->freeze( $url, {} ); $promise->reject($err); return; diff --git a/lib/Travelynx/Helper/HAFAS.pm b/lib/Travelynx/Helper/HAFAS.pm index 7671d78..538c8ea 100644 --- a/lib/Travelynx/Helper/HAFAS.pm +++ b/lib/Travelynx/Helper/HAFAS.pm @@ -199,7 +199,7 @@ sub get_journey_p { return $promise; } -sub get_route_timestamps_p { +sub get_route_p { my ( $self, %opt ) = @_; my $promise = Mojo::Promise->new; @@ -219,13 +219,12 @@ sub get_route_timestamps_p { sub { my ($hafas) = @_; my $journey = $hafas->result; - my $ret = {}; + my $ret = []; my $polyline; my $station_is_past = 1; for my $stop ( $journey->route ) { - my $name = $stop->loc->name; - $ret->{$name} = $ret->{ $stop->loc->eva } = { + my $entry = { name => $stop->loc->name, eva => $stop->loc->eva, sched_arr => _epoch( $stop->sched_arr ), @@ -237,26 +236,27 @@ sub get_route_timestamps_p { load => $stop->load }; if ( $stop->tz_offset ) { - $ret->{$name}{tz_offset} = $stop->tz_offset; + $entry->{tz_offset} = $stop->tz_offset; } if ( ( $stop->arr_cancelled or not $stop->sched_arr ) and ( $stop->dep_cancelled or not $stop->sched_dep ) ) { - $ret->{$name}{isCancelled} = 1; + $entry->{isCancelled} = 1; } if ( $station_is_past - and not $ret->{$name}{isCancelled} + and not $entry->{isCancelled} and $now->epoch < ( - $ret->{$name}{rt_arr} // $ret->{$name}{rt_dep} - // $ret->{$name}{sched_arr} - // $ret->{$name}{sched_dep} // $now->epoch + $entry->{rt_arr} // $entry->{rt_dep} + // $entry->{sched_arr} // $entry->{sched_dep} + // $now->epoch ) ) { $station_is_past = 0; } - $ret->{$name}{isPast} = $station_is_past; + $entry->{isPast} = $station_is_past; + push( @{$ret}, $entry ); } if ( $journey->polyline ) { diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index 69026ac..6bafd93 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -47,6 +47,16 @@ sub epoch_to_dt { ); } +sub epoch_or_dt_to_dt { + my ($input) = @_; + + if ( ref($input) eq 'DateTime' ) { + return $input; + } + + return epoch_to_dt($input); +} + sub new { my ( $class, %opt ) = @_; @@ -88,10 +98,13 @@ sub add { my $stop = $opt{stop}; my $checkin_station_id = $opt{departure_eva}; my $route = $opt{route}; + my $data = $opt{data}; my $json = JSON->new; if ($train) { + my $backend_id + = $db->select( 'backends', ['id'], { iris => 1 } )->hash->{id}; $db->insert( 'in_transit', { @@ -114,13 +127,23 @@ sub add { data => JSON->new->encode( { rt => $train->departure_has_realtime ? 1 - : 0 + : 0, + %{ $data // {} } } ), + backend_id => $backend_id, } ); } elsif ( $journey and $stop ) { + my $backend_id = $db->select( + 'backends', + ['id'], + { + hafas => 1, + name => 'DB' + } + )->hash->{id}; my @route; my $product = $journey->product_at( $stop->loc->eva ) // $journey->product; @@ -162,7 +185,13 @@ sub add { 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 => JSON->new->encode( + { + rt => $stop->{rt_dep} ? 1 : 0, + %{ $data // {} } + } + ), + backend_id => $backend_id, } ); } @@ -211,8 +240,15 @@ sub postprocess { if ($is_after) { push( @route_after, $station ); } - if ( $ret->{dep_name} - and $station->[0] eq $ret->{dep_name} ) + + # Note that the departure stop may be present more than once in @route, + # e.g. when traveling along ring lines such as S41 / S42 in Berlin. + if ( + $ret->{dep_name} + and $station->[0] eq $ret->{dep_name} + and not($station->[2]{sched_dep} + and $station->[2]{sched_dep} < $ret->{sched_dep_ts} ) + ) { $is_after = 1; if ( @{$station} > 1 and not $dep_info ) { @@ -273,31 +309,25 @@ sub postprocess { # station is present several times in a train's route, e.g. # for Frankfurt Flughafen in some nightly connections. my $times = $station->[2] // {}; - if ( $times->{sched_arr} - and ref( $times->{sched_arr} ) ne 'DateTime' ) - { - $times->{sched_arr} - = epoch_to_dt( $times->{sched_arr} ); - if ( $times->{rt_arr} ) { - $times->{rt_arr} - = epoch_to_dt( $times->{rt_arr} ); - $times->{arr_delay} - = $times->{rt_arr}->epoch - $times->{sched_arr}->epoch; + for my $key (qw(sched_arr rt_arr sched_dep rt_dep)) { + if ( $times->{$key} ) { + $times->{$key} + = epoch_or_dt_to_dt( $times->{$key} ); } + } + if ( $times->{sched_arr} and $times->{rt_arr} ) { + $times->{arr_delay} + = $times->{rt_arr}->epoch - $times->{sched_arr}->epoch; + } + if ( $times->{sched_arr} or $times->{rt_arr} ) { $times->{arr} = $times->{rt_arr} || $times->{sched_arr}; $times->{arr_countdown} = $times->{arr}->epoch - $epoch; } - if ( $times->{sched_dep} - and ref( $times->{sched_dep} ) ne 'DateTime' ) - { - $times->{sched_dep} - = epoch_to_dt( $times->{sched_dep} ); - if ( $times->{rt_dep} ) { - $times->{rt_dep} - = epoch_to_dt( $times->{rt_dep} ); - $times->{dep_delay} - = $times->{rt_dep}->epoch - $times->{sched_dep}->epoch; - } + if ( $times->{sched_dep} and $times->{rt_dep} ) { + $times->{dep_delay} + = $times->{rt_dep}->epoch - $times->{sched_dep}->epoch; + } + if ( $times->{sched_dep} or $times->{rt_dep} ) { $times->{dep} = $times->{rt_dep} || $times->{sched_dep}; $times->{dep_countdown} = $times->{dep}->epoch - $epoch; } @@ -566,7 +596,8 @@ sub set_polyline { $self->set_polyline_id( uid => $uid, db => $db, - polyline_id => $polyline_id + polyline_id => $polyline_id, + train_id => $opt{train_id}, ); } @@ -579,11 +610,13 @@ sub set_polyline_id { my $db = $opt{db} // $self->{pg}->db; my $polyline_id = $opt{polyline_id}; - $db->update( - 'in_transit', - { polyline_id => $polyline_id }, - { user_id => $uid } - ); + my %where = ( user_id => $uid ); + + if ( $opt{train_id} ) { + $where{train_id} = $opt{train_id}; + } + + $db->update( 'in_transit', { polyline_id => $polyline_id }, \%where ); } sub set_route_data { @@ -596,6 +629,12 @@ sub set_route_data { my $qos_msg = $opt{qos_messages}; my $him_msg = $opt{him_messages}; + my %where = ( user_id => $uid ); + + if ( $opt{train_id} ) { + $where{train_id} = $opt{train_id}; + } + my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) ->expand->hash; @@ -612,7 +651,7 @@ sub set_route_data { route => JSON->new->encode($route), data => JSON->new->encode($data) }, - { user_id => $uid } + \%where ); } @@ -839,6 +878,12 @@ sub update_data { my $db = $opt{db} // $self->{pg}->db; my $new_data = $opt{data} // {}; + my %where = ( user_id => $uid ); + + if ( $opt{train_id} ) { + $where{train_id} = $opt{train_id}; + } + my $res_h = $db->select( 'in_transit', ['data'], { user_id => $uid } ) ->expand->hash; @@ -848,11 +893,7 @@ sub update_data { $data->{$k} = $v; } - $db->update( - 'in_transit', - { data => JSON->new->encode($data) }, - { user_id => $uid } - ); + $db->update( 'in_transit', { data => JSON->new->encode($data) }, \%where ); } sub update_user_data { @@ -862,6 +903,12 @@ sub update_user_data { my $db = $opt{db} // $self->{pg}->db; my $new_data = $opt{user_data} // {}; + my %where = ( user_id => $uid ); + + if ( $opt{train_id} ) { + $where{train_id} = $opt{train_id}; + } + my $res_h = $db->select( 'in_transit', ['user_data'], { user_id => $uid } ) ->expand->hash; @@ -871,11 +918,8 @@ sub update_user_data { $data->{$k} = $v; } - $db->update( - 'in_transit', - { user_data => JSON->new->encode($data) }, - { user_id => $uid } - ); + $db->update( 'in_transit', + { user_data => JSON->new->encode($data) }, \%where ); } sub update_visibility { diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm index 97c4681..424430c 100755 --- a/lib/Travelynx/Model/Journeys.pm +++ b/lib/Travelynx/Model/Journeys.pm @@ -218,6 +218,7 @@ sub add { edited => 0x3fff, cancelled => $opt{cancelled} ? 1 : 0, route => JSON->new->encode( \@route ), + backend_id => 1, }; if ( $opt{comment} ) { @@ -515,7 +516,7 @@ sub get { my @select = ( - qw(journey_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_iris is_hafas backend_name 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, @@ -573,6 +574,9 @@ sub get { my $ref = { id => $entry->{journey_id}, + is_iris => $entry->{is_iris}, + is_hafas => $entry->{is_hafas}, + backend_name => $entry->{backend_name}, type => $entry->{train_type}, line => $entry->{train_line}, no => $entry->{train_no}, @@ -823,7 +827,7 @@ sub get_latest_checkout_stations { { name => $row->{arr_name}, eva => $row->{arr_eva}, - hafas => ( $row->{train_id} =~ m{[|]} ? 1 : 0 ), + hafas => ( $row->{train_id} =~ m{[|]} ? 'DB' : 0 ), } ); } diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm index 4602fa2..4d90d92 100644 --- a/lib/Travelynx/Model/Users.pm +++ b/lib/Travelynx/Model/Users.pm @@ -40,14 +40,6 @@ my %predicate_atoi = ( is_blocked_by => 3, ); -my @sb_templates = ( - undef, - [ 'DBF', 'https://dbf.finalrewind.org/{name}?rt=1#{tt}{tn}' ], - [ 'bahn.expert', 'https://bahn.expert/{name}#{id}' ], - [ 'DBF HAFAS', 'https://dbf.finalrewind.org/{name}?rt=1&hafas=1#{tt}{tn}' ], - [ 'bahn.expert/regional', 'https://bahn.expert/regional/{name}#{id}' ], -); - my %token_id = ( status => 1, history => 2, @@ -411,7 +403,7 @@ sub get { my $user = $db->select( 'users', 'id, name, status, public_level, email, ' - . 'external_services, accept_follows, notifications, ' + . 'accept_follows, notifications, ' . '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', @@ -435,12 +427,8 @@ sub get { past_status => $user->{public_level} & 0x08000 ? 1 : 0, past_all => $user->{public_level} & 0x10000 ? 1 : 0, email => $user->{email}, - sb_name => $user->{external_services} - ? $sb_templates[ $user->{external_services} & 0x07 ][0] - : undef, - sb_template => $user->{external_services} - ? $sb_templates[ $user->{external_services} & 0x07 ][1] - : undef, + sb_template => + 'https://dbf.finalrewind.org/{name}?rt=1&hafas={hafas}#{tt}{tn}', registered_at => DateTime->from_epoch( epoch => $user->{registered_at_ts}, time_zone => 'Europe/Berlin' @@ -659,24 +647,6 @@ sub use_history { } } -sub use_external_services { - my ( $self, %opt ) = @_; - my $db = $opt{db} // $self->{pg}->db; - my $uid = $opt{uid}; - my $value = $opt{set}; - - if ( defined $value ) { - if ( $value < 0 or $value > 4 ) { - $value = 0; - } - $db->update( 'users', { external_services => $value }, { id => $uid } ); - } - else { - return $db->select( 'users', ['external_services'], { id => $uid } ) - ->hash->{external_services}; - } -} - sub get_webhook { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; |