Multi-backend support
Squashed commit of the following: commit 92518024ba295456358618c0e8180bd8e996fdf1 Author: Birte Kristina Friesel <birte.friesel@uos.de> Date: Fri Jul 26 18:39:46 2024 +0200 add_or_update station: remove superfluos 'new backend id := old backend id' commit df21c20c6e4c86454f8a9ac69121404415217f2a Author: Birte Kristina Friesel <birte.friesel@uos.de> Date: Fri Jul 26 18:35:51 2024 +0200 revert connection targets min_count to 3 commit be335cef07d0b42874f5fc1de4a1d13396e8e807 Author: Birte Kristina Friesel <birte.friesel@uos.de> Date: Fri Jul 26 18:20:05 2024 +0200 mention backend selection in API documentation commit 9f41828fb4f18fd707e0087def3032e8d4c8d7d8 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Thu Jul 25 20:19:23 2024 +0200 use_history: not all backends provide route data in departure monitor commit 09714b4d89684b8331d0e96f564a4c7432318f70 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Thu Jul 25 20:11:44 2024 +0200 disambiguation: pass correct hafas parameter commit 8cdf1120fc32155dc6525be64601b7c10a9c7f52 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Thu Jul 25 20:11:28 2024 +0200 _checked_in: hide Zuglauf link for non-db checkins commit 7455653f541198e0e0a6d11aed421487ffdb6285 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Thu Jul 25 20:01:47 2024 +0200 debug output commit b9cda07f85601a58ea32dbdacdd5399f302db52b Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Thu Jul 25 19:09:07 2024 +0200 fix remaining get_connection_targets / get_connecting_trains_p invocations commit 2759d7258c37c7498905cfe19f6b4c4f6d16bd21 Author: Birte Kristina Friesel <derf@finalrewind.org> Date: Wed Jul 24 20:50:12 2024 +0200 support non-DB HAFAS backends (WiP)
This commit is contained in:
parent
7811520a30
commit
47f76da4f8
33 changed files with 935 additions and 382 deletions
|
@ -448,7 +448,7 @@ sub startup {
|
||||||
return Mojo::Promise->reject('You are already checked in');
|
return Mojo::Promise->reject('You are already checked in');
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $train_id =~ m{[|]} ) {
|
if ( $opt{hafas} ) {
|
||||||
return $self->_checkin_hafas_p(%opt);
|
return $self->_checkin_hafas_p(%opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -482,7 +482,9 @@ sub startup {
|
||||||
db => $db,
|
db => $db,
|
||||||
departure_eva => $eva,
|
departure_eva => $eva,
|
||||||
train => $train,
|
train => $train,
|
||||||
route => [ $self->iris->route_diff($train) ],
|
route => [ $self->iris->route_diff($train) ],
|
||||||
|
backend_id =>
|
||||||
|
$self->stations->get_backend_id( iris => 1 ),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
|
@ -530,6 +532,7 @@ sub startup {
|
||||||
my $promise = Mojo::Promise->new;
|
my $promise = Mojo::Promise->new;
|
||||||
|
|
||||||
$self->hafas->get_journey_p(
|
$self->hafas->get_journey_p(
|
||||||
|
service => $opt{hafas},
|
||||||
trip_id => $train_id,
|
trip_id => $train_id,
|
||||||
with_polyline => 1
|
with_polyline => 1
|
||||||
)->then(
|
)->then(
|
||||||
|
@ -551,17 +554,21 @@ sub startup {
|
||||||
}
|
}
|
||||||
for my $stop ( $journey->route ) {
|
for my $stop ( $journey->route ) {
|
||||||
$self->stations->add_or_update(
|
$self->stations->add_or_update(
|
||||||
stop => $stop,
|
stop => $stop,
|
||||||
db => $db,
|
db => $db,
|
||||||
|
hafas => $opt{hafas},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
eval {
|
eval {
|
||||||
$self->in_transit->add(
|
$self->in_transit->add(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
db => $db,
|
db => $db,
|
||||||
journey => $journey,
|
journey => $journey,
|
||||||
stop => $found,
|
stop => $found,
|
||||||
data => { trip_id => $journey->id }
|
data => { trip_id => $journey->id },
|
||||||
|
backend_id => $self->stations->get_backend_id(
|
||||||
|
hafas => $opt{hafas}
|
||||||
|
),
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
if ($@) {
|
if ($@) {
|
||||||
|
@ -620,8 +627,8 @@ sub startup {
|
||||||
# mustn't be called during a transaction
|
# mustn't be called during a transaction
|
||||||
if ( not $opt{in_transaction} ) {
|
if ( not $opt{in_transaction} ) {
|
||||||
$self->run_hook( $uid, 'checkin' );
|
$self->run_hook( $uid, 'checkin' );
|
||||||
if ( $journey->class <= 16 ) {
|
if ( $opt{hafas} eq 'DB' and $journey->class <= 16 ) {
|
||||||
$self->app->add_wagonorder( $uid, 1, $journey->id,
|
$self->add_wagonorder( $uid, 1, $journey->id,
|
||||||
$found->sched_dep, $journey->number );
|
$found->sched_dep, $journey->number );
|
||||||
$self->add_stationinfo( $uid, 1, $journey->id,
|
$self->add_stationinfo( $uid, 1, $journey->id,
|
||||||
$found->loc->eva );
|
$found->loc->eva );
|
||||||
|
@ -744,6 +751,7 @@ sub startup {
|
||||||
my $db = $opt{db} // $self->pg->db;
|
my $db = $opt{db} // $self->pg->db;
|
||||||
my $user = $self->get_user_status( $uid, $db );
|
my $user = $self->get_user_status( $uid, $db );
|
||||||
my $train_id = $user->{train_id};
|
my $train_id = $user->{train_id};
|
||||||
|
my $hafas = $opt{hafas};
|
||||||
|
|
||||||
my $promise = Mojo::Promise->new;
|
my $promise = Mojo::Promise->new;
|
||||||
|
|
||||||
|
@ -765,7 +773,7 @@ sub startup {
|
||||||
return $promise->resolve( 0, 'race condition' );
|
return $promise->resolve( 0, 'race condition' );
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $train_id =~ m{[|]} ) {
|
if ( $user->{is_hafas} ) {
|
||||||
return $self->_checkout_hafas_p(%opt);
|
return $self->_checkout_hafas_p(%opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1736,7 +1744,8 @@ sub startup {
|
||||||
if ( $latest_cancellation and $latest_cancellation->{cancelled} ) {
|
if ( $latest_cancellation and $latest_cancellation->{cancelled} ) {
|
||||||
if (
|
if (
|
||||||
my $station = $self->stations->get_by_eva(
|
my $station = $self->stations->get_by_eva(
|
||||||
$latest_cancellation->{dep_eva}
|
$latest_cancellation->{dep_eva},
|
||||||
|
backend_id => $latest_cancellation->{backend_id},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -1745,7 +1754,8 @@ sub startup {
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
my $station = $self->stations->get_by_eva(
|
my $station = $self->stations->get_by_eva(
|
||||||
$latest_cancellation->{arr_eva}
|
$latest_cancellation->{arr_eva},
|
||||||
|
backend_id => $latest_cancellation->{backend_id},
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -1760,14 +1770,20 @@ sub startup {
|
||||||
if ($latest) {
|
if ($latest) {
|
||||||
my $ts = $latest->{checkout_ts};
|
my $ts = $latest->{checkout_ts};
|
||||||
my $action_time = epoch_to_dt($ts);
|
my $action_time = epoch_to_dt($ts);
|
||||||
if ( my $station
|
if (
|
||||||
= $self->stations->get_by_eva( $latest->{dep_eva} ) )
|
my $station = $self->stations->get_by_eva(
|
||||||
|
$latest->{dep_eva}, backend_id => $latest->{backend_id}
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$latest->{dep_ds100} = $station->{ds100};
|
$latest->{dep_ds100} = $station->{ds100};
|
||||||
$latest->{dep_name} = $station->{name};
|
$latest->{dep_name} = $station->{name};
|
||||||
}
|
}
|
||||||
if ( my $station
|
if (
|
||||||
= $self->stations->get_by_eva( $latest->{arr_eva} ) )
|
my $station = $self->stations->get_by_eva(
|
||||||
|
$latest->{arr_eva}, backend_id => $latest->{backend_id}
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
$latest->{arr_ds100} = $station->{ds100};
|
$latest->{arr_ds100} = $station->{ds100};
|
||||||
$latest->{arr_name} = $station->{name};
|
$latest->{arr_name} = $station->{name};
|
||||||
|
@ -1776,6 +1792,10 @@ sub startup {
|
||||||
checked_in => 0,
|
checked_in => 0,
|
||||||
cancelled => 0,
|
cancelled => 0,
|
||||||
cancellation => $latest_cancellation,
|
cancellation => $latest_cancellation,
|
||||||
|
backend_id => $latest->{backend_id},
|
||||||
|
backend_name => $latest->{backend_name},
|
||||||
|
is_iris => $latest->{is_iris},
|
||||||
|
is_hafas => $latest->{is_hafas},
|
||||||
journey_id => $latest->{journey_id},
|
journey_id => $latest->{journey_id},
|
||||||
timestamp => $action_time,
|
timestamp => $action_time,
|
||||||
timestamp_delta => $now->epoch - $action_time->epoch,
|
timestamp_delta => $now->epoch - $action_time->epoch,
|
||||||
|
@ -1833,7 +1853,12 @@ sub startup {
|
||||||
$status->{checked_in}
|
$status->{checked_in}
|
||||||
or $status->{cancelled}
|
or $status->{cancelled}
|
||||||
) ? \1 : \0,
|
) ? \1 : \0,
|
||||||
comment => $status->{comment},
|
comment => $status->{comment},
|
||||||
|
backend => {
|
||||||
|
id => $status->{backend_id},
|
||||||
|
type => $status->{is_hafas} ? 'HAFAS' : 'IRIS-TTS',
|
||||||
|
name => $status->{backend_name},
|
||||||
|
},
|
||||||
fromStation => {
|
fromStation => {
|
||||||
ds100 => $status->{dep_ds100},
|
ds100 => $status->{dep_ds100},
|
||||||
name => $status->{dep_name},
|
name => $status->{dep_name},
|
||||||
|
@ -1992,6 +2017,7 @@ sub startup {
|
||||||
"Eingecheckt in $traewelling->{line} nach $traewelling->{arr_name}",
|
"Eingecheckt in $traewelling->{line} nach $traewelling->{arr_name}",
|
||||||
status_id => $traewelling->{status_id},
|
status_id => $traewelling->{status_id},
|
||||||
);
|
);
|
||||||
|
|
||||||
$self->traewelling->set_latest_pull_status_id(
|
$self->traewelling->set_latest_pull_status_id(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
status_id => $traewelling->{status_id},
|
status_id => $traewelling->{status_id},
|
||||||
|
@ -2324,6 +2350,7 @@ sub startup {
|
||||||
$authed_r->get('/account/password')->to('account#password_form');
|
$authed_r->get('/account/password')->to('account#password_form');
|
||||||
$authed_r->get('/account/mail')->to('account#change_mail');
|
$authed_r->get('/account/mail')->to('account#change_mail');
|
||||||
$authed_r->get('/account/name')->to('account#change_name');
|
$authed_r->get('/account/name')->to('account#change_name');
|
||||||
|
$authed_r->get('/account/select_backend')->to('account#backend_form');
|
||||||
$authed_r->get('/export.json')->to('account#json_export');
|
$authed_r->get('/export.json')->to('account#json_export');
|
||||||
$authed_r->get('/history.json')->to('traveling#json_history');
|
$authed_r->get('/history.json')->to('traveling#json_history');
|
||||||
$authed_r->get('/history.csv')->to('traveling#csv_history');
|
$authed_r->get('/history.csv')->to('traveling#csv_history');
|
||||||
|
@ -2345,6 +2372,7 @@ sub startup {
|
||||||
$authed_r->post('/account/hooks')->to('account#webhook');
|
$authed_r->post('/account/hooks')->to('account#webhook');
|
||||||
$authed_r->post('/account/traewelling')->to('traewelling#settings');
|
$authed_r->post('/account/traewelling')->to('traewelling#settings');
|
||||||
$authed_r->post('/account/insight')->to('account#insight');
|
$authed_r->post('/account/insight')->to('account#insight');
|
||||||
|
$authed_r->post('/account/select_backend')->to('account#change_backend');
|
||||||
$authed_r->post('/journey/add')->to('traveling#add_journey_form');
|
$authed_r->post('/journey/add')->to('traveling#add_journey_form');
|
||||||
$authed_r->post('/journey/comment')->to('traveling#comment_form');
|
$authed_r->post('/journey/comment')->to('traveling#comment_form');
|
||||||
$authed_r->post('/journey/visibility')->to('traveling#visibility_form');
|
$authed_r->post('/journey/visibility')->to('traveling#visibility_form');
|
||||||
|
|
|
@ -8,6 +8,7 @@ use Mojo::Base 'Mojolicious::Command';
|
||||||
use DateTime;
|
use DateTime;
|
||||||
use File::Slurp qw(read_file);
|
use File::Slurp qw(read_file);
|
||||||
use JSON;
|
use JSON;
|
||||||
|
use Travel::Status::DE::HAFAS;
|
||||||
use Travel::Status::DE::IRIS::Stations;
|
use Travel::Status::DE::IRIS::Stations;
|
||||||
|
|
||||||
has description => 'Initialize or upgrade database layout';
|
has description => 'Initialize or upgrade database layout';
|
||||||
|
@ -1918,7 +1919,7 @@ my @migrations = (
|
||||||
|
|
||||||
# v49 -> v50
|
# v49 -> v50
|
||||||
# travelynx 2.0 introduced proper HAFAS support, so there is no need for
|
# travelynx 2.0 introduced proper HAFAS support, so there is no need for
|
||||||
# the 'FYI, here is some hAFAS data' kludge anymore.
|
# the 'FYI, here is some HAFAS data' kludge anymore.
|
||||||
sub {
|
sub {
|
||||||
my ($db) = @_;
|
my ($db) = @_;
|
||||||
$db->query(
|
$db->query(
|
||||||
|
@ -2310,6 +2311,235 @@ my @migrations = (
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
|
# v54 -> v55
|
||||||
|
# do not share stations between backends
|
||||||
|
sub {
|
||||||
|
my ($db) = @_;
|
||||||
|
$db->query(
|
||||||
|
qq{
|
||||||
|
alter table schema_version add column hafas varchar(12);
|
||||||
|
alter table users drop column external_services;
|
||||||
|
alter table users add column backend_id smallint references backends (id) default 1;
|
||||||
|
alter table stations drop constraint stations_pkey;
|
||||||
|
alter table stations add unique (eva, source);
|
||||||
|
create index eva_by_source on stations (eva, source);
|
||||||
|
create index eva on stations (eva);
|
||||||
|
alter table related_stations drop constraint related_stations_eva_meta_key;
|
||||||
|
drop index rel_eva;
|
||||||
|
alter table related_stations add column backend_id smallint;
|
||||||
|
update related_stations set backend_id = 1;
|
||||||
|
alter table related_stations alter column backend_id set not null;
|
||||||
|
alter table related_stations add constraint backend_fk foreign key (backend_id) references backends (id);
|
||||||
|
alter table related_stations add unique (eva, meta, backend_id);
|
||||||
|
create index related_stations_eva_backend_key on related_stations (eva, backend_id);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
# up until now, IRIS and DB HAFAS shared stations, with IRIS taking
|
||||||
|
# preference. As of v2.7, this is no longer the case. However, old DB
|
||||||
|
# HAFAS journeys may still reference IRIS-specific stations. So, we
|
||||||
|
# make all IRIS stations available as DB HAFAS stations as well.
|
||||||
|
my $total
|
||||||
|
= $db->select( 'stations', 'count(*) as count', { source => 0 } )
|
||||||
|
->hash->{count};
|
||||||
|
my $count = 0;
|
||||||
|
|
||||||
|
# Caveat: If this is a fresh installation, there are no IRIS stations
|
||||||
|
# in the database yet. So we have to populate it first.
|
||||||
|
if ( not $total ) {
|
||||||
|
say
|
||||||
|
'Preparing to untangle IRIS / HAFAS stations, this may take a while ...';
|
||||||
|
$total = scalar Travel::Status::DE::IRIS::Stations::get_stations();
|
||||||
|
for my $s ( Travel::Status::DE::IRIS::Stations::get_stations() ) {
|
||||||
|
my ( $ds100, $name, $eva, $lon, $lat ) = @{$s};
|
||||||
|
if ( $ENV{__TRAVELYNX_TEST_MINI_IRIS}
|
||||||
|
and ( $eva < 8000000 or $eva > 8000100 ) )
|
||||||
|
{
|
||||||
|
next;
|
||||||
|
}
|
||||||
|
$db->insert(
|
||||||
|
'stations',
|
||||||
|
{
|
||||||
|
eva => $eva,
|
||||||
|
ds100 => $ds100,
|
||||||
|
name => $name,
|
||||||
|
lat => $lat,
|
||||||
|
lon => $lon,
|
||||||
|
source => 0,
|
||||||
|
archived => 0
|
||||||
|
},
|
||||||
|
);
|
||||||
|
if ( $count++ % 1000 == 0 ) {
|
||||||
|
printf( " %2.0f%% complete\n", $count * 100 / $total );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
say 'Untangling IRIS / HAFAS stations, this may take a while ...';
|
||||||
|
my $res = $db->query(
|
||||||
|
qq{
|
||||||
|
select eva, ds100, name, lat, lon, archived
|
||||||
|
from stations
|
||||||
|
where source = 0;
|
||||||
|
}
|
||||||
|
);
|
||||||
|
while ( my $row = $res->hash ) {
|
||||||
|
$db->insert(
|
||||||
|
'stations',
|
||||||
|
{
|
||||||
|
eva => $row->{eva},
|
||||||
|
ds100 => $row->{ds100},
|
||||||
|
name => $row->{name},
|
||||||
|
lat => $row->{lat},
|
||||||
|
lon => $row->{lon},
|
||||||
|
archived => $row->{archived},
|
||||||
|
source => 1,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
if ( $count++ % 1000 == 0 ) {
|
||||||
|
printf( " %2.0f%% complete\n", $count * 100 / $total );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$db->query(
|
||||||
|
qq{
|
||||||
|
alter table in_transit add constraint in_transit_checkin_eva_fk
|
||||||
|
foreign key (checkin_station_id, backend_id)
|
||||||
|
references stations (eva, source);
|
||||||
|
alter table in_transit add constraint in_transit_checkout_eva_fk
|
||||||
|
foreign key (checkout_station_id, backend_id)
|
||||||
|
references stations (eva, source);
|
||||||
|
alter table journeys add constraint journeys_checkin_eva_fk
|
||||||
|
foreign key (checkin_station_id, backend_id)
|
||||||
|
references stations (eva, source);
|
||||||
|
alter table journeys add constraint journeys_checkout_eva_fk
|
||||||
|
foreign key (checkout_station_id, backend_id)
|
||||||
|
references stations (eva, source);
|
||||||
|
drop view in_transit_str;
|
||||||
|
drop view journeys_str;
|
||||||
|
drop view follows_in_transit;
|
||||||
|
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, 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.ris as is_ris,
|
||||||
|
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 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,
|
||||||
|
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
|
||||||
|
order by checkin_time desc
|
||||||
|
;
|
||||||
|
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, ris, backend.name as backend_name
|
||||||
|
from users
|
||||||
|
left join backends as backend on users.backend_id = backend.id
|
||||||
|
;
|
||||||
|
update schema_version set version = 55;
|
||||||
|
update schema_version set hafas = '0';
|
||||||
|
}
|
||||||
|
);
|
||||||
|
say
|
||||||
|
'This travelynx instance now has support for non-DB HAFAS backends.';
|
||||||
|
say
|
||||||
|
'If the migration fails due to a deadlock, re-run it after stopping all background workers';
|
||||||
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
sub sync_stations {
|
sub sync_stations {
|
||||||
|
@ -2341,7 +2571,7 @@ sub sync_stations {
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
on_conflict => \
|
on_conflict => \
|
||||||
'(eva) do update set archived = false, source = 0, ds100 = EXCLUDED.ds100, name=EXCLUDED.name, lat=EXCLUDED.lat, lon=EXCLUDED.lon'
|
'(eva, source) do update set archived = false, source = 0, ds100 = EXCLUDED.ds100, name=EXCLUDED.name, lat=EXCLUDED.lat, lon=EXCLUDED.lon'
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( $count++ % 1000 == 0 ) {
|
if ( $count++ % 1000 == 0 ) {
|
||||||
|
@ -2500,6 +2730,26 @@ sub sync_stations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub sync_backends {
|
||||||
|
my ($db) = @_;
|
||||||
|
for my $service ( Travel::Status::DE::HAFAS::get_services()) {
|
||||||
|
$db->insert(
|
||||||
|
'backends',
|
||||||
|
{
|
||||||
|
iris => 0,
|
||||||
|
hafas => 1,
|
||||||
|
efa => 0,
|
||||||
|
ris => 0,
|
||||||
|
name => $service->{shortname},
|
||||||
|
},
|
||||||
|
{ on_conflict => undef }
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
$db->update( 'schema_version',
|
||||||
|
{ hafas => $Travel::Status::DE::HAFAS::VERSION } );
|
||||||
|
}
|
||||||
|
|
||||||
sub setup_db {
|
sub setup_db {
|
||||||
my ($db) = @_;
|
my ($db) = @_;
|
||||||
my $tx = $db->begin;
|
my $tx = $db->begin;
|
||||||
|
@ -2566,9 +2816,9 @@ sub migrate_db {
|
||||||
}
|
}
|
||||||
|
|
||||||
my $iris_version = get_schema_version( $db, 'iris' );
|
my $iris_version = get_schema_version( $db, 'iris' );
|
||||||
say "Found IRIS station database v${iris_version}";
|
say "Found IRIS station table v${iris_version}";
|
||||||
if ( $iris_version eq $Travel::Status::DE::IRIS::Stations::VERSION ) {
|
if ( $iris_version eq $Travel::Status::DE::IRIS::Stations::VERSION ) {
|
||||||
say 'Station database is up-to-date';
|
say 'Station table is up-to-date';
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
eval {
|
eval {
|
||||||
|
@ -2587,6 +2837,18 @@ sub migrate_db {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
my $hafas_version = get_schema_version( $db, 'hafas' );
|
||||||
|
say "Found backend table for HAFAS v${hafas_version}";
|
||||||
|
if ( $hafas_version eq $Travel::Status::DE::HAFAS::VERSION ) {
|
||||||
|
say 'Backend table is up-to-date';
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
say
|
||||||
|
"Synchronizing with Travel::Status::DE::HAFAS $Travel::Status::DE::HAFAS::VERSION";
|
||||||
|
sync_backends($db);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
$db->update( 'schema_version',
|
$db->update( 'schema_version',
|
||||||
{ travelynx => $self->app->config->{version} } );
|
{ travelynx => $self->app->config->{version} } );
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
package Travelynx::Command::dumpconfig;
|
package Travelynx::Command::dumpconfig;
|
||||||
|
|
||||||
# Copyright (C) 2020-2023 Birte Kristina Friesel
|
# Copyright (C) 2020-2023 Birte Kristina Friesel
|
||||||
#
|
#
|
||||||
# SPDX-License-Identifier: AGPL-3.0-or-later
|
# SPDX-License-Identifier: AGPL-3.0-or-later
|
||||||
|
|
|
@ -47,9 +47,12 @@ sub run {
|
||||||
my $arr = $entry->{arr_eva};
|
my $arr = $entry->{arr_eva};
|
||||||
my $train_id = $entry->{train_id};
|
my $train_id = $entry->{train_id};
|
||||||
|
|
||||||
if ( $train_id =~ m{[|]} ) {
|
if ( $entry->{is_hafas} ) {
|
||||||
|
|
||||||
$self->app->hafas->get_journey_p( trip_id => $train_id )->then(
|
$self->app->hafas->get_journey_p(
|
||||||
|
trip_id => $train_id,
|
||||||
|
service => $entry->{backend_name}
|
||||||
|
)->then(
|
||||||
sub {
|
sub {
|
||||||
my ($journey) = @_;
|
my ($journey) = @_;
|
||||||
|
|
||||||
|
@ -135,6 +138,9 @@ sub run {
|
||||||
next;
|
next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# TODO irgendwo ist hier ne race condition wo ein neuer checkin (in HAFAS) mit IRIS-Daten überschrieben wird.
|
||||||
|
# Die ganzen updates brauchen wirklich mal sanity checks mit train id ...
|
||||||
|
|
||||||
# Note: IRIS data is not always updated in real-time. Both departure and
|
# Note: IRIS data is not always updated in real-time. Both departure and
|
||||||
# arrival delays may take several minutes to appear, especially in case
|
# arrival delays may take several minutes to appear, especially in case
|
||||||
# of large-scale disturbances. We work around this by continuing to
|
# of large-scale disturbances. We work around this by continuing to
|
||||||
|
|
|
@ -999,6 +999,52 @@ sub password_form {
|
||||||
$self->render('change_password');
|
$self->render('change_password');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub backend_form {
|
||||||
|
my ($self) = @_;
|
||||||
|
my $user = $self->current_user;
|
||||||
|
|
||||||
|
my @backends = $self->stations->get_backends;
|
||||||
|
|
||||||
|
for my $backend (@backends) {
|
||||||
|
my $type = 'UNKNOWN';
|
||||||
|
if ( $backend->{iris} ) {
|
||||||
|
$type = 'IRIS-TTS';
|
||||||
|
$backend->{name} = 'DB';
|
||||||
|
}
|
||||||
|
elsif ( $backend->{hafas} ) {
|
||||||
|
$type = 'HAFAS';
|
||||||
|
$backend->{longname}
|
||||||
|
= $self->hafas->get_service( $backend->{name} )->{name};
|
||||||
|
}
|
||||||
|
$backend->{type} = $type;
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->render(
|
||||||
|
'select_backend',
|
||||||
|
backends => \@backends,
|
||||||
|
user => $user,
|
||||||
|
redirect_to => $self->req->param('redirect_to') // '/',
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
sub change_backend {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
my $backend_id = $self->req->param('backend');
|
||||||
|
my $redir = $self->req->param('redirect_to') // '/';
|
||||||
|
|
||||||
|
if ( $backend_id !~ m{ ^ \d+ $ }x ) {
|
||||||
|
$self->redirect_to($redir);
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->users->set_backend(
|
||||||
|
uid => $self->current_user->{id},
|
||||||
|
backend_id => $backend_id,
|
||||||
|
);
|
||||||
|
|
||||||
|
$self->redirect_to($redir);
|
||||||
|
}
|
||||||
|
|
||||||
sub change_password {
|
sub change_password {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
my $old_password = $self->req->param('oldpw');
|
my $old_password = $self->req->param('oldpw');
|
||||||
|
|
|
@ -117,6 +117,7 @@ sub travel_v1 {
|
||||||
deprecated => \0,
|
deprecated => \0,
|
||||||
error => 'Malformed JSON',
|
error => 'Malformed JSON',
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -130,6 +131,7 @@ sub travel_v1 {
|
||||||
deprecated => \0,
|
deprecated => \0,
|
||||||
error => 'Malformed token',
|
error => 'Malformed token',
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -143,6 +145,7 @@ sub travel_v1 {
|
||||||
deprecated => \0,
|
deprecated => \0,
|
||||||
error => 'Malformed token',
|
error => 'Malformed token',
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -155,6 +158,7 @@ sub travel_v1 {
|
||||||
deprecated => \0,
|
deprecated => \0,
|
||||||
error => 'Invalid token',
|
error => 'Invalid token',
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -169,6 +173,7 @@ sub travel_v1 {
|
||||||
error => 'Missing or invalid action',
|
error => 'Missing or invalid action',
|
||||||
status => $self->get_user_status_json_v1( uid => $uid )
|
status => $self->get_user_status_json_v1( uid => $uid )
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -177,7 +182,8 @@ sub travel_v1 {
|
||||||
my $from_station = sanitize( q{}, $payload->{fromStation} );
|
my $from_station = sanitize( q{}, $payload->{fromStation} );
|
||||||
my $to_station = sanitize( q{}, $payload->{toStation} );
|
my $to_station = sanitize( q{}, $payload->{toStation} );
|
||||||
my $train_id;
|
my $train_id;
|
||||||
my $hafas = exists $payload->{train}{journeyID} ? 1 : 0;
|
my $hafas = sanitize(undef, $payload->{hafas});
|
||||||
|
$hafas //= exists $payload->{train}{journeyID} ? 'DB' : undef;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
not(
|
not(
|
||||||
|
@ -195,11 +201,12 @@ sub travel_v1 {
|
||||||
error => 'Missing fromStation or train data',
|
error => 'Missing fromStation or train data',
|
||||||
status => $self->get_user_status_json_v1( uid => $uid )
|
status => $self->get_user_status_json_v1( uid => $uid )
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( not $hafas and not $self->stations->search($from_station) ) {
|
if ( not $hafas and not $self->stations->search($from_station, iris => 1) ) {
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
success => \0,
|
success => \0,
|
||||||
|
@ -207,13 +214,14 @@ sub travel_v1 {
|
||||||
error => 'Unknown fromStation',
|
error => 'Unknown fromStation',
|
||||||
status => $self->get_user_status_json_v1( uid => $uid )
|
status => $self->get_user_status_json_v1( uid => $uid )
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $to_station
|
if ( $to_station
|
||||||
and not $hafas
|
and not $hafas
|
||||||
and not $self->stations->search($to_station) )
|
and not $self->stations->search($to_station, iris => 1) )
|
||||||
{
|
{
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
|
@ -222,6 +230,7 @@ sub travel_v1 {
|
||||||
error => 'Unknown toStation',
|
error => 'Unknown toStation',
|
||||||
status => $self->get_user_status_json_v1( uid => $uid )
|
status => $self->get_user_status_json_v1( uid => $uid )
|
||||||
},
|
},
|
||||||
|
status => 400,
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -273,7 +282,8 @@ sub travel_v1 {
|
||||||
return $self->checkin_p(
|
return $self->checkin_p(
|
||||||
station => $from_station,
|
station => $from_station,
|
||||||
train_id => $train_id,
|
train_id => $train_id,
|
||||||
uid => $uid
|
uid => $uid,
|
||||||
|
hafas => $hafas,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
)->then(
|
)->then(
|
||||||
|
@ -654,10 +664,13 @@ sub autocomplete {
|
||||||
|
|
||||||
$self->res->headers->cache_control('max-age=86400, immutable');
|
$self->res->headers->cache_control('max-age=86400, immutable');
|
||||||
|
|
||||||
|
my $backend_id = $self->param('backend_id') // 1;
|
||||||
|
|
||||||
my $output
|
my $output
|
||||||
= "document.addEventListener('DOMContentLoaded',function(){M.Autocomplete.init(document.querySelectorAll('.autocomplete'),{\n";
|
= "document.addEventListener('DOMContentLoaded',function(){M.Autocomplete.init(document.querySelectorAll('.autocomplete'),{\n";
|
||||||
$output .= 'minLength:3,limit:50,data:';
|
$output .= 'minLength:3,limit:50,data:';
|
||||||
$output .= encode_json( $self->stations->get_for_autocomplete );
|
$output
|
||||||
|
.= encode_json( $self->stations->get_for_autocomplete( backend_id => $backend_id ) );
|
||||||
$output .= "\n});});\n";
|
$output .= "\n});});\n";
|
||||||
|
|
||||||
$self->render(
|
$self->render(
|
||||||
|
|
|
@ -24,10 +24,15 @@ sub has_str_in_list {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# when called with "eva" provided: look up connections from eva, either
|
||||||
|
# for provided backend_id / hafas or (if not provided) for user backend id.
|
||||||
|
# When calld without "eva": look up connections from current/latest arrival
|
||||||
|
# eva, using the checkin's backend id.
|
||||||
sub get_connecting_trains_p {
|
sub get_connecting_trains_p {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my $uid = $opt{uid} //= $self->current_user->{id};
|
my $user = $self->current_user;
|
||||||
|
my $uid = $opt{uid} //= $user->{id};
|
||||||
my $use_history = $self->users->use_history( uid => $uid );
|
my $use_history = $self->users->use_history( uid => $uid );
|
||||||
|
|
||||||
my ( $eva, $exclude_via, $exclude_train_id, $exclude_before );
|
my ( $eva, $exclude_via, $exclude_train_id, $exclude_before );
|
||||||
|
@ -43,10 +48,20 @@ sub get_connecting_trains_p {
|
||||||
elsif ( $opt{destination_name} ) {
|
elsif ( $opt{destination_name} ) {
|
||||||
$eva = $opt{eva};
|
$eva = $opt{eva};
|
||||||
}
|
}
|
||||||
|
if ( not defined $opt{backend_id} ) {
|
||||||
|
if ( $opt{hafas} ) {
|
||||||
|
$opt{backend_id}
|
||||||
|
= $self->stations->get_backend_id( hafas => $opt{hafas} );
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
$opt{backend_id} = $user->{backend_id};
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if ( $use_history & 0x02 ) {
|
if ( $use_history & 0x02 ) {
|
||||||
my $status = $self->get_user_status;
|
my $status = $self->get_user_status;
|
||||||
|
$opt{backend_id} = $status->{backend_id};
|
||||||
$eva = $status->{arr_eva};
|
$eva = $status->{arr_eva};
|
||||||
$exclude_via = $status->{dep_name};
|
$exclude_via = $status->{dep_name};
|
||||||
$exclude_train_id = $status->{train_id};
|
$exclude_train_id = $status->{train_id};
|
||||||
|
@ -65,10 +80,12 @@ sub get_connecting_trains_p {
|
||||||
return $promise->reject;
|
return $promise->reject;
|
||||||
}
|
}
|
||||||
|
|
||||||
my ( $dest_ids, $destinations )
|
$self->log->debug(
|
||||||
= $self->journeys->get_connection_targets(%opt);
|
"get_connecting_trains_p(backend_id => $opt{backend_id}, eva => $eva)");
|
||||||
|
|
||||||
my @destinations = uniq_by { $_->{name} } @{$destinations};
|
my @destinations = $self->journeys->get_connection_targets(%opt);
|
||||||
|
|
||||||
|
@destinations = uniq_by { $_->{name} } @destinations;
|
||||||
|
|
||||||
if ($exclude_via) {
|
if ($exclude_via) {
|
||||||
@destinations = grep { $_->{name} ne $exclude_via } @destinations;
|
@destinations = grep { $_->{name} ne $exclude_via } @destinations;
|
||||||
|
@ -78,11 +95,8 @@ sub get_connecting_trains_p {
|
||||||
return $promise->reject;
|
return $promise->reject;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $iris_eva = $eva;
|
$self->log->debug( 'get_connection_targets returned '
|
||||||
if ( $eva < 8000000 ) {
|
. join( q{, }, map { $_->{name} } @destinations ) );
|
||||||
$iris_eva = ( List::Util::first { $_ >= 8000000 } @{$dest_ids} )
|
|
||||||
// $eva;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $can_check_in = not $arr_epoch || ( $arr_countdown // 1 ) < 0;
|
my $can_check_in = not $arr_epoch || ( $arr_countdown // 1 ) < 0;
|
||||||
my $lookahead
|
my $lookahead
|
||||||
|
@ -91,11 +105,9 @@ sub get_connecting_trains_p {
|
||||||
my $iris_promise = Mojo::Promise->new;
|
my $iris_promise = Mojo::Promise->new;
|
||||||
my %via_count = map { $_->{name} => 0 } @destinations;
|
my %via_count = map { $_->{name} => 0 } @destinations;
|
||||||
|
|
||||||
if ( $iris_eva >= 8000000
|
if ( $opt{backend_id} == 0 ) {
|
||||||
and List::Util::any { $_->{eva} >= 8000000 } @destinations )
|
|
||||||
{
|
|
||||||
$self->iris->get_departures_p(
|
$self->iris->get_departures_p(
|
||||||
station => $iris_eva,
|
station => $eva,
|
||||||
lookbehind => 10,
|
lookbehind => 10,
|
||||||
lookahead => $lookahead,
|
lookahead => $lookahead,
|
||||||
with_related => 1
|
with_related => 1
|
||||||
|
@ -103,7 +115,7 @@ sub get_connecting_trains_p {
|
||||||
sub {
|
sub {
|
||||||
my ($stationboard) = @_;
|
my ($stationboard) = @_;
|
||||||
if ( $stationboard->{errstr} ) {
|
if ( $stationboard->{errstr} ) {
|
||||||
$iris_promise->resolve( [] );
|
$promise->resolve( [], [] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -237,105 +249,30 @@ sub get_connecting_trains_p {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
$iris_promise->resolve( [ @results, @cancellations ] );
|
$promise->resolve( [ @results, @cancellations ], [] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
)->catch(
|
)->catch(
|
||||||
sub {
|
sub {
|
||||||
$iris_promise->resolve( [] );
|
$promise->resolve( [], [] );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
)->wait;
|
)->wait;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$iris_promise->resolve( [] );
|
my $hafas_service
|
||||||
}
|
= $self->stations->get_hafas_name( backend_id => $opt{backend_id} );
|
||||||
|
$self->hafas->get_departures_p(
|
||||||
my $hafas_promise = Mojo::Promise->new;
|
service => $hafas_service,
|
||||||
$self->hafas->get_departures_p(
|
eva => $eva,
|
||||||
eva => $eva,
|
lookbehind => 10,
|
||||||
lookbehind => 10,
|
lookahead => $lookahead
|
||||||
lookahead => $lookahead
|
)->then(
|
||||||
)->then(
|
sub {
|
||||||
sub {
|
my ($status) = @_;
|
||||||
my ($status) = @_;
|
my @hafas_trains;
|
||||||
$hafas_promise->resolve( [ $status->results ] );
|
my @all_hafas_trains = $status->results;
|
||||||
return;
|
|
||||||
}
|
|
||||||
)->catch(
|
|
||||||
sub {
|
|
||||||
# HAFAS data is optional.
|
|
||||||
# Errors are logged by get_json_p and can be silently ignored here.
|
|
||||||
$hafas_promise->resolve( [] );
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
)->wait;
|
|
||||||
|
|
||||||
Mojo::Promise->all( $iris_promise, $hafas_promise )->then(
|
|
||||||
sub {
|
|
||||||
my ( $iris, $hafas ) = @_;
|
|
||||||
my @iris_trains = @{ $iris->[0] };
|
|
||||||
my @all_hafas_trains = @{ $hafas->[0] };
|
|
||||||
my @hafas_trains;
|
|
||||||
|
|
||||||
# We've already got a list of connecting trains; this function
|
|
||||||
# only adds further information to them. We ignore errors, as
|
|
||||||
# partial data is better than no data.
|
|
||||||
eval {
|
|
||||||
for my $iris_train (@iris_trains) {
|
|
||||||
if ( $iris_train->[0]->departure_is_cancelled ) {
|
|
||||||
for my $hafas_train (@all_hafas_trains) {
|
|
||||||
if ( $hafas_train->number
|
|
||||||
and $hafas_train->number
|
|
||||||
== $iris_train->[0]->train_no )
|
|
||||||
{
|
|
||||||
$hafas_train->{iris_seen} = 1;
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
for my $hafas_train (@all_hafas_trains) {
|
|
||||||
if ( $hafas_train->number
|
|
||||||
and $hafas_train->number
|
|
||||||
== $iris_train->[0]->train_no )
|
|
||||||
{
|
|
||||||
$hafas_train->{iris_seen} = 1;
|
|
||||||
if ( $hafas_train->load
|
|
||||||
and $hafas_train->load->{SECOND} )
|
|
||||||
{
|
|
||||||
$iris_train->[3] = $hafas_train->load;
|
|
||||||
}
|
|
||||||
for my $stop ( $hafas_train->route ) {
|
|
||||||
if ( $stop->loc->name
|
|
||||||
and $stop->loc->name eq
|
|
||||||
$iris_train->[1]->{name}
|
|
||||||
and $stop->arr )
|
|
||||||
{
|
|
||||||
$iris_train->[2] = $stop->arr;
|
|
||||||
if ( $iris_train->[0]->departure_delay
|
|
||||||
and not $stop->arr_delay )
|
|
||||||
{
|
|
||||||
$iris_train->[2]
|
|
||||||
->add( minutes => $iris_train->[0]
|
|
||||||
->departure_delay );
|
|
||||||
}
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
last;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for my $hafas_train (@all_hafas_trains) {
|
for my $hafas_train (@all_hafas_trains) {
|
||||||
if ( $hafas_train->{iris_seen} ) {
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
if ( $hafas_train->station_eva >= 8000000 ) {
|
|
||||||
|
|
||||||
# better safe than sorry, for now
|
|
||||||
next;
|
|
||||||
}
|
|
||||||
for my $stop ( $hafas_train->route ) {
|
for my $stop ( $hafas_train->route ) {
|
||||||
for my $dest (@destinations) {
|
for my $dest (@destinations) {
|
||||||
if ( $stop->loc->name
|
if ( $stop->loc->name
|
||||||
|
@ -353,30 +290,30 @@ sub get_connecting_trains_p {
|
||||||
}
|
}
|
||||||
if ( $departure->epoch >= $exclude_before ) {
|
if ( $departure->epoch >= $exclude_before ) {
|
||||||
$via_count{ $dest->{name} }++;
|
$via_count{ $dest->{name} }++;
|
||||||
push( @hafas_trains,
|
push(
|
||||||
[ $hafas_train, $dest, $arrival ] );
|
@hafas_trains,
|
||||||
|
[
|
||||||
|
$hafas_train, $dest,
|
||||||
|
$arrival, $hafas_service
|
||||||
|
]
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
$promise->resolve( [], \@hafas_trains );
|
||||||
if ($@) {
|
return;
|
||||||
$self->app->log->error(
|
|
||||||
"get_connecting_trains_p($uid): IRIS/HAFAS merge failed: $@"
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
)->catch(
|
||||||
$promise->resolve( \@iris_trains, \@hafas_trains );
|
sub {
|
||||||
return;
|
my ($err) = @_;
|
||||||
}
|
$self->log->debug("get_connection_trains: hafas: $err");
|
||||||
)->catch(
|
$promise->resolve( [], [] );
|
||||||
sub {
|
return;
|
||||||
my ($err) = @_;
|
}
|
||||||
$promise->reject($err);
|
)->wait;
|
||||||
return;
|
}
|
||||||
}
|
|
||||||
)->wait;
|
|
||||||
|
|
||||||
return $promise;
|
return $promise;
|
||||||
}
|
}
|
||||||
|
@ -394,7 +331,8 @@ sub compute_effective_visibility {
|
||||||
sub homepage {
|
sub homepage {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
if ( $self->is_user_authenticated ) {
|
if ( $self->is_user_authenticated ) {
|
||||||
my $uid = $self->current_user->{id};
|
my $user = $self->current_user;
|
||||||
|
my $uid = $user->{id};
|
||||||
my $status = $self->get_user_status;
|
my $status = $self->get_user_status;
|
||||||
my @timeline = $self->in_transit->get_timeline(
|
my @timeline = $self->in_transit->get_timeline(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
|
@ -405,7 +343,7 @@ sub homepage {
|
||||||
if ( $status->{checked_in} ) {
|
if ( $status->{checked_in} ) {
|
||||||
my $journey_visibility
|
my $journey_visibility
|
||||||
= $self->compute_effective_visibility(
|
= $self->compute_effective_visibility(
|
||||||
$self->current_user->{default_visibility_str},
|
$user->{default_visibility_str},
|
||||||
$status->{visibility_str} );
|
$status->{visibility_str} );
|
||||||
if ( defined $status->{arrival_countdown}
|
if ( defined $status->{arrival_countdown}
|
||||||
and $status->{arrival_countdown} < ( 40 * 60 ) )
|
and $status->{arrival_countdown} < ( 40 * 60 ) )
|
||||||
|
@ -416,6 +354,7 @@ sub homepage {
|
||||||
my ( $connections_iris, $connections_hafas ) = @_;
|
my ( $connections_iris, $connections_hafas ) = @_;
|
||||||
$self->render(
|
$self->render(
|
||||||
'landingpage',
|
'landingpage',
|
||||||
|
user => $user,
|
||||||
user_status => $status,
|
user_status => $status,
|
||||||
journey_visibility => $journey_visibility,
|
journey_visibility => $journey_visibility,
|
||||||
connections_iris => $connections_iris,
|
connections_iris => $connections_iris,
|
||||||
|
@ -427,6 +366,7 @@ sub homepage {
|
||||||
sub {
|
sub {
|
||||||
$self->render(
|
$self->render(
|
||||||
'landingpage',
|
'landingpage',
|
||||||
|
user => $user,
|
||||||
user_status => $status,
|
user_status => $status,
|
||||||
journey_visibility => $journey_visibility,
|
journey_visibility => $journey_visibility,
|
||||||
);
|
);
|
||||||
|
@ -438,6 +378,7 @@ sub homepage {
|
||||||
else {
|
else {
|
||||||
$self->render(
|
$self->render(
|
||||||
'landingpage',
|
'landingpage',
|
||||||
|
user => $user,
|
||||||
user_status => $status,
|
user_status => $status,
|
||||||
journey_visibility => $journey_visibility,
|
journey_visibility => $journey_visibility,
|
||||||
);
|
);
|
||||||
|
@ -451,10 +392,12 @@ sub homepage {
|
||||||
}
|
}
|
||||||
$self->render(
|
$self->render(
|
||||||
'landingpage',
|
'landingpage',
|
||||||
|
user => $user,
|
||||||
user_status => $status,
|
user_status => $status,
|
||||||
recent_targets => \@recent_targets,
|
recent_targets => \@recent_targets,
|
||||||
with_autocomplete => 1,
|
with_autocomplete => 1,
|
||||||
with_geolocation => 1
|
with_geolocation => 1,
|
||||||
|
backend_id => $user->{backend_id},
|
||||||
);
|
);
|
||||||
$self->users->mark_seen( uid => $uid );
|
$self->users->mark_seen( uid => $uid );
|
||||||
}
|
}
|
||||||
|
@ -515,6 +458,7 @@ sub status_card {
|
||||||
elsif ( $status->{cancellation} ) {
|
elsif ( $status->{cancellation} ) {
|
||||||
$self->render_later;
|
$self->render_later;
|
||||||
$self->get_connecting_trains_p(
|
$self->get_connecting_trains_p(
|
||||||
|
backend_id => $status->{backend_id},
|
||||||
eva => $status->{cancellation}{dep_eva},
|
eva => $status->{cancellation}{dep_eva},
|
||||||
destination_name => $status->{cancellation}{arr_name}
|
destination_name => $status->{cancellation}{arr_name}
|
||||||
)->then(
|
)->then(
|
||||||
|
@ -563,14 +507,63 @@ sub status_card {
|
||||||
sub geolocation {
|
sub geolocation {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
my $lon = $self->param('lon');
|
my $lon = $self->param('lon');
|
||||||
my $lat = $self->param('lat');
|
my $lat = $self->param('lat');
|
||||||
|
my $backend_id = $self->param('backend') // 0;
|
||||||
|
|
||||||
if ( not $lon or not $lat ) {
|
if ( not $lon or not $lat or $backend_id !~ m{ ^ \d+ $ }x ) {
|
||||||
$self->render( json => { error => 'Invalid lon/lat received' } );
|
$self->render( json => { error => 'Invalid lon/lat received' } );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$self->render_later;
|
|
||||||
|
my $hafas_service
|
||||||
|
= $self->stations->get_hafas_name( backend_id => $backend_id );
|
||||||
|
|
||||||
|
if ($hafas_service) {
|
||||||
|
$self->render_later;
|
||||||
|
|
||||||
|
Travel::Status::DE::HAFAS->new_p(
|
||||||
|
promise => 'Mojo::Promise',
|
||||||
|
user_agent => $self->ua,
|
||||||
|
service => $hafas_service,
|
||||||
|
geoSearch => {
|
||||||
|
lat => $lat,
|
||||||
|
lon => $lon
|
||||||
|
}
|
||||||
|
)->then(
|
||||||
|
sub {
|
||||||
|
my ($hafas) = @_;
|
||||||
|
my @hafas = map {
|
||||||
|
{
|
||||||
|
name => $_->name,
|
||||||
|
eva => $_->eva,
|
||||||
|
distance => $_->distance_m / 1000,
|
||||||
|
hafas => $hafas_service
|
||||||
|
}
|
||||||
|
} $hafas->results;
|
||||||
|
if ( @hafas > 10 ) {
|
||||||
|
@hafas = @hafas[ 0 .. 9 ];
|
||||||
|
}
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
candidates => [@hafas],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)->catch(
|
||||||
|
sub {
|
||||||
|
my ($err) = @_;
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
candidates => [],
|
||||||
|
warning => $err,
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
)->wait;
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
my @iris = map {
|
my @iris = map {
|
||||||
{
|
{
|
||||||
|
@ -580,7 +573,6 @@ sub geolocation {
|
||||||
lon => $_->[0][3],
|
lon => $_->[0][3],
|
||||||
lat => $_->[0][4],
|
lat => $_->[0][4],
|
||||||
distance => $_->[1],
|
distance => $_->[1],
|
||||||
hafas => 0,
|
|
||||||
}
|
}
|
||||||
} Travel::Status::DE::IRIS::Stations::get_station_by_location( $lon,
|
} Travel::Status::DE::IRIS::Stations::get_station_by_location( $lon,
|
||||||
$lat, 10 );
|
$lat, 10 );
|
||||||
|
@ -588,48 +580,12 @@ sub geolocation {
|
||||||
if ( @iris > 5 ) {
|
if ( @iris > 5 ) {
|
||||||
@iris = @iris[ 0 .. 4 ];
|
@iris = @iris[ 0 .. 4 ];
|
||||||
}
|
}
|
||||||
|
$self->render(
|
||||||
|
json => {
|
||||||
|
candidates => [@iris],
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
Travel::Status::DE::HAFAS->new_p(
|
|
||||||
promise => 'Mojo::Promise',
|
|
||||||
user_agent => $self->ua,
|
|
||||||
geoSearch => {
|
|
||||||
lat => $lat,
|
|
||||||
lon => $lon
|
|
||||||
}
|
|
||||||
)->then(
|
|
||||||
sub {
|
|
||||||
my ($hafas) = @_;
|
|
||||||
my @hafas = map {
|
|
||||||
{
|
|
||||||
name => $_->name,
|
|
||||||
eva => $_->eva,
|
|
||||||
distance => $_->distance_m / 1000,
|
|
||||||
hafas => 'DB'
|
|
||||||
}
|
|
||||||
} $hafas->results;
|
|
||||||
if ( @hafas > 10 ) {
|
|
||||||
@hafas = @hafas[ 0 .. 9 ];
|
|
||||||
}
|
|
||||||
my @results = map { $_->[0] }
|
|
||||||
sort { $a->[1] <=> $b->[1] }
|
|
||||||
map { [ $_, $_->{distance} ] } ( @iris, @hafas );
|
|
||||||
$self->render(
|
|
||||||
json => {
|
|
||||||
candidates => [@results],
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)->catch(
|
|
||||||
sub {
|
|
||||||
my ($err) = @_;
|
|
||||||
$self->render(
|
|
||||||
json => {
|
|
||||||
candidates => [@iris],
|
|
||||||
warning => $err,
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
)->wait;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub travel_action {
|
sub travel_action {
|
||||||
|
@ -684,6 +640,7 @@ sub travel_action {
|
||||||
$promise->then(
|
$promise->then(
|
||||||
sub {
|
sub {
|
||||||
return $self->checkin_p(
|
return $self->checkin_p(
|
||||||
|
hafas => $params->{hafas},
|
||||||
station => $params->{station},
|
station => $params->{station},
|
||||||
train_id => $params->{train}
|
train_id => $params->{train}
|
||||||
);
|
);
|
||||||
|
@ -713,8 +670,8 @@ sub travel_action {
|
||||||
my ( $still_checked_in, undef ) = @_;
|
my ( $still_checked_in, undef ) = @_;
|
||||||
if ( my $destination = $params->{dest} ) {
|
if ( my $destination = $params->{dest} ) {
|
||||||
my $station_link = '/s/' . $destination;
|
my $station_link = '/s/' . $destination;
|
||||||
if ( $status->{train_id} =~ m{[|]} ) {
|
if ( $status->{is_hafas} ) {
|
||||||
$station_link .= '?hafas=DB';
|
$station_link .= '?hafas=' . $status->{backend_name};
|
||||||
}
|
}
|
||||||
$self->render(
|
$self->render(
|
||||||
json => {
|
json => {
|
||||||
|
@ -749,8 +706,8 @@ sub travel_action {
|
||||||
sub {
|
sub {
|
||||||
my ( $still_checked_in, $error ) = @_;
|
my ( $still_checked_in, $error ) = @_;
|
||||||
my $station_link = '/s/' . $params->{station};
|
my $station_link = '/s/' . $params->{station};
|
||||||
if ( $status->{train_id} =~ m{[|]} ) {
|
if ( $status->{is_hafas} ) {
|
||||||
$station_link .= '?hafas=DB';
|
$station_link .= '?hafas=' . $status->{backend_name};
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($error) {
|
if ($error) {
|
||||||
|
@ -800,8 +757,12 @@ sub travel_action {
|
||||||
else {
|
else {
|
||||||
my $redir = '/';
|
my $redir = '/';
|
||||||
if ( $status->{checked_in} or $status->{cancelled} ) {
|
if ( $status->{checked_in} or $status->{cancelled} ) {
|
||||||
if ( $status->{train_id} =~ m{[|]} ) {
|
if ( $status->{is_hafas} ) {
|
||||||
$redir = '/s/' . $status->{dep_eva} . '?hafas=DB';
|
$redir
|
||||||
|
= '/s/'
|
||||||
|
. $status->{dep_eva}
|
||||||
|
. '?hafas='
|
||||||
|
. $status->{backend_name};
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$redir = '/s/' . $status->{dep_ds100};
|
$redir = '/s/' . $status->{dep_ds100};
|
||||||
|
@ -818,6 +779,7 @@ sub travel_action {
|
||||||
elsif ( $params->{action} eq 'cancelled_from' ) {
|
elsif ( $params->{action} eq 'cancelled_from' ) {
|
||||||
$self->render_later;
|
$self->render_later;
|
||||||
$self->checkin_p(
|
$self->checkin_p(
|
||||||
|
hafas => $params->{hafas},
|
||||||
station => $params->{station},
|
station => $params->{station},
|
||||||
train_id => $params->{train}
|
train_id => $params->{train}
|
||||||
)->then(
|
)->then(
|
||||||
|
@ -920,7 +882,8 @@ sub station {
|
||||||
my $train = $self->param('train');
|
my $train = $self->param('train');
|
||||||
my $trip_id = $self->param('trip_id');
|
my $trip_id = $self->param('trip_id');
|
||||||
my $timestamp = $self->param('timestamp');
|
my $timestamp = $self->param('timestamp');
|
||||||
my $uid = $self->current_user->{id};
|
my $user = $self->current_user;
|
||||||
|
my $uid = $user->{id};
|
||||||
|
|
||||||
my @timeline = $self->in_transit->get_timeline(
|
my @timeline = $self->in_transit->get_timeline(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
|
@ -928,7 +891,6 @@ sub station {
|
||||||
);
|
);
|
||||||
my %checkin_by_train;
|
my %checkin_by_train;
|
||||||
for my $checkin (@timeline) {
|
for my $checkin (@timeline) {
|
||||||
say $checkin->{train_id};
|
|
||||||
push( @{ $checkin_by_train{ $checkin->{train_id} } }, $checkin );
|
push( @{ $checkin_by_train{ $checkin->{train_id} } }, $checkin );
|
||||||
}
|
}
|
||||||
$self->stash( checkin_by_train => \%checkin_by_train );
|
$self->stash( checkin_by_train => \%checkin_by_train );
|
||||||
|
@ -945,10 +907,12 @@ sub station {
|
||||||
$timestamp = DateTime->now( time_zone => 'Europe/Berlin' );
|
$timestamp = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||||
}
|
}
|
||||||
|
|
||||||
my $use_hafas = $self->param('hafas');
|
my $hafas_service = $self->param('hafas')
|
||||||
|
// ( $user->{backend_hafas} ? $user->{backend_name} : undef );
|
||||||
my $promise;
|
my $promise;
|
||||||
if ($use_hafas) {
|
if ($hafas_service) {
|
||||||
$promise = $self->hafas->get_departures_p(
|
$promise = $self->hafas->get_departures_p(
|
||||||
|
service => $hafas_service,
|
||||||
eva => $station,
|
eva => $station,
|
||||||
timestamp => $timestamp,
|
timestamp => $timestamp,
|
||||||
lookbehind => 30,
|
lookbehind => 30,
|
||||||
|
@ -966,27 +930,21 @@ sub station {
|
||||||
$promise->then(
|
$promise->then(
|
||||||
sub {
|
sub {
|
||||||
my ($status) = @_;
|
my ($status) = @_;
|
||||||
my $api_link;
|
|
||||||
my @results;
|
my @results;
|
||||||
|
|
||||||
my $now = $self->now->epoch;
|
my $now = $self->now->epoch;
|
||||||
my $now_within_range
|
my $now_within_range
|
||||||
= abs( $timestamp->epoch - $now ) < 1800 ? 1 : 0;
|
= abs( $timestamp->epoch - $now ) < 1800 ? 1 : 0;
|
||||||
|
|
||||||
if ($use_hafas) {
|
if ($hafas_service) {
|
||||||
|
|
||||||
my $iris_eva = List::Util::min grep { $_ >= 1000000 }
|
|
||||||
@{ $status->station->{evas} // [] };
|
|
||||||
if ($iris_eva) {
|
|
||||||
$api_link = '/s/' . $iris_eva;
|
|
||||||
}
|
|
||||||
|
|
||||||
@results = map { $_->[0] }
|
@results = map { $_->[0] }
|
||||||
sort { $b->[1] <=> $a->[1] }
|
sort { $b->[1] <=> $a->[1] }
|
||||||
map { [ $_, $_->datetime->epoch ] } $status->results;
|
map { [ $_, $_->datetime->epoch ] } $status->results;
|
||||||
$self->stations->add_meta(
|
$self->stations->add_meta(
|
||||||
eva => $status->station->{eva},
|
eva => $status->station->{eva},
|
||||||
meta => $status->station->{evas} // []
|
meta => $status->station->{evas} // [],
|
||||||
|
hafas => $hafas_service,
|
||||||
);
|
);
|
||||||
$status = {
|
$status = {
|
||||||
station_eva => $status->station->{eva},
|
station_eva => $status->station->{eva},
|
||||||
|
@ -999,8 +957,6 @@ sub station {
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
|
||||||
$api_link = '/s/' . $status->{station_eva} . '?hafas=DB';
|
|
||||||
|
|
||||||
# You can't check into a train which terminates here
|
# You can't check into a train which terminates here
|
||||||
@results = grep { $_->departure } @{ $status->{results} };
|
@results = grep { $_->departure } @{ $status->{results} };
|
||||||
|
|
||||||
|
@ -1029,10 +985,10 @@ sub station {
|
||||||
}
|
}
|
||||||
|
|
||||||
my $connections_p;
|
my $connections_p;
|
||||||
if ( $trip_id and $use_hafas ) {
|
if ( $trip_id and $hafas_service ) {
|
||||||
@results = grep { $_->id eq $trip_id } @results;
|
@results = grep { $_->id eq $trip_id } @results;
|
||||||
}
|
}
|
||||||
elsif ( $train and not $use_hafas ) {
|
elsif ( $train and not $hafas_service ) {
|
||||||
@results
|
@results
|
||||||
= grep { $_->type . ' ' . $_->train_no eq $train } @results;
|
= grep { $_->type . ' ' . $_->train_no eq $train } @results;
|
||||||
}
|
}
|
||||||
|
@ -1044,12 +1000,15 @@ sub station {
|
||||||
$connections_p = $self->get_connecting_trains_p(
|
$connections_p = $self->get_connecting_trains_p(
|
||||||
eva => $user_status->{cancellation}{dep_eva},
|
eva => $user_status->{cancellation}{dep_eva},
|
||||||
destination_name =>
|
destination_name =>
|
||||||
$user_status->{cancellation}{arr_name}
|
$user_status->{cancellation}{arr_name},
|
||||||
|
hafas => $hafas_service,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$connections_p = $self->get_connecting_trains_p(
|
$connections_p = $self->get_connecting_trains_p(
|
||||||
eva => $status->{station_eva} );
|
eva => $status->{station_eva},
|
||||||
|
hafas => $hafas_service
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1059,18 +1018,18 @@ sub station {
|
||||||
my ( $connections_iris, $connections_hafas ) = @_;
|
my ( $connections_iris, $connections_hafas ) = @_;
|
||||||
$self->render(
|
$self->render(
|
||||||
'departures',
|
'departures',
|
||||||
|
user => $user,
|
||||||
|
hafas => $hafas_service,
|
||||||
eva => $status->{station_eva},
|
eva => $status->{station_eva},
|
||||||
datetime => $timestamp,
|
datetime => $timestamp,
|
||||||
now_in_range => $now_within_range,
|
now_in_range => $now_within_range,
|
||||||
results => \@results,
|
results => \@results,
|
||||||
hafas => $use_hafas,
|
|
||||||
station => $status->{station_name},
|
station => $status->{station_name},
|
||||||
related_stations => $status->{related_stations},
|
related_stations => $status->{related_stations},
|
||||||
user_status => $user_status,
|
user_status => $user_status,
|
||||||
can_check_out => $can_check_out,
|
can_check_out => $can_check_out,
|
||||||
connections_iris => $connections_iris,
|
connections_iris => $connections_iris,
|
||||||
connections_hafas => $connections_hafas,
|
connections_hafas => $connections_hafas,
|
||||||
api_link => $api_link,
|
|
||||||
title => "travelynx: $status->{station_name}",
|
title => "travelynx: $status->{station_name}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1078,16 +1037,16 @@ sub station {
|
||||||
sub {
|
sub {
|
||||||
$self->render(
|
$self->render(
|
||||||
'departures',
|
'departures',
|
||||||
|
user => $user,
|
||||||
|
hafas => $hafas_service,
|
||||||
eva => $status->{station_eva},
|
eva => $status->{station_eva},
|
||||||
datetime => $timestamp,
|
datetime => $timestamp,
|
||||||
now_in_range => $now_within_range,
|
now_in_range => $now_within_range,
|
||||||
results => \@results,
|
results => \@results,
|
||||||
hafas => $use_hafas,
|
|
||||||
station => $status->{station_name},
|
station => $status->{station_name},
|
||||||
related_stations => $status->{related_stations},
|
related_stations => $status->{related_stations},
|
||||||
user_status => $user_status,
|
user_status => $user_status,
|
||||||
can_check_out => $can_check_out,
|
can_check_out => $can_check_out,
|
||||||
api_link => $api_link,
|
|
||||||
title => "travelynx: $status->{station_name}",
|
title => "travelynx: $status->{station_name}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1096,16 +1055,16 @@ sub station {
|
||||||
else {
|
else {
|
||||||
$self->render(
|
$self->render(
|
||||||
'departures',
|
'departures',
|
||||||
|
user => $user,
|
||||||
|
hafas => $hafas_service,
|
||||||
eva => $status->{station_eva},
|
eva => $status->{station_eva},
|
||||||
datetime => $timestamp,
|
datetime => $timestamp,
|
||||||
now_in_range => $now_within_range,
|
now_in_range => $now_within_range,
|
||||||
results => \@results,
|
results => \@results,
|
||||||
hafas => $use_hafas,
|
|
||||||
station => $status->{station_name},
|
station => $status->{station_name},
|
||||||
related_stations => $status->{related_stations},
|
related_stations => $status->{related_stations},
|
||||||
user_status => $user_status,
|
user_status => $user_status,
|
||||||
can_check_out => $can_check_out,
|
can_check_out => $can_check_out,
|
||||||
api_link => $api_link,
|
|
||||||
title => "travelynx: $status->{station_name}",
|
title => "travelynx: $status->{station_name}",
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1120,15 +1079,22 @@ sub station {
|
||||||
status => 300,
|
status => 300,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ( $use_hafas and $status and $status->errcode eq 'LOCATION' )
|
elsif ( $hafas_service
|
||||||
|
and $status
|
||||||
|
and $status->errcode eq 'LOCATION' )
|
||||||
{
|
{
|
||||||
$self->hafas->search_location_p( query => $station )->then(
|
$self->hafas->search_location_p(
|
||||||
|
service => $hafas_service,
|
||||||
|
query => $station
|
||||||
|
)->then(
|
||||||
sub {
|
sub {
|
||||||
my ($hafas2) = @_;
|
my ($hafas2) = @_;
|
||||||
my @suggestions = $hafas2->results;
|
my @suggestions = $hafas2->results;
|
||||||
if ( @suggestions == 1 ) {
|
if ( @suggestions == 1 ) {
|
||||||
$self->redirect_to(
|
$self->redirect_to( '/s/'
|
||||||
'/s/' . $suggestions[0]->eva . '?hafas=DB' );
|
. $suggestions[0]->eva
|
||||||
|
. '?hafas='
|
||||||
|
. $hafas_service );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
$self->render(
|
$self->render(
|
||||||
|
@ -1169,17 +1135,7 @@ sub redirect_to_station {
|
||||||
my ($self) = @_;
|
my ($self) = @_;
|
||||||
my $station = $self->param('station');
|
my $station = $self->param('station');
|
||||||
|
|
||||||
if ( my $s = $self->app->stations->search($station) ) {
|
$self->redirect_to("/s/${station}");
|
||||||
if ( $s->{source} == 1 ) {
|
|
||||||
$self->redirect_to("/s/${station}?hafas=DB");
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->redirect_to("/s/${station}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
$self->redirect_to("/s/${station}?hafas=DB");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sub cancelled {
|
sub cancelled {
|
||||||
|
|
|
@ -97,6 +97,7 @@ sub get_departures_p {
|
||||||
: DateTime->now( time_zone => 'Europe/Berlin' )
|
: DateTime->now( time_zone => 'Europe/Berlin' )
|
||||||
)->subtract( minutes => $opt{lookbehind} );
|
)->subtract( minutes => $opt{lookbehind} );
|
||||||
return Travel::Status::DE::HAFAS->new_p(
|
return Travel::Status::DE::HAFAS->new_p(
|
||||||
|
service => $opt{service},
|
||||||
station => $opt{eva},
|
station => $opt{eva},
|
||||||
datetime => $when,
|
datetime => $when,
|
||||||
lookahead => $opt{lookahead} + $opt{lookbehind},
|
lookahead => $opt{lookahead} + $opt{lookbehind},
|
||||||
|
@ -111,6 +112,7 @@ sub search_location_p {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
return Travel::Status::DE::HAFAS->new_p(
|
return Travel::Status::DE::HAFAS->new_p(
|
||||||
|
service => $opt{service},
|
||||||
locationSearch => $opt{query},
|
locationSearch => $opt{query},
|
||||||
cache => $self->{realtime_cache},
|
cache => $self->{realtime_cache},
|
||||||
promise => 'Mojo::Promise',
|
promise => 'Mojo::Promise',
|
||||||
|
@ -128,6 +130,7 @@ sub get_tripid_p {
|
||||||
$train_desc =~ s{^- }{};
|
$train_desc =~ s{^- }{};
|
||||||
|
|
||||||
Travel::Status::DE::HAFAS->new_p(
|
Travel::Status::DE::HAFAS->new_p(
|
||||||
|
service => $opt{service},
|
||||||
journeyMatch => $train_desc,
|
journeyMatch => $train_desc,
|
||||||
datetime => $train->start,
|
datetime => $train->start,
|
||||||
cache => $self->{realtime_cache},
|
cache => $self->{realtime_cache},
|
||||||
|
@ -175,6 +178,7 @@ sub get_journey_p {
|
||||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||||
|
|
||||||
Travel::Status::DE::HAFAS->new_p(
|
Travel::Status::DE::HAFAS->new_p(
|
||||||
|
service => $opt{service},
|
||||||
journey => {
|
journey => {
|
||||||
id => $opt{trip_id},
|
id => $opt{trip_id},
|
||||||
},
|
},
|
||||||
|
@ -212,6 +216,7 @@ sub get_route_p {
|
||||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||||
|
|
||||||
Travel::Status::DE::HAFAS->new_p(
|
Travel::Status::DE::HAFAS->new_p(
|
||||||
|
service => $opt{service},
|
||||||
journey => {
|
journey => {
|
||||||
id => $opt{trip_id},
|
id => $opt{trip_id},
|
||||||
|
|
||||||
|
|
|
@ -9,7 +9,7 @@ use warnings;
|
||||||
|
|
||||||
use 5.020;
|
use 5.020;
|
||||||
|
|
||||||
use Encode qw(encode);
|
use Encode qw(encode);
|
||||||
use Email::Sender::Simple qw(try_to_sendmail);
|
use Email::Sender::Simple qw(try_to_sendmail);
|
||||||
use MIME::Entity;
|
use MIME::Entity;
|
||||||
|
|
||||||
|
|
|
@ -116,6 +116,7 @@ sub get_status_p {
|
||||||
|
|
||||||
my $category = $status->{train}{category};
|
my $category = $status->{train}{category};
|
||||||
my $linename = $status->{train}{lineName};
|
my $linename = $status->{train}{lineName};
|
||||||
|
my $train_no = $status->{train}{journeyNumber};
|
||||||
my $trip_id = $status->{train}{hafasId};
|
my $trip_id = $status->{train}{hafasId};
|
||||||
my ( $train_type, $train_line ) = split( qr{ }, $linename );
|
my ( $train_type, $train_line ) = split( qr{ }, $linename );
|
||||||
$promise->resolve(
|
$promise->resolve(
|
||||||
|
@ -133,6 +134,7 @@ sub get_status_p {
|
||||||
arr_ds100 => $arr_ds100,
|
arr_ds100 => $arr_ds100,
|
||||||
arr_name => $arr_name,
|
arr_name => $arr_name,
|
||||||
trip_id => $trip_id,
|
trip_id => $trip_id,
|
||||||
|
train_no => $train_no,
|
||||||
train_type => $train_type,
|
train_type => $train_type,
|
||||||
line => $linename,
|
line => $linename,
|
||||||
line_no => $train_line,
|
line_no => $train_line,
|
||||||
|
|
|
@ -93,6 +93,7 @@ sub add {
|
||||||
|
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid};
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
my $backend_id = $opt{backend_id};
|
||||||
my $train = $opt{train};
|
my $train = $opt{train};
|
||||||
my $journey = $opt{journey};
|
my $journey = $opt{journey};
|
||||||
my $stop = $opt{stop};
|
my $stop = $opt{stop};
|
||||||
|
@ -103,8 +104,6 @@ sub add {
|
||||||
my $json = JSON->new;
|
my $json = JSON->new;
|
||||||
|
|
||||||
if ($train) {
|
if ($train) {
|
||||||
my $backend_id
|
|
||||||
= $db->select( 'backends', ['id'], { iris => 1 } )->hash->{id};
|
|
||||||
$db->insert(
|
$db->insert(
|
||||||
'in_transit',
|
'in_transit',
|
||||||
{
|
{
|
||||||
|
@ -136,14 +135,6 @@ sub add {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
elsif ( $journey and $stop ) {
|
elsif ( $journey and $stop ) {
|
||||||
my $backend_id = $db->select(
|
|
||||||
'backends',
|
|
||||||
['id'],
|
|
||||||
{
|
|
||||||
hafas => 1,
|
|
||||||
name => 'DB'
|
|
||||||
}
|
|
||||||
)->hash->{id};
|
|
||||||
my @route;
|
my @route;
|
||||||
my $product = $journey->product_at( $stop->loc->eva )
|
my $product = $journey->product_at( $stop->loc->eva )
|
||||||
// $journey->product;
|
// $journey->product;
|
||||||
|
@ -440,17 +431,20 @@ sub get_all_active {
|
||||||
->hashes->each;
|
->hashes->each;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_checkout_station_id {
|
sub get_checkout_ids {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid};
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
|
||||||
my $status = $db->select( 'in_transit', ['checkout_station_id'],
|
my $status = $db->select(
|
||||||
{ user_id => $uid } )->hash;
|
'in_transit',
|
||||||
|
[ 'checkout_station_id', 'backend_id' ],
|
||||||
|
{ user_id => $uid }
|
||||||
|
)->hash;
|
||||||
|
|
||||||
if ($status) {
|
if ($status) {
|
||||||
return $status->{checkout_station_id};
|
return $status->{checkout_station_id}, $status->{backend_id};
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -819,7 +813,6 @@ sub update_arrival_hafas {
|
||||||
my $stop = $opt{stop};
|
my $stop = $opt{stop};
|
||||||
my $json = JSON->new;
|
my $json = JSON->new;
|
||||||
|
|
||||||
# TODO use old rt data if available
|
|
||||||
my @route;
|
my @route;
|
||||||
for my $j_stop ( $journey->route ) {
|
for my $j_stop ( $journey->route ) {
|
||||||
push(
|
push(
|
||||||
|
|
|
@ -545,7 +545,7 @@ sub get {
|
||||||
|
|
||||||
my @select
|
my @select
|
||||||
= (
|
= (
|
||||||
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)
|
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)
|
||||||
);
|
);
|
||||||
my %where = (
|
my %where = (
|
||||||
user_id => $uid,
|
user_id => $uid,
|
||||||
|
@ -606,6 +606,7 @@ sub get {
|
||||||
is_iris => $entry->{is_iris},
|
is_iris => $entry->{is_iris},
|
||||||
is_hafas => $entry->{is_hafas},
|
is_hafas => $entry->{is_hafas},
|
||||||
backend_name => $entry->{backend_name},
|
backend_name => $entry->{backend_name},
|
||||||
|
backend_id => $entry->{backend_id},
|
||||||
type => $entry->{train_type},
|
type => $entry->{train_type},
|
||||||
line => $entry->{train_line},
|
line => $entry->{train_line},
|
||||||
no => $entry->{train_no},
|
no => $entry->{train_no},
|
||||||
|
@ -665,7 +666,10 @@ sub get {
|
||||||
my $rename = $self->{renamed_station};
|
my $rename = $self->{renamed_station};
|
||||||
for my $stop ( @{ $ref->{route} } ) {
|
for my $stop ( @{ $ref->{route} } ) {
|
||||||
if ( $stop->[0] =~ m{^Betriebsstelle nicht bekannt (\d+)$} ) {
|
if ( $stop->[0] =~ m{^Betriebsstelle nicht bekannt (\d+)$} ) {
|
||||||
if ( my $s = $self->{stations}->get_by_eva($1) ) {
|
if ( my $s
|
||||||
|
= $self->{stations}
|
||||||
|
->get_by_eva( $1, backend_id => $ref->{backend_id} ) )
|
||||||
|
{
|
||||||
$stop->[0] = $s->{name};
|
$stop->[0] = $s->{name};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -800,14 +804,14 @@ sub get_oldest_ts {
|
||||||
return undef;
|
return undef;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_latest_checkout_station_id {
|
sub get_latest_checkout_ids {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid};
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
|
||||||
my $res_h = $db->select(
|
my $res_h = $db->select(
|
||||||
'journeys',
|
'journeys',
|
||||||
['checkout_station_id'],
|
[ 'checkout_station_id', 'backend_id', ],
|
||||||
{
|
{
|
||||||
user_id => $uid,
|
user_id => $uid,
|
||||||
cancelled => 0
|
cancelled => 0
|
||||||
|
@ -822,7 +826,7 @@ sub get_latest_checkout_station_id {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
return $res_h->{checkout_station_id};
|
return $res_h->{checkout_station_id}, $res_h->{backend_id};
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_latest_checkout_stations {
|
sub get_latest_checkout_stations {
|
||||||
|
@ -833,7 +837,10 @@ sub get_latest_checkout_stations {
|
||||||
|
|
||||||
my $res = $db->select(
|
my $res = $db->select(
|
||||||
'journeys_str',
|
'journeys_str',
|
||||||
[ 'arr_name', 'arr_eva', 'train_id' ],
|
[
|
||||||
|
'arr_name', 'arr_eva', 'train_id', 'backend_id',
|
||||||
|
'backend_name', 'is_hafas'
|
||||||
|
],
|
||||||
{
|
{
|
||||||
user_id => $uid,
|
user_id => $uid,
|
||||||
cancelled => 0
|
cancelled => 0
|
||||||
|
@ -854,9 +861,10 @@ sub get_latest_checkout_stations {
|
||||||
push(
|
push(
|
||||||
@ret,
|
@ret,
|
||||||
{
|
{
|
||||||
name => $row->{arr_name},
|
name => $row->{arr_name},
|
||||||
eva => $row->{arr_eva},
|
eva => $row->{arr_eva},
|
||||||
hafas => ( $row->{train_id} =~ m{[|]} ? 'DB' : 0 ),
|
hafas => $row->{is_hafas} ? $row->{backend_name} : 0,
|
||||||
|
backend_id => $row->{backend_id},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -1726,28 +1734,29 @@ sub get_stats {
|
||||||
return $stats;
|
return $stats;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_latest_dest_id {
|
sub get_latest_dest_ids {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid};
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
|
||||||
if (
|
if (
|
||||||
my $id = $self->{in_transit}->get_checkout_station_id(
|
my ( $id, $backend_id ) = $self->{in_transit}->get_checkout_ids(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
db => $db
|
db => $db
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
return $id;
|
return ( $id, $backend_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
return $self->get_latest_checkout_station_id(
|
return $self->get_latest_checkout_ids(
|
||||||
uid => $uid,
|
uid => $uid,
|
||||||
db => $db
|
db => $db
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Returns a listref of {eva, name} hashrefs for the specified backend.
|
||||||
sub get_connection_targets {
|
sub get_connection_targets {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
|
@ -1756,21 +1765,29 @@ sub get_connection_targets {
|
||||||
// DateTime->now( time_zone => 'Europe/Berlin' )->subtract( months => 4 );
|
// DateTime->now( time_zone => 'Europe/Berlin' )->subtract( months => 4 );
|
||||||
my $db = $opt{db} //= $self->{pg}->db;
|
my $db = $opt{db} //= $self->{pg}->db;
|
||||||
my $min_count = $opt{min_count} // 3;
|
my $min_count = $opt{min_count} // 3;
|
||||||
|
my $dest_id = $opt{eva};
|
||||||
|
|
||||||
if ( $opt{destination_name} ) {
|
if ( $opt{destination_name} ) {
|
||||||
return (
|
return [ { eva => $opt{eva}, name => $opt{destination_name} } ];
|
||||||
[],
|
|
||||||
[ { eva => $opt{eva}, name => $opt{destination_name} } ]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
my $dest_id = $opt{eva} // $self->get_latest_dest_id(%opt);
|
my $backend_id = $opt{backend_id};
|
||||||
|
|
||||||
if ( not $dest_id ) {
|
if ( not $dest_id ) {
|
||||||
return ( [], [] );
|
( $dest_id, $backend_id ) = $self->get_latest_dest_ids(%opt);
|
||||||
}
|
}
|
||||||
|
|
||||||
my $dest_ids = [ $dest_id, $self->{stations}->get_meta( eva => $dest_id ) ];
|
if ( not $dest_id ) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
my $dest_ids = [
|
||||||
|
$dest_id,
|
||||||
|
$self->{stations}->get_meta(
|
||||||
|
eva => $dest_id,
|
||||||
|
backend_id => $backend_id,
|
||||||
|
)
|
||||||
|
];
|
||||||
|
|
||||||
my $res = $db->select(
|
my $res = $db->select(
|
||||||
'journeys',
|
'journeys',
|
||||||
|
@ -1778,7 +1795,8 @@ sub get_connection_targets {
|
||||||
{
|
{
|
||||||
user_id => $uid,
|
user_id => $uid,
|
||||||
checkin_station_id => $dest_ids,
|
checkin_station_id => $dest_ids,
|
||||||
real_departure => { '>', $threshold }
|
real_departure => { '>', $threshold },
|
||||||
|
backend_id => $opt{backend_id},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
group_by => ['checkout_station_id'],
|
group_by => ['checkout_station_id'],
|
||||||
|
@ -1788,8 +1806,11 @@ sub get_connection_targets {
|
||||||
my @destinations
|
my @destinations
|
||||||
= $res->hashes->grep( sub { shift->{count} >= $min_count } )
|
= $res->hashes->grep( sub { shift->{count} >= $min_count } )
|
||||||
->map( sub { shift->{dest} } )->each;
|
->map( sub { shift->{dest} } )->each;
|
||||||
@destinations = $self->{stations}->get_by_evas(@destinations);
|
@destinations = $self->{stations}->get_by_evas(
|
||||||
return ( $dest_ids, \@destinations );
|
backend_id => $opt{backend_id},
|
||||||
|
evas => [@destinations]
|
||||||
|
);
|
||||||
|
return @destinations;
|
||||||
}
|
}
|
||||||
|
|
||||||
sub update_visibility {
|
sub update_visibility {
|
||||||
|
|
|
@ -14,38 +14,125 @@ sub new {
|
||||||
return bless( \%opt, $class );
|
return bless( \%opt, $class );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub get_backend_id {
|
||||||
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
|
if ( $opt{iris} ) {
|
||||||
|
|
||||||
|
# special case
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if ( $opt{hafas} and $self->{backend_id}{hafas}{ $opt{hafas} } ) {
|
||||||
|
return $self->{backend_id}{hafas}{ $opt{hafas} };
|
||||||
|
}
|
||||||
|
|
||||||
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
my $backend_id = 0;
|
||||||
|
|
||||||
|
if ( $opt{hafas} ) {
|
||||||
|
$backend_id = $db->select(
|
||||||
|
'backends',
|
||||||
|
['id'],
|
||||||
|
{
|
||||||
|
hafas => 1,
|
||||||
|
name => $opt{hafas}
|
||||||
|
}
|
||||||
|
)->hash->{id};
|
||||||
|
$self->{backend_id}{hafas}{ $opt{hafas} } = $backend_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $backend_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_hafas_name {
|
||||||
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
|
if ( exists $self->{hafas_name}{ $opt{backend_id} } ) {
|
||||||
|
return $self->{hafas_name}{ $opt{backend_id} };
|
||||||
|
}
|
||||||
|
|
||||||
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
my $hafas_name;
|
||||||
|
my $ret = $db->select(
|
||||||
|
'backends',
|
||||||
|
['name'],
|
||||||
|
{
|
||||||
|
hafas => 1,
|
||||||
|
id => $opt{backend_id},
|
||||||
|
}
|
||||||
|
)->hash;
|
||||||
|
|
||||||
|
if ($ret) {
|
||||||
|
$hafas_name = $ret->{name};
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{hafas_name}{ $opt{backend_id} } = $hafas_name;
|
||||||
|
|
||||||
|
return $hafas_name;
|
||||||
|
}
|
||||||
|
|
||||||
|
sub get_backends {
|
||||||
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
|
||||||
|
my $res = $opt{db}->select( 'backends', [ 'id', 'name', 'iris', 'hafas' ] );
|
||||||
|
my @ret;
|
||||||
|
|
||||||
|
while ( my $row = $res->hash ) {
|
||||||
|
push(
|
||||||
|
@ret,
|
||||||
|
{
|
||||||
|
id => $row->{id},
|
||||||
|
name => $row->{name},
|
||||||
|
iris => $row->{iris},
|
||||||
|
hafas => $row->{hafas},
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return @ret;
|
||||||
|
}
|
||||||
|
|
||||||
sub add_or_update {
|
sub add_or_update {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
my $stop = $opt{stop};
|
my $stop = $opt{stop};
|
||||||
my $loc = $stop->loc;
|
my $loc = $stop->loc;
|
||||||
my $source = 1;
|
$opt{db} //= $self->{pg}->db;
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
|
||||||
|
|
||||||
if ( my $s = $self->get_by_eva( $loc->eva, db => $db ) ) {
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
if ( $source == 1 and $s->{source} == 0 and not $s->{archived} ) {
|
|
||||||
return;
|
if (
|
||||||
}
|
my $s = $self->get_by_eva(
|
||||||
$db->update(
|
$loc->eva,
|
||||||
|
db => $opt{db},
|
||||||
|
backend_id => $opt{backend_id}
|
||||||
|
)
|
||||||
|
)
|
||||||
|
{
|
||||||
|
$opt{db}->update(
|
||||||
'stations',
|
'stations',
|
||||||
{
|
{
|
||||||
name => $loc->name,
|
name => $loc->name,
|
||||||
lat => $loc->lat,
|
lat => $loc->lat,
|
||||||
lon => $loc->lon,
|
lon => $loc->lon,
|
||||||
source => $source,
|
|
||||||
archived => 0
|
archived => 0
|
||||||
},
|
},
|
||||||
{ eva => $loc->eva }
|
{
|
||||||
|
eva => $loc->eva,
|
||||||
|
source => $opt{backend_id}
|
||||||
|
}
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
$db->insert(
|
$opt{db}->insert(
|
||||||
'stations',
|
'stations',
|
||||||
{
|
{
|
||||||
eva => $loc->eva,
|
eva => $loc->eva,
|
||||||
name => $loc->name,
|
name => $loc->name,
|
||||||
lat => $loc->lat,
|
lat => $loc->lat,
|
||||||
lon => $loc->lon,
|
lon => $loc->lon,
|
||||||
source => $source,
|
source => $opt{backend_id},
|
||||||
archived => 0
|
archived => 0
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
@ -53,17 +140,20 @@ sub add_or_update {
|
||||||
|
|
||||||
sub add_meta {
|
sub add_meta {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
|
||||||
my $eva = $opt{eva};
|
my $eva = $opt{eva};
|
||||||
my @meta = @{ $opt{meta} };
|
my @meta = @{ $opt{meta} };
|
||||||
|
|
||||||
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
for my $meta (@meta) {
|
for my $meta (@meta) {
|
||||||
if ( $meta != $eva ) {
|
if ( $meta != $eva ) {
|
||||||
$db->insert(
|
$opt{db}->insert(
|
||||||
'related_stations',
|
'related_stations',
|
||||||
{
|
{
|
||||||
eva => $eva,
|
eva => $eva,
|
||||||
meta => $meta
|
meta => $meta,
|
||||||
|
backend_id => $opt{backend_id},
|
||||||
},
|
},
|
||||||
{ on_conflict => undef }
|
{ on_conflict => undef }
|
||||||
);
|
);
|
||||||
|
@ -82,7 +172,16 @@ sub get_meta {
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
my $eva = $opt{eva};
|
my $eva = $opt{eva};
|
||||||
|
|
||||||
my $res = $db->select( 'related_stations', ['meta'], { eva => $eva } );
|
$opt{backend_id} //= $self->get_backend_id( %opt, db => $db );
|
||||||
|
|
||||||
|
my $res = $db->select(
|
||||||
|
'related_stations',
|
||||||
|
['meta'],
|
||||||
|
{
|
||||||
|
eva => $eva,
|
||||||
|
backend_id => $opt{backend_id}
|
||||||
|
}
|
||||||
|
);
|
||||||
my @ret;
|
my @ret;
|
||||||
|
|
||||||
while ( my $row = $res->hash ) {
|
while ( my $row = $res->hash ) {
|
||||||
|
@ -93,9 +192,12 @@ sub get_meta {
|
||||||
}
|
}
|
||||||
|
|
||||||
sub get_for_autocomplete {
|
sub get_for_autocomplete {
|
||||||
my ($self) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my $res = $self->{pg}->db->select( 'stations', ['name'] );
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
|
my $res = $self->{pg}
|
||||||
|
->db->select( 'stations', ['name'], { source => $opt{backend_id} } );
|
||||||
my %ret;
|
my %ret;
|
||||||
|
|
||||||
while ( my $row = $res->hash ) {
|
while ( my $row = $res->hash ) {
|
||||||
|
@ -113,18 +215,34 @@ sub get_by_eva {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
return $db->select( 'stations', '*', { eva => $eva } )->hash;
|
return $opt{db}->select(
|
||||||
|
'stations',
|
||||||
|
'*',
|
||||||
|
{
|
||||||
|
eva => $eva,
|
||||||
|
source => $opt{backend_id}
|
||||||
|
}
|
||||||
|
)->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Fast
|
# Fast
|
||||||
sub get_by_evas {
|
sub get_by_evas {
|
||||||
my ( $self, @evas ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
|
|
||||||
my @ret
|
$opt{db} //= $self->{pg}->db;
|
||||||
= $self->{pg}->db->select( 'stations', '*', { eva => { '=', \@evas } } )
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
->hashes->each;
|
|
||||||
|
my @ret = $self->{pg}->db->select(
|
||||||
|
'stations',
|
||||||
|
'*',
|
||||||
|
{
|
||||||
|
eva => { '=', $opt{evas} },
|
||||||
|
source => $opt{backend_id}
|
||||||
|
}
|
||||||
|
)->hashes->each;
|
||||||
return @ret;
|
return @ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -132,10 +250,18 @@ sub get_by_evas {
|
||||||
sub get_by_name {
|
sub get_by_name {
|
||||||
my ( $self, $name, %opt ) = @_;
|
my ( $self, $name, %opt ) = @_;
|
||||||
|
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
return $db->select( 'stations', '*', { name => $name }, { limit => 1 } )
|
return $opt{db}->select(
|
||||||
->hash;
|
'stations',
|
||||||
|
'*',
|
||||||
|
{
|
||||||
|
name => $name,
|
||||||
|
source => $opt{backend_id}
|
||||||
|
},
|
||||||
|
{ limit => 1 }
|
||||||
|
)->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Slow
|
# Slow
|
||||||
|
@ -152,16 +278,27 @@ sub get_by_names {
|
||||||
sub get_by_ds100 {
|
sub get_by_ds100 {
|
||||||
my ( $self, $ds100, %opt ) = @_;
|
my ( $self, $ds100, %opt ) = @_;
|
||||||
|
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
return $db->select( 'stations', '*', { ds100 => $ds100 }, { limit => 1 } )
|
return $opt{db}->select(
|
||||||
->hash;
|
'stations',
|
||||||
|
'*',
|
||||||
|
{
|
||||||
|
ds100 => $ds100,
|
||||||
|
source => $opt{backend_id}
|
||||||
|
},
|
||||||
|
{ limit => 1 }
|
||||||
|
)->hash;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Can be slow
|
# Can be slow
|
||||||
sub search {
|
sub search {
|
||||||
my ( $self, $identifier, %opt ) = @_;
|
my ( $self, $identifier, %opt ) = @_;
|
||||||
|
|
||||||
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
$opt{backend_id} //= $self->get_backend_id(%opt);
|
||||||
|
|
||||||
if ( $identifier =~ m{ ^ \d+ $ }x ) {
|
if ( $identifier =~ m{ ^ \d+ $ }x ) {
|
||||||
return $self->get_by_eva( $identifier, %opt )
|
return $self->get_by_eva( $identifier, %opt )
|
||||||
// $self->get_by_ds100( $identifier, %opt )
|
// $self->get_by_ds100( $identifier, %opt )
|
||||||
|
|
|
@ -224,6 +224,7 @@ sub get_pushable_accounts {
|
||||||
join in_transit_str as i on t.user_id = i.user_id
|
join in_transit_str as i on t.user_id = i.user_id
|
||||||
where t.push_sync = True
|
where t.push_sync = True
|
||||||
and i.arr_eva is not null
|
and i.arr_eva is not null
|
||||||
|
and i.backend_id <= 1
|
||||||
and i.cancelled = False
|
and i.cancelled = False
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
|
@ -205,6 +205,13 @@ sub get_privacy_by {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sub set_backend {
|
||||||
|
my ( $self, %opt ) = @_;
|
||||||
|
$opt{db} //= $self->{pg}->db;
|
||||||
|
|
||||||
|
$opt{db}->update('users', {backend_id => $opt{backend_id}}, {id => $opt{uid}});
|
||||||
|
}
|
||||||
|
|
||||||
sub set_privacy {
|
sub set_privacy {
|
||||||
my ( $self, %opt ) = @_;
|
my ( $self, %opt ) = @_;
|
||||||
my $db = $opt{db} // $self->{pg}->db;
|
my $db = $opt{db} // $self->{pg}->db;
|
||||||
|
@ -401,12 +408,13 @@ sub get {
|
||||||
my $uid = $opt{uid};
|
my $uid = $opt{uid};
|
||||||
|
|
||||||
my $user = $db->select(
|
my $user = $db->select(
|
||||||
'users',
|
'users_with_backend',
|
||||||
'id, name, status, public_level, email, '
|
'id, name, status, public_level, email, '
|
||||||
. 'accept_follows, notifications, '
|
. 'accept_follows, notifications, '
|
||||||
. 'extract(epoch from registered_at) as registered_at_ts, '
|
. 'extract(epoch from registered_at) as registered_at_ts, '
|
||||||
. 'extract(epoch from last_seen) as last_seen_ts, '
|
. 'extract(epoch from last_seen) as last_seen_ts, '
|
||||||
. 'extract(epoch from deletion_requested) as deletion_requested_ts',
|
. 'extract(epoch from deletion_requested) as deletion_requested_ts, '
|
||||||
|
. 'backend_id, backend_name, hafas',
|
||||||
{ id => $uid }
|
{ id => $uid }
|
||||||
)->hash;
|
)->hash;
|
||||||
if ($user) {
|
if ($user) {
|
||||||
|
@ -443,6 +451,9 @@ sub get {
|
||||||
time_zone => 'Europe/Berlin'
|
time_zone => 'Europe/Berlin'
|
||||||
)
|
)
|
||||||
: undef,
|
: undef,
|
||||||
|
backend_id => $user->{backend_id},
|
||||||
|
backend_name => $user->{backend_name},
|
||||||
|
backend_hafas => $user->{hafas},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return undef;
|
return undef;
|
||||||
|
|
|
@ -62,7 +62,8 @@ $(document).ready(function() {
|
||||||
};
|
};
|
||||||
|
|
||||||
const processLocation = function(loc) {
|
const processLocation = function(loc) {
|
||||||
$.post('/geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude}, processResult);
|
const backend = $('div.geolocation > button').data('backend');
|
||||||
|
$.post('/geolocation', {lon: loc.coords.longitude, lat: loc.coords.latitude, backend: backend}, processResult);
|
||||||
};
|
};
|
||||||
|
|
||||||
const processError = function(error) {
|
const processError = function(error) {
|
||||||
|
|
|
@ -191,6 +191,7 @@ function tvly_reg_handlers() {
|
||||||
var link = $(this);
|
var link = $(this);
|
||||||
var req = {
|
var req = {
|
||||||
action: 'checkin',
|
action: 'checkin',
|
||||||
|
hafas: link.data('hafas'),
|
||||||
station: link.data('station'),
|
station: link.data('station'),
|
||||||
train: link.data('train'),
|
train: link.data('train'),
|
||||||
dest: link.data('dest'),
|
dest: link.data('dest'),
|
||||||
|
@ -202,6 +203,7 @@ function tvly_reg_handlers() {
|
||||||
var link = $(this);
|
var link = $(this);
|
||||||
var req = {
|
var req = {
|
||||||
action: 'checkout',
|
action: 'checkout',
|
||||||
|
hafas: link.data('hafas'),
|
||||||
station: link.data('station'),
|
station: link.data('station'),
|
||||||
force: link.data('force'),
|
force: link.data('force'),
|
||||||
};
|
};
|
||||||
|
@ -232,6 +234,7 @@ function tvly_reg_handlers() {
|
||||||
var link = $(this);
|
var link = $(this);
|
||||||
var req = {
|
var req = {
|
||||||
action: 'cancelled_from',
|
action: 'cancelled_from',
|
||||||
|
hafas: link.data('hafas'),
|
||||||
station: link.data('station'),
|
station: link.data('station'),
|
||||||
ts: link.data('ts'),
|
ts: link.data('ts'),
|
||||||
train: link.data('train'),
|
train: link.data('train'),
|
||||||
|
@ -242,6 +245,7 @@ function tvly_reg_handlers() {
|
||||||
var link = $(this);
|
var link = $(this);
|
||||||
var req = {
|
var req = {
|
||||||
action: 'cancelled_to',
|
action: 'cancelled_to',
|
||||||
|
hafas: link.data('hafas'),
|
||||||
station: link.data('station'),
|
station: link.data('station'),
|
||||||
force: true,
|
force: true,
|
||||||
};
|
};
|
||||||
|
|
|
@ -341,6 +341,7 @@ $t->app->in_transit->add(
|
||||||
departure_eva => 8000001,
|
departure_eva => 8000001,
|
||||||
train => $train_dep,
|
train => $train_dep,
|
||||||
route => [],
|
route => [],
|
||||||
|
backend_id => $t->app->stations->get_backend_id( iris => 1 ),
|
||||||
);
|
);
|
||||||
$t->app->in_transit->set_arrival_eva(
|
$t->app->in_transit->set_arrival_eva(
|
||||||
uid => $uid1,
|
uid => $uid1,
|
||||||
|
|
|
@ -303,6 +303,7 @@ $t->app->in_transit->add(
|
||||||
departure_eva => 8000001,
|
departure_eva => 8000001,
|
||||||
train => $train_dep,
|
train => $train_dep,
|
||||||
route => [],
|
route => [],
|
||||||
|
backend_id => $t->app->stations->get_backend_id( iris => 1 ),
|
||||||
);
|
);
|
||||||
$t->app->in_transit->set_arrival_eva(
|
$t->app->in_transit->set_arrival_eva(
|
||||||
uid => $uid1,
|
uid => $uid1,
|
||||||
|
|
|
@ -266,6 +266,7 @@ $t->app->in_transit->add(
|
||||||
departure_eva => 8000001,
|
departure_eva => 8000001,
|
||||||
train => $train_dep,
|
train => $train_dep,
|
||||||
route => [],
|
route => [],
|
||||||
|
backend_id => $t->app->stations->get_backend_id( iris => 1 ),
|
||||||
);
|
);
|
||||||
$t->app->in_transit->set_arrival_eva(
|
$t->app->in_transit->set_arrival_eva(
|
||||||
uid => $uid1,
|
uid => $uid1,
|
||||||
|
|
|
@ -343,9 +343,14 @@
|
||||||
% else {
|
% else {
|
||||||
% $url = $url . $journey->{train_type} . ' ' . $journey->{train_no} . '/' . $journey->{sched_departure}->epoch . '000?station=' . $journey->{dep_eva};
|
% $url = $url . $journey->{train_type} . ' ' . $journey->{train_no} . '/' . $journey->{sched_departure}->epoch . '000?station=' . $journey->{dep_eva};
|
||||||
% }
|
% }
|
||||||
<a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left" aria-hidden="true">timeline</i> Zuglauf</a>
|
% if ($journey->{backend_id} <= 1) {
|
||||||
|
<a style="margin-right: 0;" href="<%= $url %>"><i class="material-icons left" aria-hidden="true">timeline</i> Zuglauf</a>
|
||||||
|
% }
|
||||||
|
% else {
|
||||||
|
|
||||||
|
% }
|
||||||
% if ($journey->{extra_data}{trip_id}) {
|
% if ($journey->{extra_data}{trip_id}) {
|
||||||
<a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} =~ s{#}{%23}gr %>/<%= $journey->{train_line} || 0 %>?from=<%= $journey->{dep_name} %>&to=<%= $journey->{arr_name} %>&dark=<%= (session('theme') and session('theme') eq 'dark') ? 1 : 0 %>"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
|
<a class="right" style="margin-right: 0;" href="https://dbf.finalrewind.org/map/<%= $journey->{extra_data}{trip_id} =~ s{#}{%23}gr %>/<%= $journey->{train_line} || 0 %>?hafas=<%= $journey->{backend_name} // 'DB' %>&from=<%= $journey->{dep_name} %>&to=<%= $journey->{arr_name} %>&dark=<%= (session('theme') and session('theme') eq 'dark') ? 1 : 0 %>"><i class="material-icons left" aria-hidden="true">map</i> Karte</a>
|
||||||
% }
|
% }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<span class="card-title">Ausgecheckt</span>
|
<span class="card-title">Ausgecheckt</span>
|
||||||
<p>Aus
|
<p>Aus
|
||||||
%= include '_format_train', journey => $journey
|
%= include '_format_train', journey => $journey
|
||||||
bis <a href="/s/<%= $journey->{arr_eva} %>?hafas=<%= $journey->{train_id} =~ m{[|]} ? 1 : 0 %>"><%= $journey->{arr_name} %></a></p>
|
bis <a href="/s/<%= $journey->{arr_eva} %>?hafas=<%= $journey->{is_hafas} ? $journey->{backend_name} : q{} %>"><%= $journey->{arr_name} %></a></p>
|
||||||
% if (@{stash('connections_iris') // [] } or @{stash('connections_hafas') // []}) {
|
% if (@{stash('connections_iris') // [] } or @{stash('connections_hafas') // []}) {
|
||||||
<span class="card-title" style="margin-top: 2ex;">Verbindungen</span>
|
<span class="card-title" style="margin-top: 2ex;">Verbindungen</span>
|
||||||
<p>Fahrt auswählen zum Einchecken mit Zielwahl.</p>
|
<p>Fahrt auswählen zum Einchecken mit Zielwahl.</p>
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<ul class="collection departures connections">
|
<ul class="collection departures connections">
|
||||||
% for my $res (@{$connections}) {
|
% for my $res (@{$connections}) {
|
||||||
% my ($train, $via, $via_arr) = @{$res};
|
% my ($train, $via, $via_arr, $hafas_service) = @{$res};
|
||||||
% $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{};
|
% $via_arr = $via_arr ? $via_arr->strftime('%H:%M') : q{};
|
||||||
% my $row_class = '';
|
% my $row_class = '';
|
||||||
% my $link_class = 'action-checkin';
|
% my $link_class = 'action-checkin';
|
||||||
|
@ -10,6 +10,7 @@
|
||||||
% }
|
% }
|
||||||
% if ($checkin_from) {
|
% if ($checkin_from) {
|
||||||
<li class="collection-item <%= $row_class %> <%= $link_class %>"
|
<li class="collection-item <%= $row_class %> <%= $link_class %>"
|
||||||
|
data-hafas="<%= $hafas_service %>"
|
||||||
data-station="<%= $train->station_eva %>"
|
data-station="<%= $train->station_eva %>"
|
||||||
data-train="<%= $train->id %>"
|
data-train="<%= $train->id %>"
|
||||||
data-ts="<%= ($train->sched_datetime // $train->datetime)->epoch %>"
|
data-ts="<%= ($train->sched_datetime // $train->datetime)->epoch %>"
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
</li>
|
</li>
|
||||||
% }
|
% }
|
||||||
<li class="collection-item <%= $link_class %> <%= $row_class %>"
|
<li class="collection-item <%= $link_class %> <%= $row_class %>"
|
||||||
|
data-hafas="<%= $hafas %>"
|
||||||
data-station="<%= $result->station_eva %>"
|
data-station="<%= $result->station_eva %>"
|
||||||
data-train="<%= $result->id %>"
|
data-train="<%= $result->id %>"
|
||||||
data-ts="<%= ($result->sched_datetime // $result->datetime)->epoch %>"
|
data-ts="<%= ($result->sched_datetime // $result->datetime)->epoch %>"
|
||||||
|
|
|
@ -30,6 +30,11 @@
|
||||||
"actionTime" : 1234567, (UNIX-Timestamp des letzten Checkin/Checkout)<br/>
|
"actionTime" : 1234567, (UNIX-Timestamp des letzten Checkin/Checkout)<br/>
|
||||||
"checkedIn" : true / false,<br/>
|
"checkedIn" : true / false,<br/>
|
||||||
"comment": "Kommentar",<br/>
|
"comment": "Kommentar",<br/>
|
||||||
|
"backend": {<br/>
|
||||||
|
"id": 1,<br/>
|
||||||
|
"name": "DB",<br/>
|
||||||
|
"type": "HAFAS",<br/>
|
||||||
|
},<br/>
|
||||||
"fromStation" : { (letzter Checkin)<br/>
|
"fromStation" : { (letzter Checkin)<br/>
|
||||||
"name" : "Essen Hbf",<br/>
|
"name" : "Essen Hbf",<br/>
|
||||||
"ds100" : "EE", (ggf. null)<br/>
|
"ds100" : "EE", (ggf. null)<br/>
|
||||||
|
@ -122,6 +127,7 @@
|
||||||
{<br/>
|
{<br/>
|
||||||
"token" : "<%= $uid %>-<%= $token->{travel} // 'TOKEN' %>",<br/>
|
"token" : "<%= $uid %>-<%= $token->{travel} // 'TOKEN' %>",<br/>
|
||||||
"action" : "checkin",<br/>
|
"action" : "checkin",<br/>
|
||||||
|
"hafas" : "DB", (HAFAS-Instanz – Default: Deutsche Bahn)<br/>
|
||||||
"train" : {<br/>
|
"train" : {<br/>
|
||||||
"journeyID" : "1|1426396|4|80|19082023",<br/>
|
"journeyID" : "1|1426396|4|80|19082023",<br/>
|
||||||
}<br/>
|
}<br/>
|
||||||
|
|
|
@ -1,26 +1,27 @@
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s12">
|
<div class="col s8">
|
||||||
<h2>
|
<strong style="font-size: 120%;">
|
||||||
<i class="material-icons " aria-hidden="true"><%= param('hafas') ? 'directions' : 'train' %></i>
|
|
||||||
<%= $station %>
|
<%= $station %>
|
||||||
</h2>
|
</strong>
|
||||||
% for my $related_station (sort { $a->{name} cmp $b->{name} } @{$related_stations}) {
|
% for my $related_station (sort { $a->{name} cmp $b->{name} } @{$related_stations}) {
|
||||||
+ <%= $related_station->{name} %> <br/>
|
+ <%= $related_station->{name} %> <br/>
|
||||||
% }
|
% }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
<div class="col s4 center-align">
|
||||||
% if ($api_link) {
|
% my $self_link = url_for('sstation', station => param('station'));
|
||||||
<div class="row">
|
% if (param('hafas')) {
|
||||||
<div class="col s12 center-align">
|
<span class="btn-small disabled"><i class="material-icons left" aria-hidden="true">directions</i> <%= param('hafas') %> (HAFAS)</span>
|
||||||
% if (param('hafas')) {
|
% }
|
||||||
<a href="<%= $api_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">train</i>zum Schienenverkehr</a>
|
% else {
|
||||||
% }
|
% if ($user->{backend_id}) {
|
||||||
% else {
|
<a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">directions</i><%= $user->{backend_name} %> (<%= $user->{backend_hafas} ? 'HAFAS' : q{} %>)</a>
|
||||||
<a href="<%= $api_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">directions</i>zum Nahverkehr</a>
|
% }
|
||||||
% }
|
% else {
|
||||||
|
<a href="/account/select_backend?redirect_to=<%= $self_link %>" class="btn-small"><i class="material-icons left" aria-hidden="true">train</i>DB (IRIS-TTS)</a>
|
||||||
|
% }
|
||||||
|
% }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
% }
|
|
||||||
|
|
||||||
% my $have_connections = 0;
|
% my $have_connections = 0;
|
||||||
% if ($user_status->{checked_in}) {
|
% if ($user_status->{checked_in}) {
|
||||||
|
@ -40,10 +41,10 @@
|
||||||
</div>
|
</div>
|
||||||
<div class="card-action">
|
<div class="card-action">
|
||||||
% if ($can_check_out) {
|
% if ($can_check_out) {
|
||||||
<a class="action-undo" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
|
<a class="action-undo" data-hafas="<%= param('hafas') // q{} %>" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
|
||||||
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
|
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
|
||||||
</a>
|
</a>
|
||||||
<a class="action-checkout right" data-station="<%= $eva %>" data-force="1">
|
<a class="action-checkout right" data-hafas="<%= param('hafas') // q{} %>" data-station="<%= $eva %>" data-force="1">
|
||||||
Hier auschecken
|
Hier auschecken
|
||||||
</a>
|
</a>
|
||||||
% }
|
% }
|
||||||
|
@ -51,7 +52,7 @@
|
||||||
<a class="action-undo" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
|
<a class="action-undo" data-id="in_transit" data-checkints="<%= $user_status->{timestamp}->epoch %>" style="margin-right: 0;">
|
||||||
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
|
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
|
||||||
</a>
|
</a>
|
||||||
<a class="action-checkout right" data-station="<%= $eva %>" data-force="1">
|
<a class="action-checkout right" data-hafas="<%= param('hafas') // q{} %>" data-station="<%= $eva %>" data-force="1">
|
||||||
<i class="material-icons left" aria-hidden="true">gps_off</i>
|
<i class="material-icons left" aria-hidden="true">gps_off</i>
|
||||||
Hier auschecken
|
Hier auschecken
|
||||||
</a>
|
</a>
|
||||||
|
@ -139,7 +140,7 @@
|
||||||
</p>
|
</p>
|
||||||
% if (not $user_status->{checked_in} or ($can_check_out and $user_status->{arr_eva} and $user_status->{arrival_countdown} <= 0)) {
|
% if (not $user_status->{checked_in} or ($can_check_out and $user_status->{arr_eva} and $user_status->{arrival_countdown} <= 0)) {
|
||||||
% if ($hafas) {
|
% if ($hafas) {
|
||||||
%= include '_departures_hafas', results => $results;
|
%= include '_departures_hafas', results => $results, hafas => $hafas;
|
||||||
% }
|
% }
|
||||||
% else {
|
% else {
|
||||||
%= include '_departures_iris', results => $results;
|
%= include '_departures_iris', results => $results;
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
<ul class="suggestions">
|
<ul class="suggestions">
|
||||||
% for my $suggestion (@{$suggestions // []}) {
|
% for my $suggestion (@{$suggestions // []}) {
|
||||||
<li><a href="<%= url_for('station' => $suggestion->{eva}) . (param('hafas') ? '?hafas=DB' : q{}) %>"><%= $suggestion->{name} %></a></li>
|
<li><a href="<%= url_for('station' => $suggestion->{eva}) . (param('hafas') ? '?hafas=' . param('hafas') : q{}) %>"><%= $suggestion->{name} %></a></li>
|
||||||
% }
|
% }
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -20,8 +20,15 @@
|
||||||
Timestamp:
|
Timestamp:
|
||||||
%= DateTime->now(time_zone => 'Europe/Berlin')->strftime("%d/%b/%Y:%H:%M:%S %z")
|
%= DateTime->now(time_zone => 'Europe/Berlin')->strftime("%d/%b/%Y:%H:%M:%S %z")
|
||||||
<br/><br/>
|
<br/><br/>
|
||||||
Message:
|
% if (ref($exception)) {
|
||||||
%= ref($exception) ? (split(qr{\n}, $exception->message))[0] : $exception
|
Trace:<br/>
|
||||||
|
% for my $line (split(qr{\n}, $exception->message)) {
|
||||||
|
<%= $line %><br/>
|
||||||
|
% }
|
||||||
|
% }
|
||||||
|
% else {
|
||||||
|
Message: <%= $exception %>
|
||||||
|
% }
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
% if (is_user_authenticated()) {
|
% if (is_user_authenticated()) {
|
||||||
% my $status = stash('user_status');
|
% my $status = stash('user_status');
|
||||||
|
% my $user = stash('user');
|
||||||
% if (stash('error')) {
|
% if (stash('error')) {
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col s12">
|
<div class="col s12">
|
||||||
|
@ -51,32 +52,40 @@
|
||||||
% if ( @{stash('timeline') // [] } ) {
|
% if ( @{stash('timeline') // [] } ) {
|
||||||
%= include '_timeline_link', timeline => stash('timeline')
|
%= include '_timeline_link', timeline => stash('timeline')
|
||||||
% }
|
% }
|
||||||
<div class="card">
|
%= form_for 'list_departures' => begin
|
||||||
<div class="card-content">
|
<div class="card">
|
||||||
<span class="card-title">Hallo, <%= current_user->{name} %>!</span>
|
<div class="card-content">
|
||||||
<p>Du bist gerade nicht eingecheckt.</p>
|
<span class="card-title">Hallo, <%= $user->{name} %>!</span>
|
||||||
<div class="geolocation" data-recent="<%= join('|', map { $_->{eva} . ';' . $_->{name} . ';' . $_->{hafas} } @{stash('recent_targets') // []} ) %>">
|
<p>Du bist gerade nicht eingecheckt.</p>
|
||||||
<button class="btn waves-effect waves-light btn-flat">Stationen in der Umgebung abfragen</button>
|
<p>
|
||||||
</div>
|
<div class="geolocation" data-recent="<%= join('|', map { $_->{eva} . ';' . $_->{name} . ';' . $_->{hafas} } @{stash('recent_targets') // []} ) %>" data-backend=<%= $user->{backend_id} %>">
|
||||||
%= form_for 'list_departures' => begin
|
<button class="btn waves-effect waves-light btn-flat">Stationen in der Umgebung abfragen</button>
|
||||||
|
</div>
|
||||||
<div class="input-field">
|
<div class="input-field">
|
||||||
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', autocomplete => 'off', required => undef
|
%= text_field 'station', id => 'station', class => 'autocomplete contrast-color-text', autocomplete => 'off', required => undef
|
||||||
<label for="station">Manuelle Eingabe</label>
|
<label for="station">Manuelle Eingabe</label>
|
||||||
</div>
|
</div>
|
||||||
<div class="center-align">
|
</p>
|
||||||
<button class="btn waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
|
</div>
|
||||||
<i class="material-icons left" aria-hidden="true">send</i>
|
<div class="card-action">
|
||||||
Abfahrten
|
% if ($user->{backend_id}) {
|
||||||
</button>
|
<a href="/account/select_backend?redirect_to=/" class="btn btn-flat"><i class="material-icons left" aria-hidden="true">directions</i><%= $user->{backend_name} %> (<%= $user->{backend_hafas} ? 'HAFAS' : q{} %>)</a>
|
||||||
</div>
|
% }
|
||||||
%= end
|
% else {
|
||||||
|
<a href="/account/select_backend?redirect_to=/" class="btn btn-flat"><i class="material-icons left" aria-hidden="true">train</i>DB (IRIS-TTS)</a>
|
||||||
|
% }
|
||||||
|
<button class="btn right waves-effect waves-light btn-flat" type="submit" name="action" value="departures">
|
||||||
|
<i class="material-icons left" aria-hidden="true">send</i>
|
||||||
|
Abfahrten
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
%= end
|
||||||
% }
|
% }
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 style="margin-left: 0.75rem;">Letzte Fahrten</h2>
|
<h2 style="margin-left: 0.75rem;">Letzte Fahrten</h2>
|
||||||
%= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => current_user->{id}, limit => 5, with_datetime => 1)];
|
%= include '_history_trains', date_format => '%d.%m.%Y', journeys => [journeys->get(uid => $user->{id}, limit => 5, with_datetime => 1)];
|
||||||
% }
|
% }
|
||||||
% else {
|
% else {
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
@ -62,7 +62,7 @@
|
||||||
%= javascript "/static/${av}/js/geolocation${min}.js"
|
%= javascript "/static/${av}/js/geolocation${min}.js"
|
||||||
% }
|
% }
|
||||||
% if (stash('with_autocomplete')) {
|
% if (stash('with_autocomplete')) {
|
||||||
%= javascript "/dyn/${av}/autocomplete.js", defer => undef
|
%= javascript "/dyn/${av}/autocomplete.js?backend_id=" . (stash('backend_id') // 1), defer => undef
|
||||||
% }
|
% }
|
||||||
% if (stash('with_map')) {
|
% if (stash('with_map')) {
|
||||||
%= javascript "/static/${av}/leaflet/leaflet.js"
|
%= javascript "/static/${av}/leaflet/leaflet.js"
|
||||||
|
|
34
templates/select_backend.html.ep
Normal file
34
templates/select_backend.html.ep
Normal file
|
@ -0,0 +1,34 @@
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12">
|
||||||
|
<h2>Backend auswählen</h2>
|
||||||
|
<p style="text-align: justify;">
|
||||||
|
Das ausgewählte Backend bestimmt die Datenquelle für Fahrten in travelynx.
|
||||||
|
<strong>DB (HAFAS)</strong> ist eine gute Wahl für Nah-, Regional- und Fernverkehr in Deutschland und (teilweise) Nachbarländern.
|
||||||
|
<strong>IRIS-TTS</strong> unterstützt ausschließlich Schienenverkehr; im Gegensatz zum HAFAS sind hier detaillierte Verspätungsgründe verfügbar.
|
||||||
|
Die restlichen Backends können sich für Fahrten außerhalb Deutschlands sowie in einzelnen innerdeutschen Verkehrsverbünden lohnen.
|
||||||
|
Fahrten im Ausland fehlen im DB-HAFAS oft; Fahrten im Inland können mit spezifischen Backends genauere Daten haben – z.B. liefert das AVV-HAFAS im Gegensatz zum DB-HAFAS Kartendaten für dortige Buslinien.
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
%= form_for '/account/select_backend' => (method => 'POST') => begin
|
||||||
|
% if (stash('redirect_to')) {
|
||||||
|
%= hidden_field 'redirect_to' => stash('redirect_to')
|
||||||
|
% }
|
||||||
|
% for my $backend (@{ stash('backends') // [] }) {
|
||||||
|
<div class="row">
|
||||||
|
<div class="col s12 m4 l4 center-align">
|
||||||
|
<button class="btn waves-effect waves-light <%= $backend->{id} == $user->{backend_id} ? 'disabled' : q{} %>" type="submit" name="backend" value="<%= $backend->{id} %>">
|
||||||
|
<%= $backend->{name} %> (<%= $backend->{type} %>)
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<div class="col s12 m8 l8">
|
||||||
|
% if ($backend->{longname}) {
|
||||||
|
<%= $backend->{longname} %>
|
||||||
|
% }
|
||||||
|
% if ($backend->{id} == $user->{backend_id}) {
|
||||||
|
(aktuell ausgewählt)
|
||||||
|
% }
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
% }
|
||||||
|
%= end
|
|
@ -157,26 +157,21 @@
|
||||||
<div>
|
<div>
|
||||||
<label>
|
<label>
|
||||||
%= check_box toot => 1
|
%= check_box toot => 1
|
||||||
<span>… Checkin auf Mastodon veröffentlichen</span>
|
<span>… Checkin im Fediverse veröffentlichen</span>
|
||||||
</label>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label>
|
|
||||||
%= check_box tweet => 1
|
|
||||||
<span>… Checkin auf Twitter veröffentlichen</span>
|
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
<p>Die Synchronisierung erfolgt spätestens drei Minuten nach der
|
<p>Die Synchronisierung erfolgt spätestens drei Minuten nach der
|
||||||
Zielwahl. Beachte, dass die Synchronisierung travelynx
|
Zielwahl. Es werden ausschließlich Checkins mittels
|
||||||
→ Träwelling unabhängig von der eingestellten Sichtbarkeit
|
DB (IRIS-TTS) und DB (HAFAS) synchornisiert. Beachte, dass
|
||||||
des Checkins erfolgt. travelynx reicht die Sichtbarkeit
|
die Synchronisierung travelynx → Träwelling unabhängig von
|
||||||
aber an Träwelling weiter.
|
der eingestellten Sichtbarkeit des Checkins erfolgt.
|
||||||
Träwelling-Checkins können von travelynx aktuell nicht
|
travelynx reicht die Sichtbarkeit aber an Träwelling
|
||||||
rückgängig gemacht werden. Eine nachträgliche Änderung der
|
weiter. Träwelling-Checkins können von travelynx aktuell
|
||||||
Zielstation wird nicht übernommen. Mastodon und Twitter beziehen
|
nicht rückgängig gemacht werden. Eine nachträgliche
|
||||||
sich auf die in den <a
|
Änderung der Zielstation wird nicht übernommen. Fediverse
|
||||||
|
bezieht sich auf den in den <a
|
||||||
href="https://traewelling.de/settings">Träwelling-Einstellungen</a>
|
href="https://traewelling.de/settings">Träwelling-Einstellungen</a>
|
||||||
verknüpften Accounts.</p>
|
verknüpften Account.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="input-field col s12">
|
<div class="input-field col s12">
|
||||||
<div>
|
<div>
|
||||||
|
|
|
@ -5,9 +5,13 @@
|
||||||
Travelynx kann anhand deiner vergangenen Fahrten Verbindungen zum
|
Travelynx kann anhand deiner vergangenen Fahrten Verbindungen zum
|
||||||
Einchecken vorschlagen. Fährst zu z.B regelmäßig von Dortmund Hbf
|
Einchecken vorschlagen. Fährst zu z.B regelmäßig von Dortmund Hbf
|
||||||
nach Essen Hbf, werden dir in Dortmund bevorzugt Fahrten angezeigt, die
|
nach Essen Hbf, werden dir in Dortmund bevorzugt Fahrten angezeigt, die
|
||||||
Essen passieren. Bei Auswahl dieser wird nicht nur in die Fahrt eingecheckt,
|
Essen passieren. Bei Auswahl dieser wird nicht nur in die Fahrt eingecheckt,
|
||||||
sondern auch direkt Essen Hbf als Ziel eingetragen.
|
sondern auch direkt Essen Hbf als Ziel eingetragen.
|
||||||
<p/>
|
<p/>
|
||||||
|
<p>
|
||||||
|
Beachte, dass nicht alle von travelynx unterstützten Backends die
|
||||||
|
für dieses Feature notwendigen Daten bereitstellen.
|
||||||
|
</p>
|
||||||
<!-- <p>
|
<!-- <p>
|
||||||
Falls du das nicht nützlich findest oder nicht möchtest, dass deine
|
Falls du das nicht nützlich findest oder nicht möchtest, dass deine
|
||||||
regelmäßigen (Anschluss-)Züge auf deinem Bildschirm sichtbar sind,
|
regelmäßigen (Anschluss-)Züge auf deinem Bildschirm sichtbar sind,
|
||||||
|
|
Loading…
Reference in a new issue