diff options
| author | Birte Kristina Friesel <derf@finalrewind.org> | 2025-06-21 20:48:53 +0200 | 
|---|---|---|
| committer | Birte Kristina Friesel <derf@finalrewind.org> | 2025-06-21 20:48:53 +0200 | 
| commit | da87e97a0b954860e0a53b8a0f475580d44ad73d (patch) | |
| tree | 3626df8b8792df43fcb0edf266059f70fbb92573 /lib | |
| parent | ca2226b9238ac2159d0001a071edf33915f062ae (diff) | |
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
Diffstat (limited to 'lib')
| -rwxr-xr-x | lib/Travelynx.pm | 5 | ||||
| -rw-r--r-- | lib/Travelynx/Command/work.pm | 17 | ||||
| -rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 212 | ||||
| -rw-r--r-- | lib/Travelynx/Model/InTransit.pm | 38 | ||||
| -rwxr-xr-x | lib/Travelynx/Model/Journeys.pm | 8 | 
5 files changed, 276 insertions, 4 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index a06bcea..c8c96b8 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -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'); diff --git a/lib/Travelynx/Command/work.pm b/lib/Travelynx/Command/work.pm index 60417b1..1bc4f53 100644 --- a/lib/Travelynx/Command/work.pm +++ b/lib/Travelynx/Command/work.pm @@ -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 { diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 996b4a5..31c7587 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -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; diff --git a/lib/Travelynx/Model/InTransit.pm b/lib/Travelynx/Model/InTransit.pm index b67b716..cb8f7c4 100644 --- a/lib/Travelynx/Model/InTransit.pm +++ b/lib/Travelynx/Model/InTransit.pm @@ -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,16 +390,49 @@ 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'); diff --git a/lib/Travelynx/Model/Journeys.pm b/lib/Travelynx/Model/Journeys.pm index 0fb663e..876786a 100755 --- a/lib/Travelynx/Model/Journeys.pm +++ b/lib/Travelynx/Model/Journeys.pm @@ -283,8 +283,14 @@ sub add_from_in_transit {  	my $db      = $opt{db};  	my $journey = $opt{journey}; +	if ( $journey->{train_id} eq 'manual' ) { +		$journey->{edited} = 0x3fff; +	} +	else { +		$journey->{edited} = 0; +	} +  	delete $journey->{data}; -	$journey->{edited}        = 0;  	$journey->{checkout_time} = DateTime->now( time_zone => 'Europe/Berlin' );  	return $db->insert( 'journeys', $journey, { returning => 'id' } )  | 
