Unverified Commit da87e97a authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

Add bare-bones support for manual checkins (still bound to a specific backend)

Extension opportunities (maybe, eventually)
* provide datetimes of intermediate stops
* provide an API for real-time data updates
* look up stops that travelynx does not yet know about rather than rejecting
  them outright
parent ca2226b9
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -1316,7 +1316,8 @@ sub startup {
			if (   $user->{is_dbris}
				or $user->{is_efa}
				or $user->{is_hafas}
				or $user->{is_motis} )
				or $user->{is_motis}
				or $train_id eq 'manual' )
			{
				return $self->_checkout_journey_p(%opt);
			}
@@ -3004,6 +3005,7 @@ sub startup {
	$authed_r->get('/ajax/status_card.html')->to('traveling#status_card');
	$authed_r->get( '/cancelled' => [ format => [ 'html', 'json' ] ] )
	  ->to( 'traveling#cancelled', format => undef );
	$authed_r->get('/checkin/add')->to('traveling#add_intransit_form');
	$authed_r->get('/fgr')->to('passengerrights#list_candidates');
	$authed_r->get('/account/password')->to('account#password_form');
	$authed_r->get('/account/mail')->to('account#change_mail');
@@ -3031,6 +3033,7 @@ sub startup {
	$authed_r->post('/account/traewelling')->to('traewelling#settings');
	$authed_r->post('/account/insight')->to('account#insight');
	$authed_r->post('/account/select_backend')->to('account#change_backend');
	$authed_r->post('/checkin/add')->to('traveling#add_intransit_form');
	$authed_r->post('/journey/add')->to('traveling#add_journey_form');
	$authed_r->post('/journey/comment')->to('traveling#comment_form');
	$authed_r->post('/journey/visibility')->to('traveling#visibility_form');
+17 −0
Original line number Diff line number Diff line
@@ -53,6 +53,23 @@ sub run {
		my $arr      = $entry->{arr_eva};
		my $train_id = $entry->{train_id};

		if ( $train_id eq 'manual' ) {
			if (    $arr
				and $entry->{real_arr_ts}
				and $now->epoch - $entry->{real_arr_ts} > 600 )
			{
				$self->app->checkout_p(
					station => $arr,
					force   => 2,
					dep_eva => $dep,
					arr_eva => $arr,
					uid     => $uid
				)->wait;
			}

			next;
		}

		if ( $entry->{is_dbris} ) {

			eval {
+212 −0
Original line number Diff line number Diff line
@@ -2612,4 +2612,216 @@ sub add_journey_form {
	}
}

sub add_intransit_form {
	my ($self) = @_;

	$self->stash( backend_id => $self->current_user->{backend_id} );

	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 %trip;

		my @parts = split( qr{\s+}, $self->param('train') );

		if ( @parts == 2 ) {
			@trip{ 'train_type', 'train_no' } = @parts;
		}
		elsif ( @parts == 3 ) {
			@trip{ 'train_type', 'train_line', 'train_no' } = @parts;
		}
		else {
			$self->render(
				'add_intransit',
				with_autocomplete => 1,
				status            => 400,
				error             =>
'Fahrt muss als „Typ Nummer“ oder „Typ Linie Nummer“ eingegeben werden.'
			);
			return;
		}

		for my $key (qw(sched_departure sched_arrival)) {
			if ( $self->param($key) ) {
				my $datetime = $parser->parse_datetime( $self->param($key) );
				if ( not $datetime ) {
					$self->render(
						'add_intransit',
						with_autocomplete => 1,
						status            => 400,
						error => "${key}: Ungültiges Datums-/Zeitformat"
					);
					return;
				}
				$trip{$key} = $datetime;
			}
		}

		for my $key (qw(dep_station arr_station route comment)) {
			$trip{$key} = $self->param($key);
		}

		$opt{backend_id} = $self->current_user->{backend_id};

		my $dep_stop = $self->stations->search( $trip{dep_station},
			backend_id => $opt{backend_id} );
		my $arr_stop = $self->stations->search( $trip{arr_station},
			backend_id => $opt{backend_id} );

		if ( defined $trip{route} ) {
			$trip{route} = [ split( qr{\r?\n\r?}, $trip{route} ) ];
		}

		my $route_has_start = 0;
		my $route_has_stop  = 0;

		for my $station ( @{ $trip{route} || [] } ) {
			if (   $station eq $dep_stop->{name}
				or $station eq $dep_stop->{eva} )
			{
				$route_has_start = 1;
			}
			if (   $station eq $arr_stop->{name}
				or $station eq $arr_stop->{eva} )
			{
				$route_has_stop = 1;
			}
		}

		my @route;

		if ( not $route_has_start ) {
			push(
				@route,
				[
					$dep_stop->{name},
					$dep_stop->{eva},
					{
						lat => $dep_stop->{lat},
						lon => $dep_stop->{lon},
					}
				]
			);
		}

		if ( $trip{route} ) {
			my @unknown_stations;
			for my $station ( @{ $trip{route} } ) {
				my $station_info = $self->stations->search( $station,
					backend_id => $opt{backend_id} );
				if ($station_info) {
					push(
						@route,
						[
							$station_info->{name},
							$station_info->{eva},
							{
								lat => $station_info->{lat},
								lon => $station_info->{lon},
							}
						]
					);
				}
				else {
					push( @route,            [ $station, undef, {} ] );
					push( @unknown_stations, $station );
				}
			}

			if ( @unknown_stations == 1 ) {
				$self->render(
					'add_intransit',
					with_autocomplete => 1,
					status            => 400,
					error => "Unbekannter Unterwegshalt: $unknown_stations[0]"
				);
				return;
			}
			elsif (@unknown_stations) {
				$self->render(
					'add_intransit',
					with_autocomplete => 1,
					status            => 400,
					error             => 'Unbekannte Unterwegshalte: '
					  . join( ', ', @unknown_stations )
				);
				return;
			}
		}

		if ( not $route_has_stop ) {
			push(
				@route,
				[
					$arr_stop->{name},
					$arr_stop->{eva},
					{
						lat => $arr_stop->{lat},
						lon => $arr_stop->{lon},
					}
				]
			);
		}

		for my $station (@route) {
			if (   $station->[0] eq $dep_stop->{name}
				or $station->[1] eq $dep_stop->{eva} )
			{
				$station->[2]{sched_dep} = $trip{sched_departure}->epoch;
			}
			if (   $station->[0] eq $arr_stop->{name}
				or $station->[1] eq $arr_stop->{eva} )
			{
				$station->[2]{sched_arr} = $trip{sched_arrival}->epoch;
			}
		}

		my $error;
		my $db = $self->pg->db;
		my $tx = $db->begin;

		$trip{dep_id} = $dep_stop->{eva};
		$trip{arr_id} = $arr_stop->{eva};
		$trip{route}  = \@route;

		$opt{db}     = $db;
		$opt{manual} = \%trip;
		$opt{uid}    = $self->current_user->{id};

		if ( not defined $trip{dep_id} ) {
			$error = "Unknown departure stop '$trip{dep_station}'";
		}
		elsif ( not defined $trip{arr_id} ) {
			$error = "Unknown arrival stop '$trip{arr_station}'";
		}
		else {
			$error = $self->in_transit->add(%opt);
		}

		if ($error) {
			$self->render(
				'add_intransit',
				with_autocomplete => 1,
				status            => 400,
				error             => $error,
			);
		}
		else {
			$tx->commit;
			$self->redirect_to('/');
		}
	}
	else {
		$self->render(
			'add_intransit',
			with_autocomplete => 1,
			error             => undef
		);
	}
}

1;
+36 −2
Original line number Diff line number Diff line
@@ -101,6 +101,7 @@ sub add {
	my $journey            = $opt{journey};
	my $stop               = $opt{stop};
	my $stopover           = $opt{stopover};
	my $manual             = $opt{manual};
	my $checkin_station_id = $opt{departure_eva};
	my $route              = $opt{route};
	my $data               = $opt{data};
@@ -389,17 +390,50 @@ sub add {
				sched_departure => $stopover->scheduled_departure,
				real_departure  => $stopover->departure,
				route           => $json->encode( \@route ),
				data            => JSON->new->encode(
				data            => $json->encode(
					{
						rt => $stopover->{is_realtime} ? 1 : 0,
						%{ $data // {} }
					}
				),
				user_data  => JSON->new->encode($persistent_data),
				user_data  => $json->encode($persistent_data),
				backend_id => $backend_id,
			}
		);
	}
	elsif ($manual) {
		if ( $manual->{comment} ) {
			$persistent_data->{comment} = $manual->{comment};
		}
		$db->insert(
			'in_transit',
			{
				user_id             => $uid,
				cancelled           => 0,
				checkin_station_id  => $manual->{dep_id},
				checkout_station_id => $manual->{arr_id},
				checkin_time => DateTime->now( time_zone => 'Europe/Berlin' ),
				train_type   => $manual->{train_type},
				train_no     => $manual->{train_no} || q{},
				train_id     => 'manual',
				train_line   => $manual->{train_line} || undef,
				sched_departure => $manual->{sched_departure},
				real_departure  => $manual->{sched_departure},
				sched_arrival   => $manual->{sched_arrival},
				real_arrival    => $manual->{sched_arrival},
				route           => $json->encode( $manual->{route} // [] ),
				data            => $json->encode(
					{
						manual => \1,
						%{ $data // {} }
					}
				),
				user_data  => $json->encode($persistent_data),
				backend_id => $backend_id,
			}
		);
		return;
	}
	else {
		die('invalid arguments / argument types passed to InTransit->add');
	}
+7 −1
Original line number Diff line number Diff line
@@ -283,8 +283,14 @@ sub add_from_in_transit {
	my $db      = $opt{db};
	my $journey = $opt{journey};

	delete $journey->{data};
	if ( $journey->{train_id} eq 'manual' ) {
		$journey->{edited} = 0x3fff;
	}
	else {
		$journey->{edited} = 0;
	}

	delete $journey->{data};
	$journey->{checkout_time} = DateTime->now( time_zone => 'Europe/Berlin' );

	return $db->insert( 'journeys', $journey, { returning => 'id' } )
Loading