optionally link to external departure boards where sensible (WiP)

This commit is contained in:
Daniel Friesel 2022-07-11 22:09:26 +02:00
parent 4deb0bde0b
commit 5eab0c14f4
No known key found for this signature in database
GPG key ID: 100D5BFB5166E005
7 changed files with 198 additions and 17 deletions

View file

@ -1378,6 +1378,16 @@ sub startup {
}
);
$self->helper(
'resolve_sb_template' => sub {
my ( $self, $template, %opt ) = @_;
my $ret = $template;
$ret =~ s{[{]eva[}]}{$opt{eva}}g;
$ret =~ s{[{]name[}]}{$opt{name}}g;
return $ret;
}
);
$self->helper(
'get_connection_targets' => sub {
my ( $self, %opt ) = @_;
@ -1957,16 +1967,20 @@ sub startup {
);
if ( $latest_cancellation and $latest_cancellation->{cancelled} ) {
if ( my $station
= $self->app->station_by_eva
->{ $latest_cancellation->{dep_eva} } )
if (
my $station = $self->app->station_by_eva->{
$latest_cancellation->{dep_eva}
}
)
{
$latest_cancellation->{dep_ds100} = $station->[0];
$latest_cancellation->{dep_name} = $station->[1];
}
if ( my $station
= $self->app->station_by_eva
->{ $latest_cancellation->{arr_eva} } )
if (
my $station = $self->app->station_by_eva->{
$latest_cancellation->{arr_eva}
}
)
{
$latest_cancellation->{arr_ds100} = $station->[0];
$latest_cancellation->{arr_name} = $station->[1];
@ -2554,6 +2568,7 @@ sub startup {
$authed_r->get('/account/hooks')->to('account#webhook');
$authed_r->get('/account/traewelling')->to('traewelling#settings');
$authed_r->get('/account/insight')->to('account#insight');
$authed_r->get('/account/services')->to('account#services');
$authed_r->get('/ajax/status_card.html')->to('traveling#status_card');
$authed_r->get('/cancelled')->to('traveling#cancelled');
$authed_r->get('/fgr')->to('passengerrights#list_candidates');
@ -2577,6 +2592,7 @@ sub startup {
$authed_r->post('/account/hooks')->to('account#webhook');
$authed_r->post('/account/traewelling')->to('traewelling#settings');
$authed_r->post('/account/insight')->to('account#insight');
$authed_r->post('/account/services')->to('account#services');
$authed_r->post('/journey/add')->to('traveling#add_journey_form');
$authed_r->post('/journey/comment')->to('traveling#comment_form');
$authed_r->post('/journey/edit')->to('traveling#edit_journey');

View file

@ -1069,6 +1069,20 @@ my @migrations = (
}
);
},
# v24 -> v25
# travelynx 1.23 adds optional links to external services, e.g.
# DBF or marudor.de departure boards
sub {
my ($db) = @_;
$db->query(
qq{
alter table users add column external_services smallint;
comment on column users.external_services is 'Which external service to use for stationboard or routing links';
update schema_version set version = 25;
}
);
},
);
sub setup_db {

View file

@ -375,6 +375,29 @@ sub insight {
}
sub services {
my ($self) = @_;
my $user = $self->current_user;
if ( $self->param('action') and $self->param('action') eq 'save' ) {
my $sb = $self->param('stationboard');
my $value = 0;
if ( $sb =~ m{ ^ \d+ $ }x and $sb >= 0 and $sb <= 3 ) {
$value = int($sb);
}
$self->users->use_external_services(
uid => $user->{id},
set => $value
);
$self->flash( success => 'external' );
$self->redirect_to('account');
}
$self->param( stationboard =>
$self->users->use_external_services( uid => $user->{id} ) );
$self->render('use_external_links');
}
sub webhook {
my ($self) = @_;

View file

@ -10,6 +10,13 @@ use 5.020;
use DateTime;
my @sb_templates = (
undef,
[ 'DBF', 'https://dbf.finalrewind.org/{name}' ],
[ 'marudor.de', 'https://marudor.de/{name}' ],
[ 'NVM', 'https://nvm.finalrewind.org/board/{eva}' ],
);
sub new {
my ( $class, %opt ) = @_;
@ -286,7 +293,7 @@ sub get_data {
my $user = $db->select(
'users',
'id, name, status, public_level, email, '
'id, name, status, public_level, email, external_services, '
. 'extract(epoch from registered_at) as registered_at_ts, '
. 'extract(epoch from last_seen) as last_seen_ts, '
. 'extract(epoch from deletion_requested) as deletion_requested_ts',
@ -294,11 +301,17 @@ sub get_data {
)->hash;
if ($user) {
return {
id => $user->{id},
name => $user->{name},
status => $user->{status},
is_public => $user->{public_level},
email => $user->{email},
id => $user->{id},
name => $user->{name},
status => $user->{status},
is_public => $user->{public_level},
email => $user->{email},
sb_name => $user->{external_services}
? $sb_templates[ $user->{external_services} & 0x07 ][0]
: undef,
sb_template => $user->{external_services}
? $sb_templates[ $user->{external_services} & 0x07 ][1]
: undef,
registered_at => DateTime->from_epoch(
epoch => $user->{registered_at_ts},
time_zone => 'Europe/Berlin'
@ -478,6 +491,24 @@ sub use_history {
}
}
sub use_external_services {
my ( $self, %opt ) = @_;
my $db = $opt{db} // $self->{pg}->db;
my $uid = $opt{uid};
my $value = $opt{set};
if ($value) {
if ( $value < 0 or $value > 3 ) {
$value = 0;
}
$db->update( 'users', { external_services => $value }, { id => $uid } );
}
else {
return $db->select( 'users', ['external_services'], { id => $uid } )
->hash->{external_services};
}
}
sub get_webhook {
my ( $self, %opt ) = @_;
my $db = $opt{db} // $self->{pg}->db;

View file

@ -1,3 +1,4 @@
% my $user = current_user();
<div class="autorefresh">
<div class="card">
<div class="card-content">
@ -102,7 +103,12 @@
% }
</div>
<div style="float: right; text-align: right;">
<b><%= $journey->{arr_name} %></b><br/>
% if ($user->{sb_template}) {
<b><a href="<%= resolve_sb_template($user->{sb_template}, name => $journey->{arr_name}, eva => $journey->{arr_eva}) %>" class="unmarked"><%= $journey->{arr_name} %></a></b><br/>
% }
% else {
<b><%= $journey->{arr_name} %></b><br/>
% }
% if ($journey->{real_arrival}->epoch) {
<b><%= $journey->{real_arrival}->strftime('%H:%M') %></b>
% if ($journey->{real_arrival}->epoch != $journey->{sched_arrival}->epoch) {
@ -250,14 +256,14 @@
% }
<a class="action-share blue-text right"
style="margin-right: 0;"
% if (current_user()->{is_public} & 0x04 and $journey->{comment}) {
% if ($user->{is_public} & 0x04 and $journey->{comment}) {
data-text="<%= $journey->{comment} %> (@ <%= $journey->{train_type} %> <%= $journey->{train_no} %> → <%= $journey->{arr_name} %>) #travelynx"
% }
% else {
data-text="Ich bin gerade <%= $attrib %> <%= $journey->{train_type} %> <%= $journey->{train_no} %> nach <%= $journey->{arr_name} %> #travelynx"
% }
% if (current_user()->{is_public} & 0x02) {
data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= current_user->{name} %>/<%= $journey->{sched_departure}->epoch %>"
% if ($user->{is_public} & 0x02) {
data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= $user->{name} %>/<%= $journey->{sched_departure}->epoch %>"
% }
>
<i class="material-icons left" aria-hidden="true">share</i> Teilen
@ -309,7 +315,11 @@
<tbody>
% for my $station (@{$journey->{route_after}}) {
% my $is_dest = ($journey->{arr_name} and $station->[0] eq $journey->{arr_name});
<tr><td><a style="<%= $is_dest? 'font-weight: bold;' : '' %>" class="action-checkout" data-station="<%= $station->[0] %>"><%= $station->[0] %>
<tr><td>
% if ($user->{sb_template}) {
<a href="<%= resolve_sb_template($user->{sb_template}, name => $station->[0], eva => $station->[1]{eva}) %>"><i class="material-icons tiny">info</i></a>
% }
<a style="<%= $is_dest? 'font-weight: bold;' : '' %>" class="action-checkout" data-station="<%= $station->[0] %>"><%= $station->[0] %>
% if ($station->[2] and $station->[2] eq 'cancelled') {
<span style="float: right;">entfällt</span>
% }

View file

@ -25,6 +25,9 @@
% elsif ($success eq 'use_history') {
<span class="card-title">Einstellungen zu vorgeschlagenen Verbindungen geändert</span>
% }
% elsif ($success eq 'external') {
<span class="card-title">Einstellungen zu externen Diensten geändert</span>
% }
% elsif ($success eq 'webhook') {
<span class="card-title">Web Hook aktualisiert</span>
% }
@ -144,6 +147,18 @@
% }
</td>
</tr>
<tr>
<th scope="row">Externe Dienste</th>
<td>
<a href="/account/services"><i class="material-icons">edit</i></a>
% if ($acc->{sb_name}) {
Abfahrtstafel: <%= $acc->{sb_name} %>
% }
% else {
<span style="color: #999999;">Keine</span>
% }
</td>
</tr>
<tr>
<th scope="row">Registriert am</th>
<td><%= $acc->{registered_at}->strftime('%d.%m.%Y %H:%M') %></td>

View file

@ -0,0 +1,72 @@
<h1>Externe Dienste</h1>
<div class="row">
<div class="col s12">
<p>
Travelynx kann an geeigneten Stellen Links zu externen Diensten
(z.B. Abfahrstafeln oder Informationen zum gerade genutzten Zug)
einbinden. Hier lässt sich konfigurieren, welcher Dienst für welche
Art von Informationen genutzt wird.
<p/>
</div>
</div>
<h2>Abfahrtstafel</h2>
%= form_for '/account/services' => (method => 'POST') => begin
%= csrf_field
<div class="row">
<div class="col s12">
Angaben zu anderen an einer Station verkehrenden Verkehrsmitteln
</div>
</div>
<div class="row">
<div class="input-field col s12">
<div>
<label>
%= radio_button stationboard => '0'
<span>Keine</span>
</label>
</div>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<div>
<label>
%= radio_button stationboard => '1'
<span><a href="https://dbf.finalrewind.org/">DBF</a></span>
</label>
</div>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<div>
<label>
%= radio_button stationboard => '2'
<span><a href="https://marudor.de/">marudor.de</a></span>
</label>
</div>
</div>
</div>
<div class="row">
<div class="input-field col s12">
<div>
<label>
%= radio_button stationboard => '3'
<span><a href="https://nvm.finalrewind.org/">NVM</a></span>
</label>
</div>
</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