2019-03-21 21:12:45 +00:00
|
|
|
|
package Travelynx::Controller::Traveling;
|
|
|
|
|
use Mojo::Base 'Mojolicious::Controller';
|
|
|
|
|
|
2019-03-27 20:20:59 +00:00
|
|
|
|
use DateTime;
|
2019-04-08 19:20:04 +00:00
|
|
|
|
use DateTime::Format::Strptime;
|
2020-02-07 22:19:01 +00:00
|
|
|
|
use JSON;
|
2020-01-29 17:48:58 +00:00
|
|
|
|
use List::Util qw(uniq min max);
|
2019-07-20 13:42:11 +00:00
|
|
|
|
use List::UtilsBy qw(uniq_by);
|
2019-11-16 20:24:35 +00:00
|
|
|
|
use List::MoreUtils qw(first_index);
|
2019-03-21 21:12:45 +00:00
|
|
|
|
use Travel::Status::DE::IRIS::Stations;
|
|
|
|
|
|
|
|
|
|
sub homepage {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
if ( $self->is_user_authenticated ) {
|
2019-04-13 08:43:05 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'landingpage',
|
2019-04-30 16:18:09 +00:00
|
|
|
|
version => $self->app->config->{version} // 'UNKNOWN',
|
2019-04-13 08:43:05 +00:00
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
with_geolocation => 1
|
|
|
|
|
);
|
2019-04-30 10:47:32 +00:00
|
|
|
|
$self->mark_seen( $self->current_user->{id} );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
2019-04-30 16:18:09 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'landingpage',
|
|
|
|
|
version => $self->app->config->{version} // 'UNKNOWN',
|
|
|
|
|
intro => 1
|
|
|
|
|
);
|
2019-03-21 21:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-30 21:23:49 +00:00
|
|
|
|
sub user_status {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
my $name = $self->stash('name');
|
2020-02-19 19:58:38 +00:00
|
|
|
|
my $ts = $self->stash('ts') // 0;
|
2019-04-30 21:23:49 +00:00
|
|
|
|
my $user = $self->get_privacy_by_name($name);
|
|
|
|
|
|
2020-02-19 19:58:38 +00:00
|
|
|
|
if ( not $user or not $user->{public_level} & 0x03 ) {
|
|
|
|
|
$self->render('not_found');
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( $user->{public_level} & 0x01 and not $self->is_user_authenticated ) {
|
|
|
|
|
$self->render( 'login', redirect_to => $self->req->url );
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $status = $self->get_user_status( $user->{id} );
|
|
|
|
|
my $journey;
|
|
|
|
|
|
2019-12-08 10:06:17 +00:00
|
|
|
|
if (
|
2020-02-19 19:58:38 +00:00
|
|
|
|
$ts
|
|
|
|
|
and ( not $status->{checked_in}
|
|
|
|
|
or $status->{sched_departure}->epoch != $ts )
|
|
|
|
|
and ( $user->{public_level} & 0x20
|
2019-12-08 10:06:17 +00:00
|
|
|
|
or
|
2020-02-19 19:58:38 +00:00
|
|
|
|
( $user->{public_level} & 0x10 and $self->is_user_authenticated ) )
|
2019-12-08 10:06:17 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2020-02-19 19:58:38 +00:00
|
|
|
|
for my $candidate (
|
|
|
|
|
$self->get_user_travels(
|
|
|
|
|
uid => $user->{id},
|
|
|
|
|
limit => 10,
|
|
|
|
|
verbose => 1,
|
|
|
|
|
with_datetime => 1
|
|
|
|
|
)
|
2019-05-29 18:01:52 +00:00
|
|
|
|
)
|
|
|
|
|
{
|
2020-02-19 19:58:38 +00:00
|
|
|
|
if ( $candidate->{sched_departure}->epoch eq $ts ) {
|
|
|
|
|
$journey = $candidate;
|
2019-05-29 16:10:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-19 19:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my %tw_data = (
|
|
|
|
|
card => 'summary',
|
|
|
|
|
site => '@derfnull',
|
|
|
|
|
image => $self->url_for('/static/icons/icon-512x512.png')
|
|
|
|
|
->to_abs->scheme('https'),
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if ($journey) {
|
|
|
|
|
$tw_data{title} = sprintf( 'Fahrt von %s nach %s',
|
|
|
|
|
$journey->{from_name}, $journey->{to_name} );
|
|
|
|
|
$tw_data{description}
|
|
|
|
|
= $journey->{rt_arrival}->strftime('Ankunft am %d.%m.%Y um %H:%M');
|
|
|
|
|
}
|
|
|
|
|
elsif (
|
|
|
|
|
$ts
|
|
|
|
|
and ( not $status->{checked_in}
|
|
|
|
|
or $status->{sched_departure}->epoch != $ts )
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$tw_data{title} = "Bahnfahrt beendet";
|
|
|
|
|
$tw_data{description} = "${name} hat das Ziel erreicht";
|
|
|
|
|
}
|
|
|
|
|
elsif ( $status->{checked_in} ) {
|
|
|
|
|
$tw_data{title} = "${name} ist unterwegs";
|
|
|
|
|
$tw_data{description} = sprintf(
|
|
|
|
|
'%s %s von %s nach %s',
|
|
|
|
|
$status->{train_type}, $status->{train_line} // $status->{train_no},
|
|
|
|
|
$status->{dep_name}, $status->{arr_name} // 'irgendwo'
|
|
|
|
|
);
|
|
|
|
|
if ( $status->{real_arrival}->epoch ) {
|
|
|
|
|
$tw_data{description} .= $status->{real_arrival}
|
|
|
|
|
->strftime(' – Ankunft gegen %H:%M Uhr');
|
2019-05-29 16:10:45 +00:00
|
|
|
|
}
|
2020-02-19 19:58:38 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$tw_data{title} = "${name} ist gerade nicht eingecheckt";
|
|
|
|
|
$tw_data{description} = "Letztes Fahrtziel: $status->{arr_name}";
|
|
|
|
|
}
|
2019-05-29 16:10:45 +00:00
|
|
|
|
|
2020-02-19 19:58:38 +00:00
|
|
|
|
if ($journey) {
|
|
|
|
|
if ( not $user->{public_level} & 0x04 ) {
|
|
|
|
|
delete $journey->{user_data}{comment};
|
|
|
|
|
}
|
|
|
|
|
$self->render(
|
|
|
|
|
'journey',
|
|
|
|
|
error => undef,
|
|
|
|
|
readonly => 1,
|
|
|
|
|
journey => $journey,
|
|
|
|
|
twitter => \%tw_data,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-04-30 21:23:49 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'user_status',
|
2019-12-06 20:42:26 +00:00
|
|
|
|
name => $name,
|
|
|
|
|
public_level => $user->{public_level},
|
|
|
|
|
journey => $status,
|
|
|
|
|
twitter => \%tw_data,
|
2019-04-30 21:23:49 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub public_status_card {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
my $name = $self->stash('name');
|
|
|
|
|
my $user = $self->get_privacy_by_name($name);
|
|
|
|
|
|
2019-05-02 08:05:15 +00:00
|
|
|
|
delete $self->stash->{layout};
|
|
|
|
|
|
2019-12-08 10:06:17 +00:00
|
|
|
|
if (
|
|
|
|
|
$user
|
|
|
|
|
and ( $user->{public_level} & 0x02
|
|
|
|
|
or
|
|
|
|
|
( $user->{public_level} & 0x01 and $self->is_user_authenticated ) )
|
|
|
|
|
)
|
|
|
|
|
{
|
2019-04-30 21:23:49 +00:00
|
|
|
|
my $status = $self->get_user_status( $user->{id} );
|
|
|
|
|
$self->render(
|
|
|
|
|
'_public_status_card',
|
2019-12-06 20:42:26 +00:00
|
|
|
|
name => $name,
|
|
|
|
|
public_level => $user->{public_level},
|
|
|
|
|
journey => $status
|
2019-04-30 21:23:49 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render('not_found');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 20:27:13 +00:00
|
|
|
|
sub status_card {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $status = $self->get_user_status;
|
|
|
|
|
|
|
|
|
|
delete $self->stash->{layout};
|
|
|
|
|
|
|
|
|
|
if ( $status->{checked_in} ) {
|
2019-04-24 07:00:30 +00:00
|
|
|
|
$self->render( '_checked_in', journey => $status );
|
2019-04-23 20:27:13 +00:00
|
|
|
|
}
|
2020-02-17 20:13:07 +00:00
|
|
|
|
elsif ( $status->{cancellation} ) {
|
|
|
|
|
$self->render( '_cancelled_departure',
|
|
|
|
|
journey => $status->{cancellation} );
|
|
|
|
|
}
|
2019-04-23 20:27:13 +00:00
|
|
|
|
else {
|
2019-04-24 07:00:30 +00:00
|
|
|
|
$self->render( '_checked_out', journey => $status );
|
2019-04-23 20:27:13 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 21:12:45 +00:00
|
|
|
|
sub geolocation {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
my $lon = $self->param('lon');
|
|
|
|
|
my $lat = $self->param('lat');
|
|
|
|
|
|
|
|
|
|
if ( not $lon or not $lat ) {
|
|
|
|
|
$self->render( json => { error => 'Invalid lon/lat received' } );
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
my @candidates = map {
|
|
|
|
|
{
|
|
|
|
|
ds100 => $_->[0][0],
|
|
|
|
|
name => $_->[0][1],
|
|
|
|
|
eva => $_->[0][2],
|
|
|
|
|
lon => $_->[0][3],
|
|
|
|
|
lat => $_->[0][4],
|
|
|
|
|
distance => $_->[1],
|
|
|
|
|
}
|
|
|
|
|
} Travel::Status::DE::IRIS::Stations::get_station_by_location( $lon,
|
2019-07-20 13:42:11 +00:00
|
|
|
|
$lat, 10 );
|
|
|
|
|
@candidates = uniq_by { $_->{name} } @candidates;
|
2019-10-19 14:47:33 +00:00
|
|
|
|
if ( @candidates > 5 ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
candidates => [ @candidates[ 0 .. 4 ] ],
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
candidates => [@candidates],
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-03-21 21:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub log_action {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $params = $self->req->json;
|
|
|
|
|
|
|
|
|
|
if ( not exists $params->{action} ) {
|
|
|
|
|
$params = $self->req->params->to_hash;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( not $self->is_user_authenticated ) {
|
|
|
|
|
|
|
|
|
|
# We deliberately do not set the HTTP status for these replies, as it
|
|
|
|
|
# confuses jquery.
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => 'Session error, please login again',
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( not $params->{action} ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => 'Missing action value',
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $station = $params->{station};
|
|
|
|
|
|
|
|
|
|
if ( $params->{action} eq 'checkin' ) {
|
|
|
|
|
|
|
|
|
|
my ( $train, $error )
|
|
|
|
|
= $self->checkin( $params->{station}, $params->{train} );
|
2019-05-19 08:32:57 +00:00
|
|
|
|
my $destination = $params->{dest};
|
2019-03-21 21:12:45 +00:00
|
|
|
|
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-05-19 08:32:57 +00:00
|
|
|
|
elsif ( not $destination ) {
|
2019-03-21 21:12:45 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => '/',
|
2019-03-21 21:12:45 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-05-19 08:32:57 +00:00
|
|
|
|
else {
|
|
|
|
|
# Silently ignore errors -- if they are permanent, the user will see
|
|
|
|
|
# them when selecting the destination manually.
|
|
|
|
|
my ( $still_checked_in, undef )
|
|
|
|
|
= $self->checkout( $destination, 0 );
|
|
|
|
|
my $station_link = '/s/' . $destination;
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => $still_checked_in ? '/' : $station_link,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
2019-03-21 21:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
elsif ( $params->{action} eq 'checkout' ) {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my ( $still_checked_in, $error )
|
|
|
|
|
= $self->checkout( $params->{station}, $params->{force} );
|
|
|
|
|
my $station_link = '/s/' . $params->{station};
|
2019-03-21 21:12:45 +00:00
|
|
|
|
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => $still_checked_in ? '/' : $station_link,
|
2019-03-21 21:12:45 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
elsif ( $params->{action} eq 'undo' ) {
|
2019-04-25 07:22:54 +00:00
|
|
|
|
my $status = $self->get_user_status;
|
2019-04-26 17:53:01 +00:00
|
|
|
|
my $error = $self->undo( $params->{undo_id} );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-04-25 07:22:54 +00:00
|
|
|
|
my $redir = '/';
|
2019-04-26 17:53:01 +00:00
|
|
|
|
if ( $status->{checked_in} or $status->{cancelled} ) {
|
2019-04-25 07:22:54 +00:00
|
|
|
|
$redir = '/s/' . $status->{dep_ds100};
|
|
|
|
|
}
|
2019-03-21 21:12:45 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
2019-04-25 07:22:54 +00:00
|
|
|
|
redirect_to => $redir,
|
2019-03-21 21:12:45 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
elsif ( $params->{action} eq 'cancelled_from' ) {
|
|
|
|
|
my ( undef, $error )
|
2019-04-23 21:02:44 +00:00
|
|
|
|
= $self->checkin( $params->{station}, $params->{train} );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => '/',
|
2019-03-21 21:12:45 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
elsif ( $params->{action} eq 'cancelled_to' ) {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my ( undef, $error )
|
2019-04-23 21:02:44 +00:00
|
|
|
|
= $self->checkout( $params->{station}, 1 );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => '/',
|
2019-03-21 21:12:45 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-04 16:26:53 +00:00
|
|
|
|
elsif ( $params->{action} eq 'delete' ) {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my $error = $self->delete_journey( $params->{id}, $params->{checkin},
|
2019-04-04 16:26:53 +00:00
|
|
|
|
$params->{checkout} );
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => $error,
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
success => 1,
|
|
|
|
|
redirect_to => '/history',
|
2019-04-04 16:26:53 +00:00
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-03-21 21:12:45 +00:00
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
json => {
|
|
|
|
|
success => 0,
|
|
|
|
|
error => 'invalid action value',
|
|
|
|
|
},
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub station {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $station = $self->stash('station');
|
|
|
|
|
my $train = $self->param('train');
|
|
|
|
|
|
2019-07-14 19:29:52 +00:00
|
|
|
|
my $status = $self->get_departures( $station, 120, 30, 1 );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
|
|
|
|
|
if ( $status->{errstr} ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'landingpage',
|
2019-04-30 16:18:09 +00:00
|
|
|
|
version => $self->app->config->{version} // 'UNKNOWN',
|
2019-04-13 08:43:05 +00:00
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
with_geolocation => 1,
|
|
|
|
|
error => $status->{errstr}
|
2019-03-21 21:12:45 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
# You can't check into a train which terminates here
|
|
|
|
|
my @results = grep { $_->departure } @{ $status->{results} };
|
|
|
|
|
|
|
|
|
|
@results = map { $_->[0] }
|
|
|
|
|
sort { $b->[1] <=> $a->[1] }
|
|
|
|
|
map { [ $_, $_->departure->epoch // $_->sched_departure->epoch ] }
|
|
|
|
|
@results;
|
|
|
|
|
|
|
|
|
|
if ($train) {
|
|
|
|
|
@results
|
|
|
|
|
= grep { $_->type . ' ' . $_->train_no eq $train } @results;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$self->render(
|
|
|
|
|
'departures',
|
2019-12-26 21:48:50 +00:00
|
|
|
|
eva => $status->{station_eva},
|
2019-10-19 08:15:18 +00:00
|
|
|
|
results => \@results,
|
|
|
|
|
station => $status->{station_name},
|
|
|
|
|
related_stations => $status->{related_stations},
|
|
|
|
|
title => "travelynx: $status->{station_name}",
|
2019-03-21 21:12:45 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
2019-04-30 10:47:32 +00:00
|
|
|
|
$self->mark_seen( $self->current_user->{id} );
|
2019-03-21 21:12:45 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub redirect_to_station {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $station = $self->param('station');
|
|
|
|
|
|
|
|
|
|
$self->redirect_to("/s/${station}");
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 16:44:33 +00:00
|
|
|
|
sub cancelled {
|
2019-03-22 15:56:49 +00:00
|
|
|
|
my ($self) = @_;
|
2019-11-24 19:29:52 +00:00
|
|
|
|
my @journeys = $self->get_user_travels(
|
|
|
|
|
cancelled => 1,
|
|
|
|
|
with_datetime => 1
|
|
|
|
|
);
|
2019-03-27 20:20:59 +00:00
|
|
|
|
|
2019-03-22 15:56:49 +00:00
|
|
|
|
$self->respond_to(
|
2019-03-27 20:20:59 +00:00
|
|
|
|
json => { json => [@journeys] },
|
|
|
|
|
any => {
|
2019-04-07 16:44:33 +00:00
|
|
|
|
template => 'cancelled',
|
2019-03-27 20:20:59 +00:00
|
|
|
|
journeys => [@journeys]
|
|
|
|
|
}
|
2019-03-22 15:56:49 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 16:44:33 +00:00
|
|
|
|
sub history {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
|
|
|
|
$self->render( template => 'history' );
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-15 23:01:50 +00:00
|
|
|
|
sub map_history {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
2019-11-16 14:24:16 +00:00
|
|
|
|
my $location = $self->app->coordinates_by_station;
|
2019-11-15 23:01:50 +00:00
|
|
|
|
|
2020-01-31 17:16:00 +00:00
|
|
|
|
if ( not $self->param('route_type') ) {
|
|
|
|
|
$self->param( route_type => 'polybee' );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
my $route_type = $self->param('route_type');
|
|
|
|
|
my $with_polyline = $route_type eq 'beeline' ? 0 : 1;
|
2020-01-29 17:48:58 +00:00
|
|
|
|
|
|
|
|
|
my @journeys = $self->get_user_travels( with_polyline => $with_polyline );
|
2019-11-15 23:01:50 +00:00
|
|
|
|
|
2019-11-16 22:47:18 +00:00
|
|
|
|
if ( not @journeys ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
template => 'history_map',
|
|
|
|
|
with_map => 1,
|
2020-01-25 13:55:51 +00:00
|
|
|
|
skipped_journeys => [],
|
2019-11-16 22:47:18 +00:00
|
|
|
|
station_coordinates => [],
|
2020-01-25 13:41:33 +00:00
|
|
|
|
polyline_groups => [],
|
2019-11-16 22:47:18 +00:00
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2020-02-07 22:19:01 +00:00
|
|
|
|
my $json = JSON->new->utf8;
|
|
|
|
|
|
2019-11-27 17:26:15 +00:00
|
|
|
|
my $include_manual = $self->param('include_manual') ? 1 : 0;
|
|
|
|
|
|
2019-11-16 22:47:18 +00:00
|
|
|
|
my $first_departure = $journeys[-1]->{rt_departure};
|
|
|
|
|
my $last_departure = $journeys[0]->{rt_departure};
|
|
|
|
|
|
2019-11-15 23:01:50 +00:00
|
|
|
|
my @stations = uniq map { $_->{to_name} } @journeys;
|
|
|
|
|
push( @stations, uniq map { $_->{from_name} } @journeys );
|
|
|
|
|
@stations = uniq @stations;
|
2019-11-16 14:24:16 +00:00
|
|
|
|
my @station_coordinates = map { [ $location->{$_}, $_ ] }
|
|
|
|
|
grep { exists $location->{$_} } @stations;
|
2019-11-15 23:01:50 +00:00
|
|
|
|
|
|
|
|
|
my @station_pairs;
|
2020-02-07 22:19:01 +00:00
|
|
|
|
my @polylines;
|
2019-11-16 20:24:35 +00:00
|
|
|
|
my %seen;
|
2019-11-15 23:01:50 +00:00
|
|
|
|
|
2020-01-25 13:55:51 +00:00
|
|
|
|
my @skipped_journeys;
|
2020-01-31 17:16:00 +00:00
|
|
|
|
my @polyline_journeys = grep { $_->{polyline} } @journeys;
|
|
|
|
|
my @beeline_journeys = grep { not $_->{polyline} } @journeys;
|
|
|
|
|
|
|
|
|
|
if ( $route_type eq 'polyline' ) {
|
|
|
|
|
@beeline_journeys = ();
|
|
|
|
|
}
|
|
|
|
|
elsif ( $route_type eq 'beeline' ) {
|
|
|
|
|
push( @beeline_journeys, @polyline_journeys );
|
|
|
|
|
@polyline_journeys = ();
|
|
|
|
|
}
|
2020-01-25 13:55:51 +00:00
|
|
|
|
|
2020-01-31 17:16:00 +00:00
|
|
|
|
for my $journey (@polyline_journeys) {
|
2020-01-29 17:48:58 +00:00
|
|
|
|
my @polyline = @{ $journey->{polyline} };
|
|
|
|
|
my $from_eva = $journey->{from_eva};
|
|
|
|
|
my $to_eva = $journey->{to_eva};
|
|
|
|
|
|
|
|
|
|
my $from_index
|
|
|
|
|
= first_index { $_->[2] and $_->[2] == $from_eva } @polyline;
|
|
|
|
|
my $to_index = first_index { $_->[2] and $_->[2] == $to_eva } @polyline;
|
|
|
|
|
|
|
|
|
|
if ( $from_index == -1
|
|
|
|
|
or $to_index == -1 )
|
|
|
|
|
{
|
|
|
|
|
# Fall back to route
|
|
|
|
|
delete $journey->{polyline};
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
2020-01-29 18:54:32 +00:00
|
|
|
|
my $key = $from_eva . '!' . $to_eva . '!' . ( $to_index - $from_index );
|
2020-01-29 17:48:58 +00:00
|
|
|
|
|
|
|
|
|
if ( $seen{$key} ) {
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$seen{$key} = 1;
|
|
|
|
|
|
|
|
|
|
# direction does not matter at the moment
|
2020-01-29 18:54:32 +00:00
|
|
|
|
$key = $to_eva . '!' . $from_eva . '!' . ( $to_index - $from_index );
|
2020-01-29 17:48:58 +00:00
|
|
|
|
$seen{$key} = 1;
|
|
|
|
|
|
|
|
|
|
@polyline = @polyline[ $from_index .. $to_index ];
|
2020-02-07 22:19:01 +00:00
|
|
|
|
my @polyline_coords;
|
2020-01-29 17:48:58 +00:00
|
|
|
|
for my $coord (@polyline) {
|
2020-02-07 22:19:01 +00:00
|
|
|
|
push( @polyline_coords, [ $coord->[1], $coord->[0] ] );
|
2020-01-29 17:48:58 +00:00
|
|
|
|
}
|
2020-02-07 22:19:01 +00:00
|
|
|
|
push( @polylines, [@polyline_coords] );
|
2020-01-29 17:48:58 +00:00
|
|
|
|
}
|
|
|
|
|
|
2020-01-31 17:16:00 +00:00
|
|
|
|
for my $journey (@beeline_journeys) {
|
2019-11-16 20:24:35 +00:00
|
|
|
|
|
2020-01-25 14:46:42 +00:00
|
|
|
|
my @route = map { $_->[0] } @{ $journey->{route} };
|
|
|
|
|
|
2019-11-16 20:24:35 +00:00
|
|
|
|
my $from_index = first_index { $_ eq $journey->{from_name} } @route;
|
|
|
|
|
my $to_index = first_index { $_ eq $journey->{to_name} } @route;
|
|
|
|
|
|
2020-01-25 14:46:42 +00:00
|
|
|
|
if ( $from_index == -1 ) {
|
|
|
|
|
my $rename = $self->app->renamed_station;
|
|
|
|
|
$from_index
|
|
|
|
|
= first_index { ( $rename->{$_} // $_ ) eq $journey->{from_name} }
|
|
|
|
|
@route;
|
|
|
|
|
}
|
|
|
|
|
if ( $to_index == -1 ) {
|
|
|
|
|
my $rename = $self->app->renamed_station;
|
|
|
|
|
$to_index
|
|
|
|
|
= first_index { ( $rename->{$_} // $_ ) eq $journey->{to_name} }
|
|
|
|
|
@route;
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-16 22:47:18 +00:00
|
|
|
|
if ( $from_index == -1
|
2019-11-27 17:26:15 +00:00
|
|
|
|
or $to_index == -1 )
|
|
|
|
|
{
|
2020-01-25 13:55:51 +00:00
|
|
|
|
push( @skipped_journeys,
|
|
|
|
|
[ $journey, 'Start/Ziel nicht in Route gefunden' ] );
|
2019-11-27 17:26:15 +00:00
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
# Manual journey entries are only included if one of the following
|
|
|
|
|
# conditions is satisfied:
|
|
|
|
|
# * their route has more than two elements (-> probably more than just
|
|
|
|
|
# start and stop station), or
|
|
|
|
|
# * $include_manual is true (-> user wants to see incomplete routes)
|
|
|
|
|
# This avoids messing up the map in case an A -> B connection has been
|
|
|
|
|
# tracked both with a regular checkin (-> detailed route shown on map)
|
|
|
|
|
# and entered manually (-> beeline also shown on map, typically
|
|
|
|
|
# significantly differs from detailed route) -- unless the user
|
|
|
|
|
# sets include_manual, of course.
|
|
|
|
|
if ( $journey->{edited} & 0x0010
|
|
|
|
|
and @route <= 2
|
|
|
|
|
and not $include_manual )
|
2019-11-16 22:47:18 +00:00
|
|
|
|
{
|
2020-01-25 13:55:51 +00:00
|
|
|
|
push( @skipped_journeys,
|
|
|
|
|
[ $journey, 'Manueller Eintrag ohne Unterwegshalte' ] );
|
2019-11-16 20:24:35 +00:00
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@route = @route[ $from_index .. $to_index ];
|
|
|
|
|
|
|
|
|
|
my $key = join( '|', @route );
|
|
|
|
|
|
|
|
|
|
if ( $seen{$key} ) {
|
|
|
|
|
next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$seen{$key} = 1;
|
|
|
|
|
|
|
|
|
|
# direction does not matter at the moment
|
|
|
|
|
$seen{ join( '|', reverse @route ) } = 1;
|
|
|
|
|
|
2019-11-15 23:01:50 +00:00
|
|
|
|
my $prev_station = shift @route;
|
|
|
|
|
for my $station (@route) {
|
2019-11-16 20:24:35 +00:00
|
|
|
|
push( @station_pairs, [ $prev_station, $station ] );
|
2019-11-15 23:01:50 +00:00
|
|
|
|
$prev_station = $station;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@station_pairs = uniq_by { $_->[0] . '|' . $_->[1] } @station_pairs;
|
|
|
|
|
@station_pairs
|
2019-11-16 14:24:16 +00:00
|
|
|
|
= grep { exists $location->{ $_->[0] } and exists $location->{ $_->[1] } }
|
2019-11-15 23:01:50 +00:00
|
|
|
|
@station_pairs;
|
|
|
|
|
@station_pairs
|
2019-11-16 14:24:16 +00:00
|
|
|
|
= map { [ $location->{ $_->[0] }, $location->{ $_->[1] } ] }
|
|
|
|
|
@station_pairs;
|
2019-11-15 23:01:50 +00:00
|
|
|
|
|
|
|
|
|
my @routes;
|
|
|
|
|
|
2020-01-29 17:48:58 +00:00
|
|
|
|
my @lats = map { $_->[0][0] } @station_coordinates;
|
|
|
|
|
my @lons = map { $_->[0][1] } @station_coordinates;
|
|
|
|
|
my $min_lat = min @lats;
|
|
|
|
|
my $max_lat = max @lats;
|
|
|
|
|
my $min_lon = min @lons;
|
|
|
|
|
my $max_lon = max @lons;
|
|
|
|
|
|
2019-11-15 23:01:50 +00:00
|
|
|
|
$self->render(
|
2019-11-16 14:57:09 +00:00
|
|
|
|
template => 'history_map',
|
2019-11-15 23:01:50 +00:00
|
|
|
|
with_map => 1,
|
2020-01-25 13:55:51 +00:00
|
|
|
|
skipped_journeys => \@skipped_journeys,
|
2019-11-15 23:01:50 +00:00
|
|
|
|
station_coordinates => \@station_coordinates,
|
2020-01-25 13:41:33 +00:00
|
|
|
|
polyline_groups => [
|
|
|
|
|
{
|
2020-02-07 22:19:01 +00:00
|
|
|
|
polylines => $json->encode( \@station_pairs ),
|
2020-01-29 17:48:58 +00:00
|
|
|
|
color => '#673ab7',
|
|
|
|
|
opacity => $with_polyline ? 0.4 : 0.6,
|
|
|
|
|
},
|
|
|
|
|
{
|
2020-02-07 22:19:01 +00:00
|
|
|
|
polylines => $json->encode( \@polylines ),
|
2020-01-29 17:48:58 +00:00
|
|
|
|
color => '#673ab7',
|
2020-01-31 17:16:00 +00:00
|
|
|
|
opacity => 0.8,
|
2020-01-25 13:41:33 +00:00
|
|
|
|
}
|
2020-01-29 17:48:58 +00:00
|
|
|
|
],
|
|
|
|
|
bounds => [ [ $min_lat, $min_lon ], [ $max_lat, $max_lon ] ],
|
2019-11-15 23:01:50 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:56:49 +00:00
|
|
|
|
sub json_history {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
2019-04-07 16:44:33 +00:00
|
|
|
|
$self->render( json => [ $self->get_user_travels ] );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub yearly_history {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $year = $self->stash('year');
|
|
|
|
|
my @journeys;
|
|
|
|
|
my $stats;
|
|
|
|
|
|
2019-05-10 23:35:57 +00:00
|
|
|
|
# DateTime is very slow when looking far into the future due to DST changes
|
|
|
|
|
# -> Limit time range to avoid accidental DoS.
|
|
|
|
|
if ( not( $year =~ m{ ^ [0-9]{4} $ }x and $year > 1990 and $year < 2100 ) )
|
|
|
|
|
{
|
2019-11-24 19:29:52 +00:00
|
|
|
|
@journeys = $self->get_user_travels( with_datetime => 1 );
|
2019-04-07 16:44:33 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
my $interval_start = DateTime->new(
|
|
|
|
|
time_zone => 'Europe/Berlin',
|
|
|
|
|
year => $year,
|
|
|
|
|
month => 1,
|
|
|
|
|
day => 1,
|
|
|
|
|
hour => 0,
|
|
|
|
|
minute => 0,
|
|
|
|
|
second => 0,
|
|
|
|
|
);
|
|
|
|
|
my $interval_end = $interval_start->clone->add( years => 1 );
|
|
|
|
|
@journeys = $self->get_user_travels(
|
2019-11-24 19:29:52 +00:00
|
|
|
|
after => $interval_start,
|
|
|
|
|
before => $interval_end,
|
|
|
|
|
with_datetime => 1
|
2019-04-07 16:44:33 +00:00
|
|
|
|
);
|
|
|
|
|
$stats = $self->get_journey_stats( year => $year );
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$self->respond_to(
|
|
|
|
|
json => {
|
|
|
|
|
json => {
|
|
|
|
|
journeys => [@journeys],
|
|
|
|
|
statistics => $stats
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
any => {
|
|
|
|
|
template => 'history_by_year',
|
|
|
|
|
journeys => [@journeys],
|
|
|
|
|
year => $year,
|
|
|
|
|
statistics => $stats
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
2019-03-22 15:56:49 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-27 20:20:59 +00:00
|
|
|
|
sub monthly_history {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $year = $self->stash('year');
|
|
|
|
|
my $month = $self->stash('month');
|
|
|
|
|
my @journeys;
|
|
|
|
|
my $stats;
|
|
|
|
|
my @months
|
|
|
|
|
= (
|
|
|
|
|
qw(Januar Februar März April Mai Juni Juli August September Oktober November Dezember)
|
|
|
|
|
);
|
|
|
|
|
|
2019-05-10 23:35:57 +00:00
|
|
|
|
if (
|
|
|
|
|
not( $year =~ m{ ^ [0-9]{4} $ }x
|
|
|
|
|
and $year > 1990
|
|
|
|
|
and $year < 2100
|
|
|
|
|
and $month =~ m{ ^ [0-9]{1,2} $ }x
|
|
|
|
|
and $month > 0
|
|
|
|
|
and $month < 13 )
|
|
|
|
|
)
|
2019-03-27 20:20:59 +00:00
|
|
|
|
{
|
2019-11-24 19:29:52 +00:00
|
|
|
|
@journeys = $self->get_user_travels( with_datetime => 1 );
|
2019-03-27 20:20:59 +00:00
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
my $interval_start = DateTime->new(
|
|
|
|
|
time_zone => 'Europe/Berlin',
|
|
|
|
|
year => $year,
|
|
|
|
|
month => $month,
|
|
|
|
|
day => 1,
|
|
|
|
|
hour => 0,
|
|
|
|
|
minute => 0,
|
|
|
|
|
second => 0,
|
|
|
|
|
);
|
|
|
|
|
my $interval_end = $interval_start->clone->add( months => 1 );
|
|
|
|
|
@journeys = $self->get_user_travels(
|
2019-11-24 19:29:52 +00:00
|
|
|
|
after => $interval_start,
|
|
|
|
|
before => $interval_end,
|
|
|
|
|
with_datetime => 1
|
2019-04-07 14:55:35 +00:00
|
|
|
|
);
|
|
|
|
|
$stats = $self->get_journey_stats(
|
|
|
|
|
year => $year,
|
|
|
|
|
month => $month
|
2019-03-27 20:20:59 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
$self->respond_to(
|
|
|
|
|
json => {
|
|
|
|
|
json => {
|
|
|
|
|
journeys => [@journeys],
|
|
|
|
|
statistics => $stats
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
any => {
|
2019-04-07 16:44:33 +00:00
|
|
|
|
template => 'history_by_month',
|
2019-03-27 20:20:59 +00:00
|
|
|
|
journeys => [@journeys],
|
|
|
|
|
year => $year,
|
2019-03-27 20:46:52 +00:00
|
|
|
|
month => $month,
|
|
|
|
|
month_name => $months[ $month - 1 ],
|
2019-03-27 20:20:59 +00:00
|
|
|
|
statistics => $stats
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-22 15:56:49 +00:00
|
|
|
|
sub journey_details {
|
|
|
|
|
my ($self) = @_;
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my $journey_id = $self->stash('id');
|
|
|
|
|
|
|
|
|
|
my $uid = $self->current_user->{id};
|
2019-03-22 15:56:49 +00:00
|
|
|
|
|
2019-04-23 16:08:07 +00:00
|
|
|
|
$self->param( journey_id => $journey_id );
|
2019-04-07 18:20:37 +00:00
|
|
|
|
|
2020-01-19 18:15:53 +00:00
|
|
|
|
if ( not( $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) {
|
2019-03-22 15:56:49 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'journey',
|
2020-01-19 18:21:14 +00:00
|
|
|
|
status => 404,
|
2019-03-22 15:56:49 +00:00
|
|
|
|
error => 'notfound',
|
|
|
|
|
journey => {}
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my $journey = $self->get_journey(
|
2019-11-24 19:29:52 +00:00
|
|
|
|
uid => $uid,
|
|
|
|
|
journey_id => $journey_id,
|
|
|
|
|
verbose => 1,
|
|
|
|
|
with_datetime => 1,
|
2019-03-22 15:56:49 +00:00
|
|
|
|
);
|
2019-04-23 16:08:07 +00:00
|
|
|
|
|
|
|
|
|
if ($journey) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'journey',
|
|
|
|
|
error => undef,
|
|
|
|
|
journey => $journey,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-03-22 15:56:49 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'journey',
|
2020-01-19 18:21:14 +00:00
|
|
|
|
status => 404,
|
2019-03-22 15:56:49 +00:00
|
|
|
|
error => 'notfound',
|
|
|
|
|
journey => {}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
2019-12-06 20:40:51 +00:00
|
|
|
|
sub comment_form {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $dep_ts = $self->param('dep_ts');
|
|
|
|
|
my $status = $self->get_user_status;
|
|
|
|
|
|
|
|
|
|
if ( not $status->{checked_in} ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'edit_comment',
|
|
|
|
|
error => 'notfound',
|
|
|
|
|
journey => {}
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
elsif ( not $dep_ts ) {
|
|
|
|
|
$self->param( dep_ts => $status->{sched_departure}->epoch );
|
|
|
|
|
$self->param( comment => $status->{comment} );
|
|
|
|
|
$self->render(
|
|
|
|
|
'edit_comment',
|
|
|
|
|
error => undef,
|
|
|
|
|
journey => $status
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
elsif ( $self->validation->csrf_protect->has_error('csrf_token') ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'edit_comment',
|
|
|
|
|
error => undef,
|
|
|
|
|
journey => $status
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
elsif ( $dep_ts != $status->{sched_departure}->epoch ) {
|
|
|
|
|
|
|
|
|
|
# TODO find and update appropriate past journey (if it exists)
|
|
|
|
|
$self->param( comment => $status->{comment} );
|
|
|
|
|
$self->render(
|
|
|
|
|
'edit_comment',
|
|
|
|
|
error => undef,
|
|
|
|
|
journey => $status
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->app->log->debug("set comment");
|
|
|
|
|
$self->update_in_transit_comment( $self->param('comment') );
|
|
|
|
|
$self->redirect_to('/');
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-07 18:20:37 +00:00
|
|
|
|
sub edit_journey {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
my ($self) = @_;
|
|
|
|
|
my $journey_id = $self->param('journey_id');
|
|
|
|
|
my $uid = $self->current_user->{id};
|
2019-04-07 18:20:37 +00:00
|
|
|
|
|
2019-04-23 16:08:07 +00:00
|
|
|
|
if ( not( $journey_id =~ m{ ^ \d+ $ }x ) ) {
|
2019-04-07 18:20:37 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'edit_journey',
|
2020-01-19 18:21:14 +00:00
|
|
|
|
status => 404,
|
2019-04-07 18:20:37 +00:00
|
|
|
|
error => 'notfound',
|
|
|
|
|
journey => {}
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-08 19:20:04 +00:00
|
|
|
|
my $journey = $self->get_journey(
|
2019-11-24 19:29:52 +00:00
|
|
|
|
uid => $uid,
|
|
|
|
|
journey_id => $journey_id,
|
2019-12-08 18:46:45 +00:00
|
|
|
|
verbose => 1,
|
2019-11-24 19:29:52 +00:00
|
|
|
|
with_datetime => 1,
|
2019-04-07 18:20:37 +00:00
|
|
|
|
);
|
2019-04-08 19:20:04 +00:00
|
|
|
|
|
|
|
|
|
if ( not $journey ) {
|
2019-04-07 18:20:37 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'edit_journey',
|
2020-01-19 18:21:14 +00:00
|
|
|
|
status => 404,
|
2019-04-07 18:20:37 +00:00
|
|
|
|
error => 'notfound',
|
|
|
|
|
journey => {}
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-08 19:20:04 +00:00
|
|
|
|
my $error = undef;
|
|
|
|
|
|
|
|
|
|
if ( $self->param('action') and $self->param('action') eq 'save' ) {
|
|
|
|
|
my $parser = DateTime::Format::Strptime->new(
|
|
|
|
|
pattern => '%d.%m.%Y %H:%M',
|
|
|
|
|
locale => 'de_DE',
|
|
|
|
|
time_zone => 'Europe/Berlin'
|
|
|
|
|
);
|
|
|
|
|
|
2019-04-22 10:11:22 +00:00
|
|
|
|
my $db = $self->pg->db;
|
|
|
|
|
my $tx = $db->begin;
|
2019-04-08 19:20:04 +00:00
|
|
|
|
|
|
|
|
|
for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival))
|
|
|
|
|
{
|
|
|
|
|
my $datetime = $parser->parse_datetime( $self->param($key) );
|
|
|
|
|
if ( $datetime and $datetime->epoch ne $journey->{$key}->epoch ) {
|
2019-04-23 16:08:07 +00:00
|
|
|
|
$error = $self->update_journey_part( $db, $journey->{id},
|
|
|
|
|
$key, $datetime );
|
2019-04-08 19:20:04 +00:00
|
|
|
|
if ($error) {
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-02-01 15:15:20 +00:00
|
|
|
|
for my $key (qw(from_name to_name)) {
|
|
|
|
|
if ( defined $self->param($key)
|
|
|
|
|
and $self->param($key) ne $journey->{$key} )
|
|
|
|
|
{
|
|
|
|
|
$error = $self->update_journey_part( $db, $journey->{id}, $key,
|
|
|
|
|
$self->param($key) );
|
|
|
|
|
if ($error) {
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-08-23 10:02:22 +00:00
|
|
|
|
for my $key (qw(comment)) {
|
|
|
|
|
if (
|
|
|
|
|
defined $self->param($key)
|
|
|
|
|
and ( not $journey->{user_data}
|
|
|
|
|
or $journey->{user_data}{$key} ne $self->param($key) )
|
|
|
|
|
)
|
|
|
|
|
{
|
|
|
|
|
$error = $self->update_journey_part( $db, $journey->{id}, $key,
|
|
|
|
|
$self->param($key) );
|
|
|
|
|
if ($error) {
|
|
|
|
|
last;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 16:41:21 +00:00
|
|
|
|
if ( defined $self->param('route') ) {
|
|
|
|
|
my @route_old = map { $_->[0] } @{ $journey->{route} };
|
|
|
|
|
my @route_new = split( qr{\r?\n\r?}, $self->param('route') );
|
|
|
|
|
@route_new = grep { $_ ne '' } @route_new;
|
|
|
|
|
if ( join( '|', @route_old ) ne join( '|', @route_new ) ) {
|
|
|
|
|
$error
|
|
|
|
|
= $self->update_journey_part( $db, $journey->{id}, 'route',
|
|
|
|
|
[@route_new] );
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-12-08 18:46:45 +00:00
|
|
|
|
{
|
2020-02-01 15:15:20 +00:00
|
|
|
|
my $cancelled_old = $journey->{cancelled} // 0;
|
2019-12-08 18:46:45 +00:00
|
|
|
|
my $cancelled_new = $self->param('cancelled') // 0;
|
|
|
|
|
if ( $cancelled_old != $cancelled_new ) {
|
|
|
|
|
$error
|
|
|
|
|
= $self->update_journey_part( $db, $journey->{id},
|
|
|
|
|
'cancelled', $cancelled_new );
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-08 19:20:04 +00:00
|
|
|
|
|
2019-04-22 10:11:22 +00:00
|
|
|
|
if ( not $error ) {
|
2019-04-08 19:20:04 +00:00
|
|
|
|
$journey = $self->get_journey(
|
2019-11-24 19:29:52 +00:00
|
|
|
|
uid => $uid,
|
|
|
|
|
db => $db,
|
|
|
|
|
journey_id => $journey_id,
|
|
|
|
|
verbose => 1,
|
|
|
|
|
with_datetime => 1,
|
2019-04-08 19:20:04 +00:00
|
|
|
|
);
|
|
|
|
|
$error = $self->journey_sanity_check($journey);
|
|
|
|
|
}
|
2019-04-22 10:11:22 +00:00
|
|
|
|
if ( not $error ) {
|
|
|
|
|
$tx->commit;
|
2019-04-23 16:08:07 +00:00
|
|
|
|
$self->redirect_to("/journey/${journey_id}");
|
2019-04-22 10:11:22 +00:00
|
|
|
|
return;
|
|
|
|
|
}
|
2019-04-08 19:20:04 +00:00
|
|
|
|
}
|
2019-04-07 18:20:37 +00:00
|
|
|
|
|
|
|
|
|
for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival)) {
|
|
|
|
|
if ( $journey->{$key} and $journey->{$key}->epoch ) {
|
|
|
|
|
$self->param(
|
|
|
|
|
$key => $journey->{$key}->strftime('%d.%m.%Y %H:%M') );
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-11-20 16:41:21 +00:00
|
|
|
|
|
|
|
|
|
$self->param(
|
|
|
|
|
route => join( "\n", map { $_->[0] } @{ $journey->{route} } ) );
|
|
|
|
|
|
2020-02-01 15:15:20 +00:00
|
|
|
|
$self->param( cancelled => $journey->{cancelled} ? 1 : 0 );
|
|
|
|
|
$self->param( from_name => $journey->{from_name} );
|
|
|
|
|
$self->param( to_name => $journey->{to_name} );
|
2019-12-08 18:46:45 +00:00
|
|
|
|
|
2019-08-23 10:02:22 +00:00
|
|
|
|
for my $key (qw(comment)) {
|
|
|
|
|
if ( $journey->{user_data} and $journey->{user_data}{$key} ) {
|
|
|
|
|
$self->param( $key => $journey->{user_data}{$key} );
|
|
|
|
|
}
|
|
|
|
|
}
|
2019-04-07 18:20:37 +00:00
|
|
|
|
|
|
|
|
|
$self->render(
|
|
|
|
|
'edit_journey',
|
2020-02-01 15:15:20 +00:00
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
error => $error,
|
|
|
|
|
journey => $journey
|
2019-04-07 18:20:37 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub add_journey_form {
|
|
|
|
|
my ($self) = @_;
|
|
|
|
|
|
2019-04-13 08:43:05 +00:00
|
|
|
|
if ( $self->param('action') and $self->param('action') eq 'save' ) {
|
|
|
|
|
my $parser = DateTime::Format::Strptime->new(
|
|
|
|
|
pattern => '%d.%m.%Y %H:%M',
|
|
|
|
|
locale => 'de_DE',
|
|
|
|
|
time_zone => 'Europe/Berlin'
|
|
|
|
|
);
|
|
|
|
|
my %opt;
|
|
|
|
|
|
|
|
|
|
my @parts = split( qr{\s+}, $self->param('train') );
|
|
|
|
|
|
|
|
|
|
if ( @parts == 2 ) {
|
|
|
|
|
@opt{ 'train_type', 'train_no' } = @parts;
|
|
|
|
|
}
|
|
|
|
|
elsif ( @parts == 3 ) {
|
|
|
|
|
@opt{ 'train_type', 'train_line', 'train_no' } = @parts;
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$self->render(
|
|
|
|
|
'add_journey',
|
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
error =>
|
|
|
|
|
'Zug muss als „Typ Nummer“ oder „Typ Linie Nummer“ eingegeben werden.'
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival))
|
|
|
|
|
{
|
2019-04-26 17:53:01 +00:00
|
|
|
|
if ( $self->param($key) ) {
|
|
|
|
|
my $datetime = $parser->parse_datetime( $self->param($key) );
|
|
|
|
|
if ( not $datetime ) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'add_journey',
|
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
error => "${key}: Ungültiges Datums-/Zeitformat"
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
$opt{$key} = $datetime;
|
2019-04-13 08:43:05 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-18 20:00:24 +00:00
|
|
|
|
$opt{rt_departure} //= $opt{sched_departure};
|
|
|
|
|
$opt{rt_arrival} //= $opt{sched_arrival};
|
|
|
|
|
|
2019-11-19 18:46:21 +00:00
|
|
|
|
for my $key (qw(dep_station arr_station route cancelled comment)) {
|
2019-04-13 08:43:05 +00:00
|
|
|
|
$opt{$key} = $self->param($key);
|
|
|
|
|
}
|
|
|
|
|
|
2019-11-19 18:46:21 +00:00
|
|
|
|
if ( $opt{route} ) {
|
|
|
|
|
$opt{route} = [ split( qr{\r?\n\r?}, $opt{route} ) ];
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-26 17:53:01 +00:00
|
|
|
|
my $db = $self->pg->db;
|
|
|
|
|
my $tx = $db->begin;
|
|
|
|
|
|
|
|
|
|
$opt{db} = $db;
|
|
|
|
|
|
|
|
|
|
my ( $journey_id, $error ) = $self->add_journey(%opt);
|
2019-04-13 08:43:05 +00:00
|
|
|
|
|
2019-04-26 17:53:01 +00:00
|
|
|
|
if ( not $error ) {
|
|
|
|
|
my $journey = $self->get_journey(
|
|
|
|
|
uid => $self->current_user->{id},
|
|
|
|
|
db => $db,
|
|
|
|
|
journey_id => $journey_id,
|
|
|
|
|
verbose => 1
|
|
|
|
|
);
|
|
|
|
|
$error = $self->journey_sanity_check($journey);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ($error) {
|
|
|
|
|
$self->render(
|
|
|
|
|
'add_journey',
|
|
|
|
|
with_autocomplete => 1,
|
|
|
|
|
error => $error,
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
else {
|
|
|
|
|
$tx->commit;
|
|
|
|
|
$self->redirect_to("/journey/${journey_id}");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
else {
|
2019-04-13 08:43:05 +00:00
|
|
|
|
$self->render(
|
|
|
|
|
'add_journey',
|
|
|
|
|
with_autocomplete => 1,
|
2019-04-26 17:53:01 +00:00
|
|
|
|
error => undef
|
2019-04-13 08:43:05 +00:00
|
|
|
|
);
|
|
|
|
|
}
|
2019-04-07 18:20:37 +00:00
|
|
|
|
}
|
|
|
|
|
|
2019-03-21 21:12:45 +00:00
|
|
|
|
1;
|