summaryrefslogtreecommitdiff
path: root/lib/Travelynx.pm
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2020-09-30 19:12:29 +0200
committerDaniel Friesel <derf@finalrewind.org>2020-09-30 19:12:29 +0200
commit89e709d8d593939ab528b81d125fd37d303c4fa9 (patch)
tree574a0fbe6b6b0849d878c228e1f6b84e2c29d878 /lib/Travelynx.pm
parent952740969ca9fa74c893dfe0961d3ae55ec9e85b (diff)
Allow linking a Träwelling account, auto-sync Träwelling→travelynx
travelynx→Träwelling is still work-in-progress Squashed commit of the following: commit 97faa6e2e6c8d20fba30f2d0f6e78187ceeb72e6 Author: Daniel Friesel <derf@finalrewind.org> Date: Wed Sep 30 18:50:05 2020 +0200 improve traewelling log and tx handling commit 487d7dd728b9d45b731bdc7098cf3358ea2e206e Author: Daniel Friesel <derf@finalrewind.org> Date: Wed Sep 30 18:02:41 2020 +0200 add missing traewelling template commit 0148da2f48d9a52dcddc0ab81f83d8f8ac3062ab Author: Daniel Friesel <derf@finalrewind.org> Date: Wed Sep 30 18:02:35 2020 +0200 improve traewelling pull sync commit 4861a9750f9f2d7621043361d0af6b0a8869a0df Author: Daniel Friesel <derf@finalrewind.org> Date: Tue Sep 29 22:14:24 2020 +0200 wip checkin from traewelling commit f6aeb6f06998a2a7a80f63a7b1b688b1a26b66bd Author: Daniel Friesel <derf@finalrewind.org> Date: Tue Sep 29 18:37:53 2020 +0200 refactor traewelling integration. login and logout are less of a hack now. checkin and checkout are not supported at the moment.
Diffstat (limited to 'lib/Travelynx.pm')
-rwxr-xr-xlib/Travelynx.pm251
1 files changed, 228 insertions, 23 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm
index 4f58f57..ab1f7ef 100755
--- a/lib/Travelynx.pm
+++ b/lib/Travelynx.pm
@@ -20,7 +20,9 @@ use Travelynx::Helper::DBDB;
use Travelynx::Helper::HAFAS;
use Travelynx::Helper::IRIS;
use Travelynx::Helper::Sendmail;
+use Travelynx::Helper::Traewelling;
use Travelynx::Model::Journeys;
+use Travelynx::Model::Traewelling;
use Travelynx::Model::Users;
use XML::LibXML;
@@ -293,6 +295,26 @@ sub startup {
);
$self->helper(
+ traewelling => sub {
+ my ($self) = @_;
+ state $trwl = Travelynx::Model::Traewelling->new( pg => $self->pg );
+ }
+ );
+
+ $self->helper(
+ traewelling_api => sub {
+ my ($self) = @_;
+ state $trwl_api = Travelynx::Helper::Traewelling->new(
+ log => $self->app->log,
+ model => $self->traewelling,
+ root_url => $self->url_for('/')->to_abs,
+ user_agent => $self->ua,
+ version => $self->app->config->{version},
+ );
+ }
+ );
+
+ $self->helper(
journeys => sub {
my ($self) = @_;
state $journeys = Travelynx::Model::Journeys->new(
@@ -389,9 +411,12 @@ sub startup {
$self->helper(
'checkin' => sub {
- my ( $self, $station, $train_id, $uid ) = @_;
+ my ( $self, %opt ) = @_;
- $uid //= $self->current_user->{id};
+ my $station = $opt{station};
+ my $train_id = $opt{train_id};
+ my $uid = $opt{uid} // $self->current_user->{id};
+ my $db = $opt{db} // $self->pg->db;
my $status = $self->iris->get_departures(
station => $station,
@@ -409,7 +434,7 @@ sub startup {
}
else {
- my $user = $self->get_user_status($uid);
+ my $user = $self->get_user_status( $uid, $db );
if ( $user->{checked_in} or $user->{cancelled} ) {
if ( $user->{train_id} eq $train_id
@@ -420,12 +445,17 @@ sub startup {
}
# Otherwise, someone forgot to check out first
- $self->checkout( $station, 1, $uid );
+ $self->checkout(
+ station => $station,
+ force => 1,
+ uid => $uid,
+ db => $db
+ );
}
eval {
my $json = JSON->new;
- $self->pg->db->insert(
+ $db->insert(
'in_transit',
{
user_id => $uid,
@@ -459,8 +489,12 @@ sub startup {
"Checkin($uid): INSERT failed: $@");
return ( undef, 'INSERT failed: ' . $@ );
}
- $self->add_route_timestamps( $uid, $train, 1 );
- $self->run_hook( $uid, 'checkin' );
+ if ( not $opt{in_transaction} ) {
+
+ # mustn't be called during a transaction
+ $self->add_route_timestamps( $uid, $train, 1 );
+ $self->run_hook( $uid, 'checkin' );
+ }
return ( $train, undef );
}
}
@@ -547,16 +581,19 @@ sub startup {
$self->helper(
'checkout' => sub {
- my ( $self, $station, $force, $uid ) = @_;
+ my ( $self, %opt ) = @_;
- my $db = $self->pg->db;
- my $status = $self->iris->get_departures(
+ my $station = $opt{station};
+ my $force = $opt{force};
+ my $uid = $opt{uid};
+ my $db = $opt{db} // $self->pg->db;
+ my $status = $self->iris->get_departures(
station => $station,
lookbehind => 120,
lookahead => 120
);
$uid //= $self->current_user->{id};
- my $user = $self->get_user_status($uid);
+ my $user = $self->get_user_status( $uid, $db );
my $train_id = $user->{train_id};
if ( not $user->{checked_in} and not $user->{cancelled} ) {
@@ -671,7 +708,11 @@ sub startup {
}
}
if ( not $force ) {
- $self->run_hook( $uid, 'update' );
+
+ # mustn't be called during a transaction
+ if ( not $opt{in_transaction} ) {
+ $self->run_hook( $uid, 'update' );
+ }
return ( 1, undef );
}
}
@@ -680,7 +721,10 @@ sub startup {
eval {
- my $tx = $db->begin;
+ my $tx;
+ if ( not $opt{in_transaction} ) {
+ $tx = $db->begin;
+ }
if ( defined $train and not $train->arrival and not $force ) {
my $train_no = $train->train_no;
@@ -778,7 +822,9 @@ sub startup {
);
}
- $tx->commit;
+ if ( not $opt{in_transaction} ) {
+ $tx->commit;
+ }
};
if ($@) {
@@ -787,27 +833,33 @@ sub startup {
}
if ( $has_arrived or $force ) {
- $self->run_hook( $uid, 'checkout' );
+ if ( not $opt{in_transaction} ) {
+ $self->run_hook( $uid, 'checkout' );
+ }
return ( 0, undef );
}
- $self->run_hook( $uid, 'update' );
- $self->add_route_timestamps( $uid, $train, 0 );
+ if ( not $opt{in_transaction} ) {
+ $self->run_hook( $uid, 'update' );
+ $self->add_route_timestamps( $uid, $train, 0 );
+ }
return ( 1, undef );
}
);
$self->helper(
'update_in_transit_comment' => sub {
- my ( $self, $comment, $uid ) = @_;
+ my ( $self, $comment, $uid, $db ) = @_;
$uid //= $self->current_user->{id};
+ $db //= $self->pg->db;
- my $status = $self->pg->db->select( 'in_transit', ['user_data'],
- { user_id => $uid } )->expand->hash;
+ my $status
+ = $db->select( 'in_transit', ['user_data'], { user_id => $uid } )
+ ->expand->hash;
if ( not $status ) {
return;
}
$status->{user_data}{comment} = $comment;
- $self->pg->db->update(
+ $db->update(
'in_transit',
{ user_data => JSON->new->encode( $status->{user_data} ) },
{ user_id => $uid }
@@ -1872,11 +1924,11 @@ sub startup {
$self->helper(
'get_user_status' => sub {
- my ( $self, $uid ) = @_;
+ my ( $self, $uid, $db ) = @_;
$uid //= $self->current_user->{id};
+ $db //= $self->pg->db;
- my $db = $self->pg->db;
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
my $epoch = $now->epoch;
@@ -2316,6 +2368,157 @@ sub startup {
);
$self->helper(
+ 'traewelling_to_travelynx' => sub {
+ my ( $self, %opt ) = @_;
+ my $traewelling = $opt{traewelling};
+ my $user_data = $opt{user_data};
+ my $uid = $user_data->{user_id};
+
+ if ( not $traewelling->{checkin}
+ or $self->now->epoch - $traewelling->{checkin}->epoch > 900 )
+ {
+ $self->log->debug("... not checked in");
+ return;
+ }
+ if ( $traewelling->{status_id}
+ and $user_data->{data}{latest_pull_status_id}
+ and $traewelling->{status_id}
+ == $user_data->{data}{latest_pull_status_id} )
+ {
+ $self->log->debug("... already handled");
+ return;
+ }
+ $self->log->debug("... checked in");
+ my $user_status = $self->get_user_status($uid);
+ if ( $user_status->{checked_in} ) {
+ $self->log->debug(
+ "... also checked in via travelynx. aborting.");
+ return;
+ }
+
+ if ( $traewelling->{category}
+ !~ m{^ (?: nationalExpress | regional | suburban ) $ }x )
+ {
+ $self->log->debug("... status is not a train");
+ $self->traewelling->log(
+ uid => $uid,
+ message =>
+"$traewelling->{line} nach $traewelling->{arr_name} ist keine Zugfahrt",
+ status_id => $traewelling->{status_id},
+ );
+ $self->traewelling->set_latest_pull_status_id(
+ uid => $uid,
+ status_id => $traewelling->{status_id}
+ );
+ return;
+ }
+
+ my $dep = $self->iris->get_departures(
+ station => $traewelling->{dep_eva},
+ lookbehind => 60,
+ lookahead => 40
+ );
+ if ( $dep->{errstr} ) {
+ $self->traewelling->log(
+ uid => $uid,
+ message =>
+"Fehler bei $traewelling->{line} nach $traewelling->{arr_name}: $dep->{errstr}",
+ status_id => $traewelling->{status_id},
+ is_error => 1,
+ );
+ return;
+ }
+ my ( $train_ref, $train_id );
+ for my $train ( @{ $dep->{results} } ) {
+ if ( $train->line ne $traewelling->{line} ) {
+ next;
+ }
+ if ( not $train->sched_departure
+ or $train->sched_departure->epoch
+ != $traewelling->{dep_dt}->epoch )
+ {
+ next;
+ }
+ if (
+ not List::Util::first { $_ eq $traewelling->{arr_name} }
+ $train->route_post
+ )
+ {
+ next;
+ }
+ $train_id = $train->train_id;
+ $train_ref = $train;
+ last;
+ }
+ if ($train_id) {
+ $self->log->debug("... found train: $train_id");
+
+ my $db = $self->pg->db;
+ my $tx = $db->begin;
+
+ my ( undef, $err ) = $self->checkin(
+ station => $traewelling->{dep_eva},
+ train_id => $train_id,
+ uid => $uid,
+ in_transaction => 1,
+ db => $db
+ );
+
+ if ( not $err ) {
+ ( undef, $err ) = $self->checkout(
+ station => $traewelling->{arr_eva},
+ train_id => 0,
+ uid => $uid,
+ in_transaction => 1,
+ db => $db
+ );
+ if ( not $err ) {
+ $self->log->debug("... success!");
+ if ( $traewelling->{message} ) {
+ $self->update_in_transit_comment(
+ $traewelling->{message},
+ $uid, $db );
+ }
+ $self->traewelling->log(
+ uid => $uid,
+ db => $db,
+ message =>
+"Eingecheckt in $traewelling->{line} nach $traewelling->{arr_name}",
+ status_id => $traewelling->{status_id},
+ );
+ $self->traewelling->set_latest_pull_status_id(
+ uid => $uid,
+ status_id => $traewelling->{status_id},
+ db => $db
+ );
+
+ $tx->commit;
+ }
+ }
+ if ($err) {
+ $self->log->debug("... error: $err");
+ $self->traewelling->log(
+ uid => $uid,
+ message =>
+"Fehler bei $traewelling->{line} nach $traewelling->{arr_name}: $err",
+ status_id => $traewelling->{status_id},
+ is_error => 1
+ );
+ }
+ }
+ else {
+ $self->traewelling->log(
+ uid => $uid,
+ message =>
+"$traewelling->{line} nach $traewelling->{arr_name} nicht gefunden",
+ status_id => $traewelling->{status_id},
+ is_error => 1
+ );
+ }
+ }
+ );
+
+ $self->helper(
'journeys_to_map_data' => sub {
my ( $self, %opt ) = @_;
@@ -2647,6 +2850,7 @@ sub startup {
$authed_r->get('/account')->to('account#account');
$authed_r->get('/account/privacy')->to('account#privacy');
$authed_r->get('/account/hooks')->to('account#webhook');
+ $authed_r->get('/account/traewelling')->to('traewelling#settings');
$authed_r->get('/account/insight')->to('account#insight');
$authed_r->get('/ajax/status_card.html')->to('traveling#status_card');
$authed_r->get('/cancelled')->to('traveling#cancelled');
@@ -2668,6 +2872,7 @@ sub startup {
$authed_r->get('/confirm_mail/:token')->to('account#confirm_mail');
$authed_r->post('/account/privacy')->to('account#privacy');
$authed_r->post('/account/hooks')->to('account#webhook');
+ $authed_r->post('/account/traewelling')->to('traewelling#settings');
$authed_r->post('/account/insight')->to('account#insight');
$authed_r->post('/journey/add')->to('traveling#add_journey_form');
$authed_r->post('/journey/comment')->to('traveling#comment_form');