diff options
Diffstat (limited to 'lib/Travelynx/Helper/Traewelling.pm')
-rw-r--r-- | lib/Travelynx/Helper/Traewelling.pm | 235 |
1 files changed, 109 insertions, 126 deletions
diff --git a/lib/Travelynx/Helper/Traewelling.pm b/lib/Travelynx/Helper/Traewelling.pm index 88b91a0..d688004 100644 --- a/lib/Travelynx/Helper/Traewelling.pm +++ b/lib/Travelynx/Helper/Traewelling.pm @@ -1,12 +1,14 @@ package Travelynx::Helper::Traewelling; -# Copyright (C) 2020 Daniel Friesel +# Copyright (C) 2020-2023 Birte Kristina Friesel +# Copyright (C) 2023 networkException <git@nwex.de> # # SPDX-License-Identifier: AGPL-3.0-or-later use strict; use warnings; use 5.020; +use utf8; use DateTime; use DateTime::Format::Strptime; @@ -74,54 +76,61 @@ sub get_status_p { }; $self->{user_agent}->request_timeout(20) - ->get_p( "https://traewelling.de/api/v0/user/${username}" => $header ) - ->then( + ->get_p( + "https://traewelling.de/api/v1/user/${username}/statuses?limit=1" => + $header )->then( sub { my ($tx) = @_; if ( my $err = $tx->error ) { - my $err_msg = "HTTP $err->{code} $err->{message}"; - $promise->reject($err_msg); + my $err_msg + = "v1/user/${username}/statuses: HTTP $err->{code} $err->{message}"; + $promise->reject( { http => $err->{code}, text => $err_msg } ); return; } else { - if ( my $status = $tx->result->json->{statuses}{data}[0] ) { + if ( my $status = $tx->result->json->{data}[0] ) { my $status_id = $status->{id}; my $message = $status->{body}; my $checkin_at - = $self->parse_datetime( $status->{created_at} ); + = $self->parse_datetime( $status->{createdAt} ); my $dep_dt = $self->parse_datetime( - $status->{train_checkin}{departure} ); + $status->{train}{origin}{departurePlanned} ); my $arr_dt = $self->parse_datetime( - $status->{train_checkin}{arrival} ); + $status->{train}{destination}{arrivalPlanned} ); my $dep_eva - = $status->{train_checkin}{origin}{ibnr}; + = $status->{train}{origin}{evaIdentifier}; my $arr_eva - = $status->{train_checkin}{destination}{ibnr}; + = $status->{train}{destination}{evaIdentifier}; + + my $dep_ds100 + = $status->{train}{origin}{rilIdentifier}; + my $arr_ds100 + = $status->{train}{destination}{rilIdentifier}; my $dep_name - = $status->{train_checkin}{origin}{name}; + = $status->{train}{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}; + = $status->{train}{destination}{name}; + + my $category = $status->{train}{category}; + my $linename = $status->{train}{lineName}; + my $trip_id = $status->{train}{hafasId}; my ( $train_type, $train_line ) = split( qr{ }, $linename ); $promise->resolve( { + http => $tx->res->code, status_id => $status_id, message => $message, checkin => $checkin_at, dep_dt => $dep_dt, dep_eva => $dep_eva, + dep_ds100 => $dep_ds100, dep_name => $dep_name, arr_dt => $arr_dt, arr_eva => $arr_eva, + arr_ds100 => $arr_ds100, arr_name => $arr_name, trip_id => $trip_id, train_type => $train_type, @@ -133,7 +142,8 @@ sub get_status_p { return; } else { - $promise->reject("unknown error"); + $promise->reject( + { text => "v1/${username}/statuses: unknown error" } ); return; } } @@ -141,7 +151,7 @@ sub get_status_p { )->catch( sub { my ($err) = @_; - $promise->reject($err); + $promise->reject( { text => "v1/${username}/statuses: $err" } ); return; } )->wait; @@ -160,21 +170,20 @@ sub get_user_p { }; my $promise = Mojo::Promise->new; - $ua->get_p( "https://traewelling.de/api/v0/getuser" => $header )->then( + $ua->get_p( "https://traewelling.de/api/v1/auth/user" => $header )->then( sub { my ($tx) = @_; if ( my $err = $tx->error ) { - my $err_msg - = "HTTP $err->{code} $err->{message} bei Abfrage der Nutzerdaten"; + my $err_msg = "v1/auth/user: HTTP $err->{code} $err->{message}"; $promise->reject($err_msg); return; } else { - my $user_data = $tx->result->json; + my $user_data = $tx->result->json->{data}; $self->{model}->set_user( uid => $uid, trwl_id => $user_data->{id}, - screen_name => $user_data->{name}, + screen_name => $user_data->{displayName}, user_name => $user_data->{username}, ); $promise->resolve; @@ -184,84 +193,7 @@ sub get_user_p { )->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 { - my $res = $tx->result->json; - $token = $res->{token}; - my $expiry_dt = $self->parse_datetime( $res->{expires_at} ); - - # Fall back to one year expiry - $expiry_dt //= DateTime->now( time_zone => 'Europe/Berlin' ) - ->add( years => 1 ); - $self->{model}->link( - uid => $uid, - email => $email, - token => $token, - expires => $expiry_dt - ); - 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); - } + $promise->reject("v1/auth/user: $err"); return; } )->wait; @@ -289,12 +221,13 @@ sub logout_p { my $promise = Mojo::Promise->new; $ua->post_p( - "https://traewelling.de/api/v0/auth/logout" => $header => json => + "https://traewelling.de/api/v1/auth/logout" => $header => json => $request )->then( sub { my ($tx) = @_; if ( my $err = $tx->error ) { - my $err_msg = "HTTP $err->{code} $err->{message}"; + my $err_msg + = "v1/auth/logout: HTTP $err->{code} $err->{message}"; $promise->reject($err_msg); return; } @@ -306,7 +239,7 @@ sub logout_p { )->catch( sub { my ($err) = @_; - $promise->reject($err); + $promise->reject("v1/auth/logout: $err"); return; } )->wait; @@ -314,7 +247,34 @@ sub logout_p { return $promise; } -sub checkin { +sub convert_travelynx_to_traewelling_visibility { + my ($travelynx_visibility) = @_; + + my %visibilities = ( + + # public => StatusVisibility::PUBLIC + 100 => 0, + + # travelynx => StatusVisibility::AUTHENTICATED + # (only visible for logged in users) + 80 => 4, + + # followers => StatusVisibility::FOLLOWERS + 60 => 2, + + # unlisted => StatusVisibility::PRIVATE + # (there is no träwelling equivalent to unlisted, their + # StatusVisibility::UNLISTED shows the journey on the profile) + 30 => 3, + + # private => StatusVisibility::PRIVATE + 10 => 3, + ); + + return $visibilities{$travelynx_visibility}; +} + +sub checkin_p { my ( $self, %opt ) = @_; my $header = { @@ -334,47 +294,63 @@ sub checkin { } my $request = { - tripID => $opt{trip_id}, + tripId => $opt{trip_id}, lineName => $opt{train_type} . ' ' . ( $opt{train_line} // $opt{train_no} ), + ibnr => \1, start => q{} . $opt{dep_eva}, destination => q{} . $opt{arr_eva}, departure => $departure_ts, arrival => $arrival_ts, - toot => $opt{data}{toot} ? \1 : \0, + toot => $opt{data}{toot} ? \1 : \0, tweet => $opt{data}{tweet} ? \1 : \0, + visibility => + convert_travelynx_to_traewelling_visibility( $opt{visibility} ) }; if ( $opt{user_data}{comment} ) { $request->{body} = $opt{user_data}{comment}; } + my $debug_prefix + = "v1/trains/checkin('$request->{lineName}' $request->{tripId} $request->{start} -> $request->{destination})"; + + my $promise = Mojo::Promise->new; + $self->{user_agent}->request_timeout(20) - ->post_p( "https://traewelling.de/api/v0/trains/checkin" => - $header => json => $request )->then( + ->post_p( + "https://traewelling.de/api/v1/trains/checkin" => $header => json => + $request )->then( sub { my ($tx) = @_; if ( my $err = $tx->error ) { my $err_msg = "HTTP $err->{code} $err->{message}"; - if ( $err->{code} != 409 and $err->{code} != 406 ) { - $self->{log}->warn("Traewelling checkin error: $err_msg"); - } - else { - $self->{log}->debug("Traewelling checkin error: $err_msg"); + if ( $tx->res->body ) { + if ( $err->{code} == 409 ) { + my $j = $tx->res->json; + $err_msg .= sprintf( +': Bereits in %s eingecheckt: https://traewelling.de/status/%d', + $j->{message}{lineName}, + $j->{message}{status_id} + ); + } + else { + $err_msg .= ' ' . $tx->res->body; + } } + $self->{log} + ->debug("Traewelling $debug_prefix error: $err_msg"); $self->{model}->log( - uid => $opt{uid}, + uid => $opt{uid}, message => - "Fehler bei $opt{train_type} $opt{train_no}: $err_msg", +"Konnte $opt{train_type} $opt{train_no} nicht übertragen: $debug_prefix returned $err_msg", is_error => 1 ); + $promise->reject( { http => $err->{code} } ); return; } $self->{log}->debug( "... success! " . $tx->res->body ); - # As of 2020-10-04, traewelling.de checkins do not yet return - # "statusId". The patch is present on the develop branch and waiting - # for a merge into master. $self->{model}->log( uid => $opt{uid}, message => "Eingecheckt in $opt{train_type} $opt{train_no}", @@ -384,21 +360,28 @@ sub checkin { uid => $opt{uid}, ts => $opt{checkin_ts} ); + $promise->resolve( { http => $tx->res->code } ); # TODO store status_id in in_transit object so that it can be shown # on the user status page + return; } )->catch( sub { my ($err) = @_; - $self->{log}->debug("... error: $err"); + $self->{log}->debug("... $debug_prefix error: $err"); $self->{model}->log( - uid => $opt{uid}, - message => "Fehler bei $opt{train_type} $opt{train_no}: $err", + uid => $opt{uid}, + message => +"Konnte $opt{train_type} $opt{train_no} nicht übertragen: $debug_prefix returned $err", is_error => 1 ); + $promise->reject( { connection => $err } ); + return; } )->wait; + + return $promise; } 1; |