summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Friesel <derf@finalrewind.org>2022-07-11 22:09:26 +0200
committerDaniel Friesel <derf@finalrewind.org>2022-07-11 22:09:26 +0200
commit5eab0c14f4feb5b369d9e1605f0d1f8ba413bb6e (patch)
tree3ffda5aa6573903c8dccd429d873b0b86e8b0ff4
parent4deb0bde0b36a175922bb0b274087f1b19762c4c (diff)
optionally link to external departure boards where sensible (WiP)
-rwxr-xr-xlib/Travelynx.pm28
-rw-r--r--lib/Travelynx/Command/database.pm14
-rw-r--r--lib/Travelynx/Controller/Account.pm23
-rw-r--r--lib/Travelynx/Model/Users.pm43
-rw-r--r--templates/_checked_in.html.ep20
-rw-r--r--templates/account.html.ep15
-rw-r--r--templates/use_external_links.html.ep72
7 files changed, 198 insertions, 17 deletions
diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm
index 73182ed..de5ea18 100755
--- a/lib/Travelynx.pm
+++ b/lib/Travelynx.pm
@@ -1379,6 +1379,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');
diff --git a/lib/Travelynx/Command/database.pm b/lib/Travelynx/Command/database.pm
index e84cf54..32522be 100644
--- a/lib/Travelynx/Command/database.pm
+++ b/lib/Travelynx/Command/database.pm
@@ -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 {
diff --git a/lib/Travelynx/Controller/Account.pm b/lib/Travelynx/Controller/Account.pm
index 97ea8ad..f4f05d9 100644
--- a/lib/Travelynx/Controller/Account.pm
+++ b/lib/Travelynx/Controller/Account.pm
@@ -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) = @_;
diff --git a/lib/Travelynx/Model/Users.pm b/lib/Travelynx/Model/Users.pm
index 3d19831..061bb33 100644
--- a/lib/Travelynx/Model/Users.pm
+++ b/lib/Travelynx/Model/Users.pm
@@ -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;
diff --git a/templates/_checked_in.html.ep b/templates/_checked_in.html.ep
index d882501..2c37bbc 100644
--- a/templates/_checked_in.html.ep
+++ b/templates/_checked_in.html.ep
@@ -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>
% }
diff --git a/templates/account.html.ep b/templates/account.html.ep
index bce4dcb..7658237 100644
--- a/templates/account.html.ep
+++ b/templates/account.html.ep
@@ -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>
% }
@@ -145,6 +148,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>
</tr>
diff --git a/templates/use_external_links.html.ep b/templates/use_external_links.html.ep
new file mode 100644
index 0000000..f1c8c81
--- /dev/null
+++ b/templates/use_external_links.html.ep
@@ -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