diff options
| author | Daniel Friesel <derf@finalrewind.org> | 2019-04-08 21:20:04 +0200 | 
|---|---|---|
| committer | Daniel Friesel <derf@finalrewind.org> | 2019-04-08 21:20:04 +0200 | 
| commit | c0c7b1a589b51b9fe27980ff7b5c80e56a77eb01 (patch) | |
| tree | 7aec58d2d32418578e0e785f19f787629e5a27c1 | |
| parent | beb17acb8440bb44f1070c2fb3b2e6cf7521f800 (diff) | |
Work-in-progress journey editor. Not ready for deployment.
| -rw-r--r-- | README.md | 2 | ||||
| -rwxr-xr-x | lib/Travelynx.pm | 130 | ||||
| -rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 67 | ||||
| -rw-r--r-- | templates/edit_journey.html.ep | 19 | ||||
| -rw-r--r-- | templates/journey.html.ep | 5 | 
5 files changed, 200 insertions, 23 deletions
| @@ -13,6 +13,8 @@ Dependencies   * perl >= 5.10   * Cache::File (part of the Cache module)   * Crypt::Eksblowfish + * DateTime + * DateTime::Format::Strptime   * DBI   * DBD::Pg   * Email::Sender diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 7c1c1df..62d70c7 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -267,6 +267,37 @@ sub startup {  		}  	);  	$self->attr( +		action_set_sched_time_query => sub { +			my ($self) = @_; + +         # TODO (re-)initialize all automatically added journeys with edited = 0 +         # and use it as a bit field to precisely indicate which fields have +         # been edited. -> ".. set edited = edited | 1", "... | 2" etc. +         # The action_id check is redundant, but better safe than sorry +			return $self->app->dbh->prepare( +				qq{ +					update user_actions +					set sched_time = to_timestamp(?), edited = 1 +					where id = ? and action_id = ? +				} +			); +		} +	); +	$self->attr( +		action_set_real_time_query => sub { +			my ($self) = @_; + +			# The action_id check is redundant, but better safe than sorry +			return $self->app->dbh->prepare( +				qq{ +					update user_actions +					set real_time = to_timestamp(?), edited = 1 +					where id = ? and action_id = ? +				} +			); +		} +	); +	$self->attr(  		action_query => sub {  			my ($self) = @_; @@ -312,7 +343,7 @@ sub startup {  			stations.ds100, stations.name,  			train_type, train_line, train_no, train_id,  			extract(epoch from sched_time), extract(epoch from real_time), -			route, messages +			route, messages, edited  			from user_actions  			left outer join stations on station_id = stations.id  			where user_id = ? @@ -331,7 +362,7 @@ sub startup {  			stations.ds100, stations.name,  			train_type, train_line, train_no, train_id,  			extract(epoch from sched_time), extract(epoch from real_time), -			route, messages +			route, messages, edited  			from user_actions  			left outer join stations on station_id = stations.id  			where user_id = ? @@ -354,7 +385,7 @@ sub startup {  			stations.ds100, stations.name,  			train_type, train_line, train_no, train_id,  			extract(epoch from sched_time), extract(epoch from real_time), -			route, messages +			route, messages, edited  			from user_actions  			left outer join stations on station_id = stations.id  			where user_id = ? @@ -375,7 +406,7 @@ sub startup {  			stations.ds100, stations.name,  			train_type, train_line, train_no, train_id,  			extract(epoch from sched_time), extract(epoch from real_time), -			route, messages +			route, messages, edited  			from user_actions  			left outer join stations on station_id = stations.id  			where user_id = ? @@ -809,6 +840,77 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  	);  	$self->helper( +		'update_journey_part' => sub { +			my ( $self, $checkin_id, $checkout_id, $key, $value ) = @_; +			my ( $query, $id, $action_type ); + +			if ( $key eq 'sched_departure' ) { +				$query       = $self->app->action_set_sched_time_query; +				$id          = $checkin_id; +				$action_type = $self->app->action_type->{checkin}; +			} +			elsif ( $key eq 'rt_departure' ) { +				$query       = $self->app->action_set_real_time_query; +				$id          = $checkin_id; +				$action_type = $self->app->action_type->{checkin}; +			} +			elsif ( $key eq 'sched_arrival' ) { +				$query       = $self->app->action_set_sched_time_query; +				$id          = $checkout_id; +				$action_type = $self->app->action_type->{checkout}; +			} +			elsif ( $key eq 'rt_arrival' ) { +				$query       = $self->app->action_set_real_time_query; +				$id          = $checkout_id; +				$action_type = $self->app->action_type->{checkout}; +			} +			else { +				$self->app->log->error( +					"update_journey_part(id = $id): Invalid key $key"); +				return 'Internal Error'; +			} + +			my $success = $query->execute( $value, $id, $action_type ); +			if ($success) { +				if ( $query->rows == 1 ) { +					return undef; +				} +				return 'UPDATE failed: did not match any journey part'; +			} +			my $err = $query->errstr; +			$self->app->log->error( +				"update_journey_part($id): UPDATE failed: $err"); +			return 'UPDATE failed: ' . $err; +		} +	); + +	$self->helper( +		'journey_sanity_check' => sub { +			my ( $self, $journey ) = @_; + +			if ( $journey->{sched_duration} and $journey->{sched_duration} < 0 ) +			{ +				return 'Die geplante Dauer dieser Zugfahrt ist negativ'; +			} +			if ( $journey->{rt_duration} and $journey->{rt_duration} < 0 ) { +				return 'Die Dauer dieser Zugfahrt ist negativ'; +			} +			if (    $journey->{sched_duration} +				and $journey->{sched_duration} > 60 * 60 * 24 ) +			{ +				return 'Die Zugfahrt ist länger als 24 Stunden'; +			} +			if (    $journey->{rt_duration} +				and $journey->{rt_duration} > 60 * 60 * 24 ) +			{ +				return 'Die Zugfahrt ist länger als 24 Stunden'; +			} + +			return undef; +		} +	); + +	$self->helper(  		'get_station_id' => sub {  			my ( $self, %opt ) = @_; @@ -1161,7 +1263,7 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  					$ds100,        $name,        $train_type,  					$train_line,   $train_no,    $train_id,  					$raw_sched_ts, $raw_real_ts, $raw_route, -					$raw_messages +					$raw_messages, $edited  				) = @row;  				if ( $action == $match_actions[0] @@ -1185,6 +1287,7 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  							? [ split( qr{[|]}, $raw_route ) ]  							: undef,  							completed => 0, +							edited    => $edited // 0,  						}  					);  				} @@ -1208,6 +1311,7 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  					$ref->{no}       //= $train_no;  					$ref->{messages} //= [ split( qr{[|]}, $raw_messages ) ];  					$ref->{route}    //= [ split( qr{[|]}, $raw_route ) ]; +					$ref->{edited} += $edited;  					if ( $opt{verbose} ) {  						my @parsed_messages; @@ -1273,6 +1377,22 @@ qq{select * from pending_mails where email = ? and num_tries > 1;}  	);  	$self->helper( +		'get_journey' => sub { +			my ( $self, %opt ) = @_; + +			my @journeys = $self->get_user_travels(%opt); +			if (   @journeys == 0 +				or not $journeys[0]{completed} +				or $journeys[0]{ids}[1] != $opt{checkout_id} ) +			{ +				return undef; +			} + +			return $journeys[0]; +		} +	); + +	$self->helper(  		'get_user_status' => sub {  			my ( $self, $uid ) = @_; diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 83036ba..ce7d1d4 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -2,6 +2,7 @@ package Travelynx::Controller::Traveling;  use Mojo::Base 'Mojolicious::Controller';  use DateTime; +use DateTime::Format::Strptime;  use Travel::Status::DE::IRIS::Stations;  sub homepage { @@ -427,14 +428,12 @@ sub edit_journey {  		return;  	} -	my @journeys = $self->get_user_travels( +	my $journey = $self->get_journey(  		uid         => $uid, -		checkout_id => $checkout_id, +		checkout_id => $checkout_id  	); -	if (   @journeys == 0 -		or not $journeys[0]{completed} -		or $journeys[0]{ids}[1] != $checkout_id ) -	{ + +	if ( not $journey ) {  		$self->render(  			'edit_journey',  			error   => 'notfound', @@ -443,7 +442,59 @@ sub edit_journey {  		return;  	} -	my $journey = $journeys[0]; +	my $error = undef; + +	if ( $self->param('action') and $self->param('action') eq 'cancel' ) { +		$self->redirect_to("/journey/${uid}-${checkout_id}"); +		return; +	} + +	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' +		); + +		$self->app->dbh->begin_work; + +		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 ) { +				$error = $self->update_journey_part( +					$journey->{ids}[0], +					$journey->{ids}[1], +					$key, $datetime->epoch +				); +				if ($error) { +					last; +				} +			} +		} + +		if ($error) { +			$self->app->dbh->rollback; +		} +		else { +			$journey = $self->get_journey( +				uid         => $uid, +				checkout_id => $checkout_id, +				verbose     => 1 +			); +			$error = $self->journey_sanity_check($journey); +			if ($error) { +				$self->app->dbh->rollback; +			} +			else { +				$self->invalidate_stats_cache( $journey->{checkout} ); +				$self->app->dbh->commit; +				$self->redirect_to("/journey/${uid}-${checkout_id}"); +				return; +			} +		} + +	}  	for my $key (qw(sched_departure rt_departure sched_arrival rt_arrival)) {  		if ( $journey->{$key} and $journey->{$key}->epoch ) { @@ -458,7 +509,7 @@ sub edit_journey {  	$self->render(  		'edit_journey', -		error   => undef, +		error   => $error,  		journey => $journey  	);  } diff --git a/templates/edit_journey.html.ep b/templates/edit_journey.html.ep index 8fdc5b6..d36fc65 100644 --- a/templates/edit_journey.html.ep +++ b/templates/edit_journey.html.ep @@ -1,3 +1,4 @@ +<h1>Zugfahrt bearbeiten</h1>  % if ($error and $error eq 'notfound') {  	<div class="row">  		<div class="col s12"> @@ -25,6 +26,7 @@  	% }  	%= form_for '/journey/edit' => (method => 'POST') => begin  		%= csrf_field +		%= hidden_field 'journey_id' => param('journey_id')  		<div class="row">  			<div class="col s12">  				<p> @@ -35,6 +37,10 @@  					am  					<b><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></b>  				</p> +				<p> +					Nach einer Änderung können die ursprünglich eingetragenen +					Zeiten nicht mehr wiederhergestellt werden. +				</p>  				<table class="striped">  					<tr>  						<th scope="row">Zug</th> @@ -69,17 +75,14 @@  							%= text_field 'rt_arrival', id => 'real_arrival', class => 'validate', pattern => '[0-9][0-9]?[.][0-9][0-9]?[.][0-9][0-9][0-9][0-9] +[0-9][0-9]:[0-9][0-9]'  						</td>  					</tr> -					<tr> -						<th scope="row">Route</th> -						<td> -							%= text_area 'route', id => 'route', cols => 40, rows => 20 -						</td> -					</tr>  				</table>  			</div>  		</div>  		<div class="row"> -			<div class="col s3 m3 l3"> +			<div class="col s6 m6 l6 center-align"> +				<button class="btn waves-effect waves-light" type="submit" name="action" value="cancel"> +					Abbrechen +				</button>  			</div>  			<div class="col s6 m6 l6 center-align">  				<button class="btn waves-effect waves-light" type="submit" name="action" value="save"> @@ -87,8 +90,6 @@  					<i class="material-icons right">send</i>  				</button>  			</div> -			<div class="col s3 m3 l3"> -			</div>  		</div>  	%= end  % } diff --git a/templates/journey.html.ep b/templates/journey.html.ep index 3b84d67..b5c24a7 100644 --- a/templates/journey.html.ep +++ b/templates/journey.html.ep @@ -26,6 +26,9 @@  				am  				<b><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></b>  			</p> +			% if ($journey->{edited}) { +				<p>Die Ankunfts- und Abfahrtsdaten wurden nachträglich bearbeitet.</p> +			% }  			<table class="striped">  				<tr>  					<th scope="row">Zug</th> @@ -141,7 +144,7 @@  		<div class="col s6 m6 l6 center-align">  			%= form_for '/journey/edit' => (method => 'POST') => begin  				%= hidden_field 'journey_id' => param('journey_id') -				<button class="btn waves-effect waves-light" type="submit" name="action" value="edit" disabled="disabled"> +				<button class="btn waves-effect waves-light" type="submit" name="action" value="edit">  					Bearbeiten  				</button>  			%= end | 
