89e709d8d5
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.
332 lines
7.5 KiB
Perl
332 lines
7.5 KiB
Perl
package Travelynx::Helper::Traewelling;
|
|
|
|
use strict;
|
|
use warnings;
|
|
use 5.020;
|
|
|
|
use Mojo::Promise;
|
|
|
|
sub new {
|
|
my ( $class, %opt ) = @_;
|
|
|
|
my $version = $opt{version};
|
|
|
|
$opt{header}
|
|
= { 'User-Agent' =>
|
|
"travelynx/${version} on $opt{root_url} +https://finalrewind.org/projects/travelynx"
|
|
};
|
|
|
|
return bless( \%opt, $class );
|
|
}
|
|
|
|
sub get_status_p {
|
|
my ( $self, %opt ) = @_;
|
|
|
|
my $username = $opt{username};
|
|
my $token = $opt{token};
|
|
my $promise = Mojo::Promise->new;
|
|
|
|
my $header = {
|
|
'User-Agent' => $self->{header}{'User-Agent'},
|
|
'Authorization' => "Bearer $token",
|
|
};
|
|
|
|
$self->{user_agent}->request_timeout(20)
|
|
->get_p( "https://traewelling.de/api/v0/user/${username}" => $header )
|
|
->then(
|
|
sub {
|
|
my ($tx) = @_;
|
|
if ( my $err = $tx->error ) {
|
|
my $err_msg = "HTTP $err->{code} $err->{message}";
|
|
$promise->reject($err_msg);
|
|
return;
|
|
}
|
|
else {
|
|
if ( my $status = $tx->result->json->{statuses}{data}[0] ) {
|
|
my $strp = DateTime::Format::Strptime->new(
|
|
pattern => '%Y-%m-%dT%H:%M:%S.000000Z',
|
|
time_zone => 'UTC',
|
|
);
|
|
my $status_id = $status->{id};
|
|
my $message = $status->{body};
|
|
my $checkin_at
|
|
= $strp->parse_datetime( $status->{created_at} );
|
|
|
|
my $dep_dt = $strp->parse_datetime(
|
|
$status->{train_checkin}{departure} );
|
|
my $arr_dt = $strp->parse_datetime(
|
|
$status->{train_checkin}{arrival} );
|
|
|
|
my $dep_eva
|
|
= $status->{train_checkin}{origin}{ibnr};
|
|
my $arr_eva
|
|
= $status->{train_checkin}{destination}{ibnr};
|
|
|
|
my $dep_name
|
|
= $status->{train_checkin}{origin}{name};
|
|
my $arr_name
|
|
= $status->{train_checkin}{destination}{name};
|
|
|
|
my $category
|
|
= $status->{train_checkin}{hafas_trip}{category};
|
|
my $trip_id
|
|
= $status->{train_checkin}{hafas_trip}{trip_id};
|
|
my $linename
|
|
= $status->{train_checkin}{hafas_trip}{linename};
|
|
my ( $train_type, $train_line ) = split( qr{ }, $linename );
|
|
$promise->resolve(
|
|
{
|
|
status_id => $status_id,
|
|
message => $message,
|
|
checkin => $checkin_at,
|
|
dep_dt => $dep_dt,
|
|
dep_eva => $dep_eva,
|
|
dep_name => $dep_name,
|
|
arr_dt => $arr_dt,
|
|
arr_eva => $arr_eva,
|
|
arr_name => $arr_name,
|
|
trip_id => $trip_id,
|
|
train_type => $train_type,
|
|
line => $linename,
|
|
line_no => $train_line,
|
|
category => $category,
|
|
}
|
|
);
|
|
return;
|
|
}
|
|
else {
|
|
$promise->reject("unknown error");
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
)->catch(
|
|
sub {
|
|
my ($err) = @_;
|
|
$promise->reject($err);
|
|
return;
|
|
}
|
|
)->wait;
|
|
|
|
return $promise;
|
|
}
|
|
|
|
sub get_user_p {
|
|
my ( $self, $uid, $token ) = @_;
|
|
my $ua = $self->{user_agent}->request_timeout(20);
|
|
|
|
my $header = {
|
|
'User-Agent' => $self->{header}{'User-Agent'},
|
|
'Authorization' => "Bearer $token",
|
|
};
|
|
my $promise = Mojo::Promise->new;
|
|
|
|
$ua->get_p( "https://traewelling.de/api/v0/getuser" => $header )->then(
|
|
sub {
|
|
my ($tx) = @_;
|
|
if ( my $err = $tx->error ) {
|
|
my $err_msg
|
|
= "HTTP $err->{code} $err->{message} bei Abfrage der Nutzerdaten";
|
|
$promise->reject($err_msg);
|
|
return;
|
|
}
|
|
else {
|
|
my $user_data = $tx->result->json;
|
|
$self->{model}->set_user(
|
|
uid => $uid,
|
|
trwl_id => $user_data->{id},
|
|
screen_name => $user_data->{name},
|
|
user_name => $user_data->{username},
|
|
);
|
|
$promise->resolve;
|
|
return;
|
|
}
|
|
}
|
|
)->catch(
|
|
sub {
|
|
my ($err) = @_;
|
|
$promise->reject("$err bei Abfrage der Nutzerdaten");
|
|
return;
|
|
}
|
|
)->wait;
|
|
|
|
return $promise;
|
|
}
|
|
|
|
sub login_p {
|
|
my ( $self, %opt ) = @_;
|
|
|
|
my $uid = $opt{uid};
|
|
my $email = $opt{email};
|
|
my $password = $opt{password};
|
|
|
|
my $ua = $self->{user_agent}->request_timeout(20);
|
|
|
|
my $request = {
|
|
email => $email,
|
|
password => $password,
|
|
};
|
|
|
|
my $promise = Mojo::Promise->new;
|
|
my $token;
|
|
|
|
$ua->post_p(
|
|
"https://traewelling.de/api/v0/auth/login" => $self->{header} =>
|
|
json => $request )->then(
|
|
sub {
|
|
my ($tx) = @_;
|
|
if ( my $err = $tx->error ) {
|
|
my $err_msg = "HTTP $err->{code} $err->{message} bei Login";
|
|
$promise->reject($err_msg);
|
|
return;
|
|
}
|
|
else {
|
|
$token = $tx->result->json->{token};
|
|
$self->{model}->link(
|
|
uid => $uid,
|
|
email => $email,
|
|
token => $token
|
|
);
|
|
return $self->get_user_p( $uid, $token );
|
|
}
|
|
}
|
|
)->then(
|
|
sub {
|
|
$promise->resolve;
|
|
return;
|
|
}
|
|
)->catch(
|
|
sub {
|
|
my ($err) = @_;
|
|
if ($token) {
|
|
|
|
# We have a token, but couldn't complete the login. For now, we
|
|
# solve this by logging out and invalidating the token.
|
|
$self->logout_p(
|
|
uid => $uid,
|
|
token => $token
|
|
)->finally(
|
|
sub {
|
|
$promise->reject($err);
|
|
return;
|
|
}
|
|
);
|
|
}
|
|
else {
|
|
$promise->reject($err);
|
|
}
|
|
return;
|
|
}
|
|
)->wait;
|
|
|
|
return $promise;
|
|
}
|
|
|
|
sub logout_p {
|
|
my ( $self, %opt ) = @_;
|
|
|
|
my $uid = $opt{uid};
|
|
my $token = $opt{token};
|
|
|
|
my $ua = $self->{user_agent}->request_timeout(20);
|
|
|
|
my $header = {
|
|
'User-Agent' => $self->{header}{'User-Agent'},
|
|
'Authorization' => "Bearer $token",
|
|
};
|
|
my $request = {};
|
|
|
|
$self->{model}->unlink( uid => $uid );
|
|
|
|
my $promise = Mojo::Promise->new;
|
|
|
|
$ua->post_p(
|
|
"https://traewelling.de/api/v0/auth/logout" => $header => json =>
|
|
$request )->then(
|
|
sub {
|
|
my ($tx) = @_;
|
|
if ( my $err = $tx->error ) {
|
|
my $err_msg = "HTTP $err->{code} $err->{message}";
|
|
$promise->reject($err_msg);
|
|
return;
|
|
}
|
|
else {
|
|
$promise->resolve;
|
|
return;
|
|
}
|
|
}
|
|
)->catch(
|
|
sub {
|
|
my ($err) = @_;
|
|
$promise->reject($err);
|
|
return;
|
|
}
|
|
)->wait;
|
|
|
|
return $promise;
|
|
}
|
|
|
|
sub checkin {
|
|
my ( $self, $uid ) = @_;
|
|
if ( my $token = $self->get_traewelling_push_token($uid) ) {
|
|
my $user = $self->get_user_status;
|
|
|
|
# TODO delete previous traewelling status if the train's destination has been changed
|
|
# TODO delete traewelling status when undoing a travelynx checkin
|
|
if ( $user->{checked_in} and $user->{extra_data}{trip_id} ) {
|
|
my $traewelling = $self->{model}->get($uid);
|
|
if ( $traewelling->{data}{trip_id} eq $user->{extra_data}{trip_id} )
|
|
{
|
|
return;
|
|
}
|
|
my $header = {
|
|
'User-Agent' => 'travelynx/' . $self->{version},
|
|
'Authorization' => "Bearer $token",
|
|
};
|
|
|
|
my $request = {
|
|
tripID => $user->{extra_data}{trip_id},
|
|
start => q{} . $user->{dep_eva},
|
|
destination => q{} . $user->{arr_eva},
|
|
};
|
|
my $trip_req = sprintf(
|
|
"tripID=%s&lineName=%s%%20%s&start=%s",
|
|
$user->{extra_data}{trip_id}, $user->{train_type},
|
|
$user->{train_line} // $user->{train_no}, $user->{dep_eva}
|
|
);
|
|
$self->{user_agent}->request_timeout(20)
|
|
->get_p(
|
|
"https://traewelling.de/api/v0/trains/trip?$trip_req" =>
|
|
$header )->then(
|
|
sub {
|
|
return $self->{user_agent}->request_timeout(20)
|
|
->post_p(
|
|
"https://traewelling.de/api/v0/trains/checkin" =>
|
|
$header => json => $request );
|
|
}
|
|
)->then(
|
|
sub {
|
|
my ($tx) = @_;
|
|
if ( my $err = $tx->error ) {
|
|
my $err_msg = "HTTP $err->{code} $err->{message}";
|
|
$self->mark_trwl_checkin_error( $uid, $user, $err_msg );
|
|
}
|
|
else {
|
|
# TODO check for traewelling error ("error" key in response)
|
|
# TODO store ID of resulting status (request /user/{name} and store status ID)
|
|
$self->mark_trwl_checkin_success( $uid, $user );
|
|
|
|
# mark success: checked into (trip_id, start, destination)
|
|
}
|
|
}
|
|
)->catch(
|
|
sub {
|
|
my ($err) = @_;
|
|
$self->mark_trwl_checkin_error( $uid, $user, $err );
|
|
}
|
|
)->wait;
|
|
}
|
|
}
|
|
}
|
|
|
|
1;
|