diff options
| author | Daniel Friesel <derf@finalrewind.org> | 2019-05-20 19:15:21 +0200 | 
|---|---|---|
| committer | Daniel Friesel <derf@finalrewind.org> | 2019-05-20 19:15:21 +0200 | 
| commit | 1dc04eb45ad9d7208cbfa1d7eb046861ff43e0c2 (patch) | |
| tree | 4ca2a48c1cee83c71f4a06c80914ee191ec3c9b3 | |
| parent | 531cb95c1773fe459a2ef4c9f2adc8d89e75a62d (diff) | |
show journey suggestions on departure board as well1.6.0
| -rwxr-xr-x | lib/Travelynx.pm | 112 | ||||
| -rw-r--r-- | lib/Travelynx/Command/database.pm | 11 | ||||
| -rw-r--r-- | lib/Travelynx/Controller/Account.pm | 32 | ||||
| -rw-r--r-- | templates/_checked_in.html.ep | 4 | ||||
| -rw-r--r-- | templates/_checked_out.html.ep | 2 | ||||
| -rw-r--r-- | templates/_connections.html.ep | 8 | ||||
| -rw-r--r-- | templates/account.html.ep | 16 | ||||
| -rw-r--r-- | templates/changelog.html.ep | 17 | ||||
| -rw-r--r-- | templates/departures.html.ep | 61 | ||||
| -rw-r--r-- | templates/use_history.html.ep | 62 | 
10 files changed, 278 insertions, 47 deletions
| diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index d313b25..3e65963 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -317,7 +317,7 @@ sub startup {  		'checkin' => sub {  			my ( $self, $station, $train_id ) = @_; -			my $status = $self->get_departures( $station, 140, 30 ); +			my $status = $self->get_departures( $station, 140, 40 );  			if ( $status->{errstr} ) {  				return ( undef, $status->{errstr} );  			} @@ -753,6 +753,10 @@ sub startup {  				return $res_h->{id};  			} +			if ( $opt{readonly} ) { +				return; +			} +  			$self->pg->db->insert(  				'stations',  				{ @@ -1495,14 +1499,11 @@ sub startup {  	);  	$self->helper( -		'get_connection_targets' => sub { +		'get_latest_dest_id' => sub {  			my ( $self, %opt ) = @_; -			my $uid       = $opt{uid} // $self->current_user->{id}; -			my $threshold = $opt{threshold} -			  // DateTime->now( time_zone => 'Europe/Berlin' ) -			  ->subtract( weeks => 6 ); -			my $db = $opt{db} // $self->pg->db; +			my $uid = $opt{uid} // $self->current_user->{id}; +			my $db  = $opt{db} // $self->pg->db;  			my $journey = $db->select( 'in_transit', ['checkout_station_id'],  				{ user_id => $uid } )->hash; @@ -1525,6 +1526,37 @@ sub startup {  				return;  			} +			return $journey->{checkout_station_id}; +		} +	); + +	$self->helper( +		'get_connection_targets' => sub { +			my ( $self, %opt ) = @_; + +			my $uid = $opt{uid} //= $self->current_user->{id}; +			my $threshold = $opt{threshold} +			  // DateTime->now( time_zone => 'Europe/Berlin' ) +			  ->subtract( weeks => 6 ); +			my $db = $opt{db} //= $self->pg->db; +			my $min_count = $opt{min_count} // 3; + +			my $dest_id; + +			if ( $opt{ds100} ) { +				$dest_id = $self->get_station_id( +					ds100    => $opt{ds100}, +					readonly => 1 +				); +			} +			else { +				$dest_id = $self->get_latest_dest_id(%opt); +			} + +			if ( not $dest_id ) { +				return; +			} +  			my $res = $db->query(  				qq{  					select @@ -1539,11 +1571,12 @@ sub startup {  					order by count desc;  				},  				$uid, -				$journey->{checkout_station_id}, +				$dest_id,  				$threshold  			); -			my @destinations = $res->hashes->grep( sub { shift->{count} > 2 } ) -			  ->map( sub { shift->{dest} } )->each; +			my @destinations +			  = $res->hashes->grep( sub { shift->{count} >= $min_count } ) +			  ->map( sub                { shift->{dest} } )->each;  			return @destinations;  		}  	); @@ -1552,21 +1585,41 @@ sub startup {  		'get_connecting_trains' => sub {  			my ( $self, %opt ) = @_; -			my $status = $self->get_user_status; +			my $uid = $opt{uid} //= $self->current_user->{id}; +			my $use_history = $self->account_use_history($uid); + +			my ( $ds100, $exclude_via, $exclude_train_id, $exclude_before ); + +			if ( $opt{ds100} ) { +				if ( $use_history & 0x01 ) { +					$ds100 = $opt{ds100}; +				} +			} +			else { +				if ( $use_history & 0x02 ) { +					my $status = $self->get_user_status; +					$ds100            = $status->{arr_ds100}; +					$exclude_via      = $status->{dep_name}; +					$exclude_train_id = $status->{train_id}; +					$exclude_before   = $status->{real_arrival}->epoch; +				} +			} -			if ( not $status->{arr_ds100} ) { +			if ( not $ds100 ) {  				return;  			}  			my @destinations = $self->get_connection_targets(%opt); -			@destinations = grep { $_ ne $status->{dep_name} } @destinations; + +			if ($exclude_via) { +				@destinations = grep { $_ ne $exclude_via } @destinations; +			}  			if ( not @destinations ) {  				return;  			} -			my $stationboard -			  = $self->get_departures( $status->{arr_ds100}, 0, 60 ); +			my $stationboard = $self->get_departures( $ds100, 0, 40 );  			if ( $stationboard->{errstr} ) {  				return;  			} @@ -1576,16 +1629,19 @@ sub startup {  				if ( not $train->departure ) {  					next;  				} -				if ( $train->departure->epoch < $status->{real_arrival}->epoch ) +				if (    $exclude_before +					and $train->departure->epoch < $exclude_before )  				{  					next;  				} -				if ( $train->train_id eq $status->{train_id} ) { +				if (    $exclude_train_id +					and $train->train_id eq $exclude_train_id ) +				{  					next;  				}  				my @via = ( $train->route_post, $train->route_end );  				for my $dest (@destinations) { -					if ( $via_count{$dest} < 3 +					if ( $via_count{$dest} < 2  						and List::Util::any { $_ eq $dest } @via )  					{  						push( @results, [ $train, $dest ] ); @@ -1609,6 +1665,24 @@ sub startup {  	);  	$self->helper( +		'account_use_history' => sub { +			my ( $self, $uid, $value ) = @_; + +			if ($value) { +				$self->pg->db->update( +					'users', +					{ use_history => $value }, +					{ id          => $uid } +				); +			} +			else { +				return $self->pg->db->select( 'users', ['use_history'], +					{ id => $uid } )->hash->{use_history}; +			} +		} +	); + +	$self->helper(  		'get_user_travels' => sub {  			my ( $self, %opt ) = @_; @@ -2113,6 +2187,7 @@ sub startup {  	$authed_r->get('/account')->to('account#account');  	$authed_r->get('/account/privacy')->to('account#privacy');  	$authed_r->get('/account/hooks')->to('account#webhook'); +	$authed_r->get('/account/insight')->to('account#insight');  	$authed_r->get('/ajax/status_card.html')->to('traveling#status_card');  	$authed_r->get('/cancelled')->to('traveling#cancelled');  	$authed_r->get('/account/password')->to('account#password_form'); @@ -2128,6 +2203,7 @@ sub startup {  	$authed_r->get('/confirm_mail/:token')->to('account#confirm_mail');  	$authed_r->post('/account/privacy')->to('account#privacy');  	$authed_r->post('/account/hooks')->to('account#webhook'); +	$authed_r->post('/account/insight')->to('account#insight');  	$authed_r->post('/journey/add')->to('traveling#add_journey_form');  	$authed_r->post('/journey/edit')->to('traveling#edit_journey');  	$authed_r->post('/account/password')->to('account#change_password'); diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm index a15390d..99fcc61 100644 --- a/lib/Travelynx/Command/database.pm +++ b/lib/Travelynx/Command/database.pm @@ -535,6 +535,17 @@ my @migrations = (  			}  		);  	}, + +	# v12 -> v13 +	sub { +		my ($db) = @_; +		$db->query( +			qq{ +				alter table users add column use_history smallint default 255; +				update schema_version set version = 13; +			} +		); +	},  );  sub setup_db { diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm index e2bfd39..0275b96 100644 --- a/lib/Travelynx/Controller/Account.pm +++ b/lib/Travelynx/Controller/Account.pm @@ -232,6 +232,38 @@ sub privacy {  	}  } +sub insight { +	my ($self) = @_; + +	my $user        = $self->current_user; +	my $use_history = $self->account_use_history( $user->{id} ); + +	if ( $self->param('action') and $self->param('action') eq 'save' ) { +		if ( $self->param('on_departure') ) { +			$use_history |= 0x01; +		} +		else { +			$use_history &= ~0x01; +		} + +		if ( $self->param('on_arrival') ) { +			$use_history |= 0x02; +		} +		else { +			$use_history &= ~0x02; +		} + +		$self->account_use_history( $user->{id}, $use_history ); +		$self->flash( success => 'use_history' ); +		$self->redirect_to('account'); +	} + +	$self->param( on_departure => $use_history & 0x01 ? 1 : 0 ); +	$self->param( on_arrival   => $use_history & 0x02 ? 1 : 0 ); +	$self->render('use_history'); + +} +  sub webhook {  	my ($self) = @_; diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep index d5b14e5..ebe84e8 100644 --- a/templates/_checked_in.html.ep +++ b/templates/_checked_in.html.ep @@ -79,6 +79,10 @@  		% }  		% if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} < (20*60)) {  			% if (my @connections = get_connecting_trains()) { +				<span class="card-title" style="margin-top: 2ex;">Verbindungen</span> +				% if ($journey->{arrival_countdown} < 0) { +					<p>Zug auswählen zum Einchecken mit Zielwahl.</p> +				% }  				%= include '_connections', connections => \@connections, checkin_from => $journey->{arrival_countdown} < 0 ? $journey->{arr_ds100} : undef;  			% }  		% } diff --git a/templates/_checked_out.html.ep b/templates/_checked_out.html.ep index 18b613b..ca9373d 100644 --- a/templates/_checked_out.html.ep +++ b/templates/_checked_out.html.ep @@ -5,6 +5,8 @@  			bis <a href="/s/<%= $journey->{arr_ds100} %>"><%= $journey->{arr_name} %></a></p>  		% if (now()->epoch - $journey->{timestamp}->epoch < (30*60)) {  			% if (my @connections = get_connecting_trains()) { +				<span class="card-title" style="margin-top: 2ex;">Verbindungen</span> +				<p>Zug auswählen zum Einchecken mit Zielwahl.</p>  				%= include '_connections', connections => \@connections, checkin_from => $journey->{arr_ds100};  			% }  		% } diff --git a/templates/_connections.html.ep b/templates/_connections.html.ep index 1c7f003..d421d4e 100644 --- a/templates/_connections.html.ep +++ b/templates/_connections.html.ep @@ -1,8 +1,4 @@ -<span class="card-title" style="margin-top: 2ex;">Verbindungen</span> -% if ($checkin_from) { -	<p>Zug auswählen zum Einchecken mit Zielwahl.</p> -% } -<div class="hide-on-med-and-up"><table><tbody> +<div class="hide-on-med-and-up"><table class="striped"><tbody>  	% for my $res (@{$connections}) {  		% my ($train, $via) = @{$res};  		<tr> @@ -30,7 +26,7 @@  		</tr>  	% }  </tbody></table></div> -<div class="hide-on-small-only"><table><tbody> +<div class="hide-on-small-only"><table class="striped"><tbody>  	% for my $res (@{$connections}) {  		% my ($train, $via) = @{$res};  		<tr> diff --git a/templates/account.html.ep b/templates/account.html.ep index 2c58a7b..627be85 100644 --- a/templates/account.html.ep +++ b/templates/account.html.ep @@ -16,6 +16,9 @@  					% elsif ($success eq 'privacy') {  						<span class="card-title">Einstellungen zu öffentliche Account-Daten geändert</span>  					% } +					% elsif ($success eq 'use_history') { +						<span class="card-title">Einstellungen zu vorgeschlagenen Verbindungen geändert</span> +					% }  					% elsif ($success eq 'webhook') {  						<span class="card-title">Web Hook aktualisiert</span>  					% } @@ -28,6 +31,7 @@  <h1>Account</h1>  % my $acc = current_user();  % my $hook = get_webhook(); +% my $use_history = account_use_history($acc->{id});  <div class="row">  	<div class="col s12">  		<table class="striped"> @@ -44,6 +48,18 @@  				<td><a href="/account/password"><i class="material-icons">edit</i></a></td>  			</tr>  			<tr> +				<th scope="row">Verbindungen</th> +				<td> +					<a href="/account/insight"><i class="material-icons">edit</i></a> +					% if ($use_history & 0x03) { +						Vorschläge aktiv +					% } +					% else { +						<span style="color: #999999;">Vorschläge deaktiviert</span> +					% } +				</td> +			</tr> +			<tr>  				<th scope="row">Öffentliche Daten</th>  				<td>  					<a href="/account/privacy"><i class="material-icons">edit</i></a> diff --git a/templates/changelog.html.ep b/templates/changelog.html.ep index fec21a3..9c3d13f 100644 --- a/templates/changelog.html.ep +++ b/templates/changelog.html.ep @@ -2,6 +2,23 @@  <div class="row">  	<div class="col s12 m1 l1"> +		1.6 +	</div> +	<div class="col s12 m11 l11"> +		<p> +			<i class="material-icons left">add</i> Anzeige von häufig genutzten +			Verbindungen in der Abfahrtstafel. Wie bei den Anschlusszügen kann +			darüber direkt (inkl. Vorauswahl des Ziels) eingecheckt werden. +		</p> +		<p> +			<i class="material-icons left">add</i> Konfigurationsseite, um die +			Heuristik für Anschlusszüge und häufige Verbindungen zu deaktivieren. +		</p> +	</div> +</div> + +<div class="row"> +	<div class="col s12 m1 l1">  		1.5  	</div>  	<div class="col s12 m11 l11"> diff --git a/templates/departures.html.ep b/templates/departures.html.ep index 3c9638e..7e98d9c 100644 --- a/templates/departures.html.ep +++ b/templates/departures.html.ep @@ -1,7 +1,13 @@  <div class="row"> -	<div class="col s12"> -		% my $status = $self->get_user_status; -		% if ($status->{checked_in}) { +	<div class="col s12 center-align"><b> +		%= $station +	</b></div> +</div> +% my $status = $self->get_user_status; +% my $have_connections = 0; +% if ($status->{checked_in}) { +	<div class="row"> +		<div class="col s12">  			<div class="card">  				<div class="card-content">  					<span class="card-title">Aktuell eingecheckt</span> @@ -14,31 +20,40 @@  					</a>  				</div>  			</div> -		% } -		% elsif ($status->{timestamp_delta} < 180) { +		</div> +	</div> +% } +% elsif ($status->{timestamp_delta} < 180) { +	<div class="row"> +		<div class="col s12">  			%= include '_checked_out', journey => $status; -		% } +		</div>  	</div> -</div> +% } +% elsif (not param('train') and my @connections = get_connecting_trains(ds100 => $ds100)) { +	% $have_connections = 1; +	<div class="row"> +		<div class="col s12"> +			<p>Häufig genutzte Verbindungen – Zug auswählen zum Einchecken mit Zielwahl</p> +			%= include '_connections', connections => \@connections, checkin_from => $ds100; +		</div> +	</div> +% }  <div class="row">  	<div class="col s12"> -		%= $station -		% if (@{$results}) { -			– Zug auswählen zum Einchecken. -		% } -		% else { -			– Keine Abfahrten gefunden. Ein Checkin ist frühestens 30 Minuten vor -			und maximal 120 Minuten nach Abfahrt möglich. -		% } -		<br/> +		<p> +			% if ($have_connections) { +				Alle Abfahrten – +			% } +			% if (@{$results}) { +				Zug auswählen zum Einchecken. +			% } +			% else { +				Keine Abfahrten gefunden. Ein Checkin ist frühestens 30 Minuten vor +				und maximal 120 Minuten nach Abfahrt möglich. +			% } +		</p>  		<table class="striped"> -			<thead> -				<tr> -					<th>Zug</th> -					<th></th> -					<th>Abfahrt</th> -				</tr> -			</thead>  			<tbody>  				% for my $result (@{$results}) {  					% my $td_class = ''; diff --git a/templates/use_history.html.ep b/templates/use_history.html.ep new file mode 100644 index 0000000..e8e129f --- /dev/null +++ b/templates/use_history.html.ep @@ -0,0 +1,62 @@ +<h1>Bevorzugte Verbindungen</h1> +<div class="row"> +	<div class="col s12"> +		<p> +			Travelynx kann anhand deiner vergangenen Fahrten Verbindungen zum +			Einchecken vorschlagen. Fährst zu z.B regelmäßig von Dortmund Hbf +			nach Essen Hbf, werden dir in Dortmund bevorzugt Züge angezeigt, die über +			Essen fahren.  Bei Auswahl dieser wird nicht nur in den Zug eingecheckt, +			sondern auch direkt Essen Hbf als Ziel eingetragen. +		<p/> +<!--		<p> +			Falls du das nicht nützlich findest oder nicht möchtest, dass deine +			regelmäßigen (Anschluss-)Züge auf deinem Bildschirm sichtbar sind, +			kannst du dieses Feature hier +			ausschalten. +		</p> --> +	</div> +</div> +<h2>Vorschläge aktiv für:</h2> +%= form_for '/account/insight' => (method => 'POST') => begin +	%= csrf_field +	<div class="row"> +		<div class="input-field col s12"> +			<label> +				%= check_box on_departure => 1 +				<span>Abfahrtstafel</span> +			</label> +		</div> +	</div> +	<div class="row"> +		<div class="col s12"> +			Zeige häufige Fahrten im Abfahrtsmonitor. +		</div> +	</div> +	<div class="row"> +		<div class="input-field col s12"> +			<label> +				%= check_box on_arrival => 1 +				<span>Reisestatus</span> +			</label> +		</div> +	</div> +	<div class="row"> +		<div class="col s12"> +			Zeige Anschlussmöglichkeiten kurz vor Ankunft am Ziel der aktuellen +			Reise. Sobald es erreicht wurde, ist über diese Liste auch ein Checkin +			ohne Umweg über die Abfahrtstafel möglich. +		</div> +	</div> +	<div class="row"> +		<div class="col s3 m3 l3"> +		</div> +		<div class="col s6 m6 l6 center-align"> +			<button class="btn waves-effect waves-light" type="submit" name="action" value="save"> +				Speichern +				<i class="material-icons right">send</i> +			</button> +		</div> +		<div class="col s3 m3 l3"> +		</div> +	</div> +%= end | 
