set visibility per journey (wip)
some odds and ends left to polish, but ready for testing
This commit is contained in:
parent
fb3878665b
commit
6d261197e3
16 changed files with 883 additions and 382 deletions
|
@ -420,6 +420,25 @@ sub startup {
|
|||
}
|
||||
);
|
||||
|
||||
$self->helper(
|
||||
'visibility_icon' => sub {
|
||||
my ( $self, $visibility ) = @_;
|
||||
if ( $visibility eq 'public' ) {
|
||||
return 'language';
|
||||
}
|
||||
if ( $visibility eq 'travelynx' ) {
|
||||
return 'lock_open';
|
||||
}
|
||||
if ( $visibility eq 'unlisted' ) {
|
||||
return 'lock_outline';
|
||||
}
|
||||
if ( $visibility eq 'private' ) {
|
||||
return 'lock';
|
||||
}
|
||||
return 'help_outline';
|
||||
}
|
||||
);
|
||||
|
||||
$self->helper(
|
||||
'checkin' => sub {
|
||||
my ( $self, %opt ) = @_;
|
||||
|
@ -1348,7 +1367,8 @@ sub startup {
|
|||
uid => $uid,
|
||||
db => $db,
|
||||
with_data => 1,
|
||||
with_timestamps => 1
|
||||
with_timestamps => 1,
|
||||
with_visibility => 1,
|
||||
);
|
||||
|
||||
if ($in_transit) {
|
||||
|
@ -1425,6 +1445,8 @@ sub startup {
|
|||
messages => $in_transit->{messages},
|
||||
extra_data => $in_transit->{data},
|
||||
comment => $in_transit->{user_data}{comment},
|
||||
visibility => $in_transit->{visibility},
|
||||
visibility_str => $in_transit->{visibility_str},
|
||||
};
|
||||
|
||||
my $traewelling = $self->traewelling->get(
|
||||
|
@ -2205,6 +2227,7 @@ sub startup {
|
|||
$authed_r->get('/history/:year/:month')->to('traveling#monthly_history');
|
||||
$authed_r->get('/journey/add')->to('traveling#add_journey_form');
|
||||
$authed_r->get('/journey/comment')->to('traveling#comment_form');
|
||||
$authed_r->get('/journey/visibility')->to('traveling#visibility_form');
|
||||
$authed_r->get('/journey/:id')->to('traveling#journey_details');
|
||||
$authed_r->get('/s/*station')->to('traveling#station');
|
||||
$authed_r->get('/confirm_mail/:token')->to('account#confirm_mail');
|
||||
|
@ -2215,6 +2238,7 @@ sub startup {
|
|||
$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/visibility')->to('traveling#visibility_form');
|
||||
$authed_r->post('/journey/edit')->to('traveling#edit_journey');
|
||||
$authed_r->post('/journey/passenger_rights/*filename')
|
||||
->to('passengerrights#generate');
|
||||
|
|
|
@ -1312,6 +1312,120 @@ my @migrations = (
|
|||
}
|
||||
);
|
||||
},
|
||||
|
||||
# v32 -> v33
|
||||
# add optional per-status visibility that overrides global visibility
|
||||
sub {
|
||||
my ($db) = @_;
|
||||
$db->query(
|
||||
qq{
|
||||
alter table journeys add column visibility smallint;
|
||||
alter table in_transit add column visibility smallint;
|
||||
drop view journeys_str;
|
||||
drop view in_transit_str;
|
||||
create view journeys_str as select
|
||||
journeys.id as journey_id, user_id,
|
||||
train_type, train_line, train_no, train_id,
|
||||
extract(epoch from checkin_time) as checkin_ts,
|
||||
extract(epoch from sched_departure) as sched_dep_ts,
|
||||
extract(epoch from real_departure) as real_dep_ts,
|
||||
checkin_station_id as dep_eva,
|
||||
dep_station.ds100 as dep_ds100,
|
||||
dep_station.name as dep_name,
|
||||
dep_station.lat as dep_lat,
|
||||
dep_station.lon as dep_lon,
|
||||
extract(epoch from checkout_time) as checkout_ts,
|
||||
extract(epoch from sched_arrival) as sched_arr_ts,
|
||||
extract(epoch from real_arrival) as real_arr_ts,
|
||||
checkout_station_id as arr_eva,
|
||||
arr_station.ds100 as arr_ds100,
|
||||
arr_station.name as arr_name,
|
||||
arr_station.lat as arr_lat,
|
||||
arr_station.lon as arr_lon,
|
||||
polylines.polyline as polyline,
|
||||
visibility,
|
||||
cancelled, edited, route, messages, user_data,
|
||||
dep_platform, arr_platform
|
||||
from journeys
|
||||
left join polylines on polylines.id = polyline_id
|
||||
left join stations as dep_station on checkin_station_id = dep_station.eva
|
||||
left join stations as arr_station on checkout_station_id = arr_station.eva
|
||||
;
|
||||
create view in_transit_str as select
|
||||
user_id,
|
||||
train_type, train_line, train_no, train_id,
|
||||
extract(epoch from checkin_time) as checkin_ts,
|
||||
extract(epoch from sched_departure) as sched_dep_ts,
|
||||
extract(epoch from real_departure) as real_dep_ts,
|
||||
checkin_station_id as dep_eva,
|
||||
dep_station.ds100 as dep_ds100,
|
||||
dep_station.name as dep_name,
|
||||
dep_station.lat as dep_lat,
|
||||
dep_station.lon as dep_lon,
|
||||
extract(epoch from checkout_time) as checkout_ts,
|
||||
extract(epoch from sched_arrival) as sched_arr_ts,
|
||||
extract(epoch from real_arrival) as real_arr_ts,
|
||||
checkout_station_id as arr_eva,
|
||||
arr_station.ds100 as arr_ds100,
|
||||
arr_station.name as arr_name,
|
||||
arr_station.lat as arr_lat,
|
||||
arr_station.lon as arr_lon,
|
||||
polylines.polyline as polyline,
|
||||
visibility,
|
||||
cancelled, route, messages, user_data,
|
||||
dep_platform, arr_platform, data
|
||||
from in_transit
|
||||
left join polylines on polylines.id = polyline_id
|
||||
left join stations as dep_station on checkin_station_id = dep_station.eva
|
||||
left join stations as arr_station on checkout_station_id = arr_station.eva
|
||||
;
|
||||
}
|
||||
);
|
||||
my $res = $db->select( 'users', [ 'id', 'public_level' ] );
|
||||
while ( my $row = $res->hash ) {
|
||||
my $old_level = $row->{public_level};
|
||||
my $new_level = 0;
|
||||
if ( $old_level & 0x01 ) {
|
||||
|
||||
# status: account required
|
||||
$new_level = 80;
|
||||
}
|
||||
if ( $old_level & 0x02 ) {
|
||||
|
||||
# status: public
|
||||
$new_level = 100;
|
||||
}
|
||||
if ( $old_level & 0x04 ) {
|
||||
|
||||
# comment public
|
||||
$new_level |= 0x80;
|
||||
}
|
||||
if ( $old_level & 0x10 ) {
|
||||
|
||||
# past: account required
|
||||
$new_level |= 0x100;
|
||||
}
|
||||
if ( $old_level & 0x20 ) {
|
||||
|
||||
# past: public
|
||||
$new_level |= 0x200;
|
||||
}
|
||||
if ( $old_level & 0x40 ) {
|
||||
|
||||
# past: infinite (default is 4 weeks)
|
||||
$new_level |= 0x400;
|
||||
}
|
||||
my $r = $db->update(
|
||||
'users',
|
||||
{ public_level => $new_level },
|
||||
{ id => $row->{id} }
|
||||
)->rows;
|
||||
if ( $r != 1 ) {
|
||||
die("oh no");
|
||||
}
|
||||
}
|
||||
$db->update( 'schema_version', { version => 33 } );
|
||||
},
|
||||
);
|
||||
|
||||
sub sync_stations {
|
||||
|
|
|
@ -9,6 +9,22 @@ use Crypt::Eksblowfish::Bcrypt qw(bcrypt en_base64);
|
|||
use JSON;
|
||||
use UUID::Tiny qw(:std);
|
||||
|
||||
my %visibility_itoa = (
|
||||
100 => 'public',
|
||||
80 => 'travelynx',
|
||||
60 => 'followers',
|
||||
30 => 'unlisted',
|
||||
10 => 'private',
|
||||
);
|
||||
|
||||
my %visibility_atoi = (
|
||||
public => 100,
|
||||
travelynx => 80,
|
||||
followers => 60,
|
||||
unlisted => 30,
|
||||
private => 10,
|
||||
);
|
||||
|
||||
# Internal Helpers
|
||||
|
||||
sub hash_password {
|
||||
|
@ -438,50 +454,30 @@ sub privacy {
|
|||
my $public_level = $user->{is_public};
|
||||
|
||||
if ( $self->param('action') and $self->param('action') eq 'save' ) {
|
||||
if ( $self->param('status_level') eq 'intern' ) {
|
||||
$public_level |= 0x01;
|
||||
$public_level &= ~0x02;
|
||||
}
|
||||
elsif ( $self->param('status_level') eq 'extern' ) {
|
||||
$public_level |= 0x02;
|
||||
$public_level &= ~0x01;
|
||||
}
|
||||
else {
|
||||
$public_level &= ~0x03;
|
||||
my %opt;
|
||||
my $default_visibility
|
||||
= $visibility_atoi{ $self->param('status_level') };
|
||||
if ( defined $default_visibility ) {
|
||||
$opt{default_visibility} = $default_visibility;
|
||||
}
|
||||
|
||||
# public comment with non-public status does not make sense
|
||||
if ( $self->param('public_comment')
|
||||
and $self->param('status_level') ne 'private' )
|
||||
{
|
||||
$public_level |= 0x04;
|
||||
}
|
||||
else {
|
||||
$public_level &= ~0x04;
|
||||
}
|
||||
$opt{comments_visible} = $self->param('public_comment') ? 1 : 0;
|
||||
|
||||
$opt{past_all} = $self->param('history_age') eq 'infinite' ? 1 : 0;
|
||||
|
||||
if ( $self->param('history_level') eq 'intern' ) {
|
||||
$public_level |= 0x10;
|
||||
$public_level &= ~0x20;
|
||||
$opt{past_visible} = 1;
|
||||
}
|
||||
elsif ( $self->param('history_level') eq 'extern' ) {
|
||||
$public_level |= 0x20;
|
||||
$public_level &= ~0x10;
|
||||
$opt{past_visible} = 2;
|
||||
}
|
||||
else {
|
||||
$public_level &= ~0x30;
|
||||
}
|
||||
|
||||
if ( $self->param('history_age') eq 'infinite' ) {
|
||||
$public_level |= 0x40;
|
||||
}
|
||||
else {
|
||||
$public_level &= ~0x40;
|
||||
$opt{past_visible} = 0;
|
||||
}
|
||||
|
||||
$self->users->set_privacy(
|
||||
uid => $user->{id},
|
||||
level => $public_level
|
||||
uid => $user->{id},
|
||||
%opt
|
||||
);
|
||||
|
||||
$self->flash( success => 'privacy' );
|
||||
|
@ -489,18 +485,14 @@ sub privacy {
|
|||
}
|
||||
else {
|
||||
$self->param(
|
||||
status_level => $public_level & 0x01 ? 'intern'
|
||||
: $public_level & 0x02 ? 'extern'
|
||||
: 'private'
|
||||
);
|
||||
$self->param( public_comment => $public_level & 0x04 ? 1 : 0 );
|
||||
status_level => $visibility_itoa{ $user->{default_visibility} } );
|
||||
$self->param( public_comment => $user->{comments_visible} );
|
||||
$self->param(
|
||||
history_level => $public_level & 0x10 ? 'intern'
|
||||
: $public_level & 0x20 ? 'extern'
|
||||
: 'private'
|
||||
history_level => $user->{past_visible} & 0x01 ? 'intern'
|
||||
: $user->{past_visible} & 0x02 ? 'extern'
|
||||
: 'private'
|
||||
);
|
||||
$self->param(
|
||||
history_age => $public_level & 0x40 ? 'infinite' : 'month' );
|
||||
$self->param( history_age => $user->{past_all} ? 'infinite' : 'month' );
|
||||
$self->render( 'privacy', name => $user->{name} );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -370,6 +370,14 @@ sub get_connecting_trains_p {
|
|||
return $promise;
|
||||
}
|
||||
|
||||
sub compute_effective_visibility {
|
||||
my ( $self, $default_visibility, $journey_visibility ) = @_;
|
||||
if ( $journey_visibility eq 'default' ) {
|
||||
return $default_visibility;
|
||||
}
|
||||
return $journey_visibility;
|
||||
}
|
||||
|
||||
# Controllers
|
||||
|
||||
sub homepage {
|
||||
|
@ -378,6 +386,10 @@ sub homepage {
|
|||
my $status = $self->get_user_status;
|
||||
my @recent_targets;
|
||||
if ( $status->{checked_in} ) {
|
||||
my $journey_visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$self->current_user->{default_visibility_str},
|
||||
$status->{visibility_str} );
|
||||
if ( defined $status->{arrival_countdown}
|
||||
and $status->{arrival_countdown} < ( 40 * 60 ) )
|
||||
{
|
||||
|
@ -389,11 +401,10 @@ sub homepage {
|
|||
'landingpage',
|
||||
version => $self->app->config->{version}
|
||||
// 'UNKNOWN',
|
||||
user_status => $status,
|
||||
connections => $connecting_trains,
|
||||
transit_fyi => $transit_fyi,
|
||||
with_autocomplete => 1,
|
||||
with_geolocation => 1
|
||||
user_status => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
connections => $connecting_trains,
|
||||
transit_fyi => $transit_fyi,
|
||||
);
|
||||
$self->users->mark_seen(
|
||||
uid => $self->current_user->{id} );
|
||||
|
@ -404,9 +415,8 @@ sub homepage {
|
|||
'landingpage',
|
||||
version => $self->app->config->{version}
|
||||
// 'UNKNOWN',
|
||||
user_status => $status,
|
||||
with_autocomplete => 1,
|
||||
with_geolocation => 1
|
||||
user_status => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
);
|
||||
$self->users->mark_seen(
|
||||
uid => $self->current_user->{id} );
|
||||
|
@ -414,6 +424,16 @@ sub homepage {
|
|||
)->wait;
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$self->render(
|
||||
'landingpage',
|
||||
version => $self->app->config->{version} // 'UNKNOWN',
|
||||
user_status => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
);
|
||||
$self->users->mark_seen( uid => $self->current_user->{id} );
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
@recent_targets = uniq_by { $_->{eva} }
|
||||
|
@ -439,6 +459,26 @@ sub homepage {
|
|||
}
|
||||
}
|
||||
|
||||
sub status_token_ok {
|
||||
my ( $self, $status, $ts2_ext ) = @_;
|
||||
my $token = $self->param('token') // q{};
|
||||
|
||||
my ( $eva, $ts, $ts2 ) = split( qr{-}, $token );
|
||||
if ( not $ts ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$ts2 //= $ts2_ext;
|
||||
|
||||
if ( $eva == $status->{dep_eva}
|
||||
and $ts == $status->{timestamp}->epoch
|
||||
and $ts2 == $status->{sched_departure}->epoch )
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
sub user_status {
|
||||
my ($self) = @_;
|
||||
|
||||
|
@ -446,47 +486,33 @@ sub user_status {
|
|||
my $ts = $self->stash('ts') // 0;
|
||||
my $user = $self->users->get_privacy_by_name( name => $name );
|
||||
|
||||
if ( not $user or not $user->{public_level} & 0x03 ) {
|
||||
if ( not $user ) {
|
||||
$self->render('not_found');
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $user->{public_level} & 0x01 and not $self->is_user_authenticated ) {
|
||||
$self->render( 'login', redirect_to => $self->req->url );
|
||||
return;
|
||||
}
|
||||
|
||||
my $status = $self->get_user_status( $user->{id} );
|
||||
my $journey;
|
||||
|
||||
if (
|
||||
$ts
|
||||
and ( not $status->{checked_in}
|
||||
or $status->{sched_departure}->epoch != $ts )
|
||||
and (
|
||||
$user->{public_level} & 0x20
|
||||
or ( $user->{public_level} & 0x10
|
||||
and $self->is_user_authenticated )
|
||||
)
|
||||
)
|
||||
{
|
||||
for my $candidate (
|
||||
$self->journeys->get(
|
||||
uid => $user->{id},
|
||||
limit => 10,
|
||||
limit => 20,
|
||||
)
|
||||
)
|
||||
{
|
||||
if ( $candidate->{sched_dep_ts} eq $ts ) {
|
||||
$journey = $self->journeys->get_single(
|
||||
uid => $user->{id},
|
||||
journey_id => $candidate->{id},
|
||||
verbose => 1,
|
||||
with_datetime => 1,
|
||||
with_polyline => 1,
|
||||
);
|
||||
$self->redirect_to("/p/${name}/j/$candidate->{id}");
|
||||
return;
|
||||
}
|
||||
}
|
||||
$self->render('not_found');
|
||||
return;
|
||||
}
|
||||
|
||||
my %tw_data = (
|
||||
|
@ -502,24 +528,30 @@ sub user_status {
|
|||
site_name => 'travelynx',
|
||||
);
|
||||
|
||||
if ($journey) {
|
||||
$og_data{title} = $tw_data{title} = sprintf( 'Fahrt von %s nach %s',
|
||||
$journey->{from_name}, $journey->{to_name} );
|
||||
$og_data{description} = $tw_data{description}
|
||||
= $journey->{rt_arrival}->strftime('Ankunft am %d.%m.%Y um %H:%M');
|
||||
$og_data{url} .= "/${ts}";
|
||||
my $visibility;
|
||||
if ( $status->{checked_in} ) {
|
||||
$visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$user->{default_visibility_str},
|
||||
$status->{visibility_str} );
|
||||
if (
|
||||
not(
|
||||
$visibility eq 'public'
|
||||
or ( $visibility eq 'unlisted'
|
||||
and $self->status_token_ok( $status, $ts ) )
|
||||
or (
|
||||
$visibility eq 'travelynx'
|
||||
and ( $self->is_user_authenticated
|
||||
or $self->status_token_ok( $status, $ts ) )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
$status->{checked_in} = 0;
|
||||
}
|
||||
}
|
||||
elsif (
|
||||
$ts
|
||||
and ( not $status->{checked_in}
|
||||
or $status->{sched_departure}->epoch != $ts )
|
||||
)
|
||||
{
|
||||
$og_data{title} = $tw_data{title} = "Bahnfahrt beendet";
|
||||
$og_data{description} = $tw_data{description}
|
||||
= "${name} hat das Ziel erreicht";
|
||||
}
|
||||
elsif ( $status->{checked_in} ) {
|
||||
|
||||
if ( $status->{checked_in} ) {
|
||||
$og_data{url} .= '/' . $status->{sched_departure}->epoch;
|
||||
$og_data{title} = $tw_data{title} = "${name} ist unterwegs";
|
||||
$og_data{description} = $tw_data{description} = sprintf(
|
||||
|
@ -537,39 +569,18 @@ sub user_status {
|
|||
else {
|
||||
$og_data{title} = $tw_data{title}
|
||||
= "${name} ist gerade nicht eingecheckt";
|
||||
$og_data{description} = $tw_data{description}
|
||||
= "Letztes Fahrtziel: $status->{arr_name}";
|
||||
$og_data{description} = $tw_data{description} = q{};
|
||||
}
|
||||
|
||||
if ($journey) {
|
||||
if ( not $user->{public_level} & 0x04 ) {
|
||||
delete $journey->{user_data}{comment};
|
||||
}
|
||||
my $map_data = $self->journeys_to_map_data(
|
||||
journeys => [$journey],
|
||||
include_manual => 1,
|
||||
);
|
||||
$self->render(
|
||||
'journey',
|
||||
error => undef,
|
||||
with_map => 1,
|
||||
readonly => 1,
|
||||
journey => $journey,
|
||||
twitter => \%tw_data,
|
||||
opengraph => \%og_data,
|
||||
%{$map_data},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$self->render(
|
||||
'user_status',
|
||||
name => $name,
|
||||
public_level => $user->{public_level},
|
||||
journey => $status,
|
||||
twitter => \%tw_data,
|
||||
opengraph => \%og_data,
|
||||
);
|
||||
}
|
||||
$self->render(
|
||||
'user_status',
|
||||
name => $name,
|
||||
public_level => $user->{public_level},
|
||||
journey => $status,
|
||||
journey_visibility => $visibility,
|
||||
twitter => \%tw_data,
|
||||
opengraph => \%og_data,
|
||||
);
|
||||
}
|
||||
|
||||
sub public_profile {
|
||||
|
@ -578,48 +589,77 @@ sub public_profile {
|
|||
my $name = $self->stash('name');
|
||||
my $user = $self->users->get_privacy_by_name( name => $name );
|
||||
|
||||
if (
|
||||
$user
|
||||
and (
|
||||
$user->{public_level} & 0x22
|
||||
or ( $user->{public_level} & 0x11
|
||||
and $self->is_user_authenticated )
|
||||
)
|
||||
)
|
||||
{
|
||||
my $status = $self->get_user_status( $user->{id} );
|
||||
my @journeys;
|
||||
if ( $user->{public_level} & 0x40 ) {
|
||||
@journeys = $self->journeys->get(
|
||||
uid => $user->{id},
|
||||
limit => 10,
|
||||
with_datetime => 1
|
||||
);
|
||||
}
|
||||
else {
|
||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||
my $month_ago = $now->clone->subtract( weeks => 4 );
|
||||
@journeys = $self->journeys->get(
|
||||
uid => $user->{id},
|
||||
limit => 10,
|
||||
with_datetime => 1,
|
||||
after => $month_ago,
|
||||
before => $now
|
||||
);
|
||||
}
|
||||
$self->render(
|
||||
'profile',
|
||||
name => $name,
|
||||
uid => $user->{id},
|
||||
public_level => $user->{public_level},
|
||||
journey => $status,
|
||||
journeys => [@journeys],
|
||||
version => $self->app->config->{version} // 'UNKNOWN',
|
||||
);
|
||||
}
|
||||
else {
|
||||
if ( not $user ) {
|
||||
$self->render('not_found');
|
||||
}
|
||||
|
||||
my $status = $self->get_user_status( $user->{id} );
|
||||
my $visibility;
|
||||
if ( $status->{checked_in} ) {
|
||||
$visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$user->{default_visibility_str},
|
||||
$status->{visibility_str} );
|
||||
if (
|
||||
not(
|
||||
$visibility eq 'public'
|
||||
or ( $visibility eq 'unlisted'
|
||||
and $self->status_token_ok($status) )
|
||||
or (
|
||||
$visibility eq 'travelynx'
|
||||
and ( $self->is_user_authenticated
|
||||
or $self->status_token_ok($status) )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
$status->{checked_in} = 0;
|
||||
}
|
||||
}
|
||||
|
||||
my %opt = (
|
||||
uid => $user->{id},
|
||||
limit => 10,
|
||||
with_datetime => 1
|
||||
);
|
||||
|
||||
if ( not $user->{past_all} ) {
|
||||
my $now = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||
$opt{before} = DateTime->now( time_zone => 'Europe/Berlin' );
|
||||
$opt{after} = $now->clone->subtract( weeks => 4 );
|
||||
}
|
||||
|
||||
if (
|
||||
$user->{default_visibility_str} eq 'public'
|
||||
or ( $user->{default_visibility_str} eq 'travelynx'
|
||||
and $self->is_user_authenticated )
|
||||
)
|
||||
{
|
||||
$opt{with_default_visibility} = 1;
|
||||
}
|
||||
else {
|
||||
$opt{with_default_visibility} = 0;
|
||||
}
|
||||
|
||||
if ( $self->is_user_authenticated ) {
|
||||
$opt{min_visibility} = 'travelynx';
|
||||
}
|
||||
else {
|
||||
$opt{min_visibility} = 'public';
|
||||
}
|
||||
|
||||
my @journeys = $self->journeys->get(%opt);
|
||||
|
||||
$self->render(
|
||||
'profile',
|
||||
name => $name,
|
||||
uid => $user->{id},
|
||||
public_level => $user->{public_level},
|
||||
journey => $status,
|
||||
journey_visibility => $visibility,
|
||||
journeys => [@journeys],
|
||||
version => $self->app->config->{version} // 'UNKNOWN',
|
||||
);
|
||||
}
|
||||
|
||||
sub public_journey_details {
|
||||
|
@ -630,7 +670,7 @@ sub public_journey_details {
|
|||
|
||||
$self->param( journey_id => $journey_id );
|
||||
|
||||
if ( not( $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) {
|
||||
if ( not( $user and $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) {
|
||||
$self->render(
|
||||
'journey',
|
||||
status => 404,
|
||||
|
@ -640,98 +680,112 @@ sub public_journey_details {
|
|||
return;
|
||||
}
|
||||
|
||||
my $journey = $self->journeys->get_single(
|
||||
uid => $user->{id},
|
||||
journey_id => $journey_id,
|
||||
verbose => 1,
|
||||
with_datetime => 1,
|
||||
with_polyline => 1,
|
||||
with_visibility => 1,
|
||||
);
|
||||
|
||||
if ( not $journey ) {
|
||||
$self->render(
|
||||
'journey',
|
||||
status => 404,
|
||||
error => 'notfound',
|
||||
journey => {}
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
my $visibility
|
||||
= $self->compute_effective_visibility( $user->{default_visibility_str},
|
||||
$journey->{visibility_str} );
|
||||
|
||||
if (
|
||||
$user
|
||||
and (
|
||||
$user->{public_level} & 0x20
|
||||
or ( $user->{public_level} & 0x10
|
||||
and $self->is_user_authenticated )
|
||||
not(
|
||||
$visibility eq 'public'
|
||||
or ( $visibility eq 'unlisted'
|
||||
and $self->status_token_ok($journey) )
|
||||
or (
|
||||
$visibility eq 'travelynx'
|
||||
and ( $self->is_user_authenticated
|
||||
or $self->status_token_ok($journey) )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
my $journey = $self->journeys->get_single(
|
||||
uid => $user->{id},
|
||||
journey_id => $journey_id,
|
||||
verbose => 1,
|
||||
with_datetime => 1,
|
||||
with_polyline => 1,
|
||||
$self->render(
|
||||
'journey',
|
||||
status => 404,
|
||||
error => 'notfound',
|
||||
journey => {}
|
||||
);
|
||||
|
||||
if ( not( $user->{public_level} & 0x40 ) ) {
|
||||
my $month_ago = DateTime->now( time_zone => 'Europe/Berlin' )
|
||||
->subtract( weeks => 4 )->epoch;
|
||||
if ( $journey and $journey->{rt_dep_ts} < $month_ago ) {
|
||||
$journey = undef;
|
||||
}
|
||||
}
|
||||
|
||||
if ($journey) {
|
||||
my $title = sprintf( 'Fahrt von %s nach %s am %s',
|
||||
$journey->{from_name}, $journey->{to_name},
|
||||
$journey->{rt_arrival}->strftime('%d.%m.%Y') );
|
||||
my $delay = 'pünktlich ';
|
||||
if ( $journey->{rt_arrival} != $journey->{sched_arrival} ) {
|
||||
$delay = sprintf(
|
||||
'mit %+d ',
|
||||
(
|
||||
$journey->{rt_arrival}->epoch
|
||||
- $journey->{sched_arrival}->epoch
|
||||
) / 60
|
||||
);
|
||||
}
|
||||
my $description = sprintf( 'Ankunft mit %s %s %s',
|
||||
$journey->{type}, $journey->{no},
|
||||
$journey->{rt_arrival}->strftime('um %H:%M') );
|
||||
if ( $journey->{km_route} > 0.1 ) {
|
||||
$description = sprintf( '%.0f km mit %s %s – Ankunft %sum %s',
|
||||
$journey->{km_route}, $journey->{type}, $journey->{no},
|
||||
$delay, $journey->{rt_arrival}->strftime('%H:%M') );
|
||||
}
|
||||
my %tw_data = (
|
||||
card => 'summary',
|
||||
site => '@derfnull',
|
||||
image => $self->url_for('/static/icons/icon-512x512.png')
|
||||
->to_abs->scheme('https'),
|
||||
title => $title,
|
||||
description => $description,
|
||||
);
|
||||
my %og_data = (
|
||||
type => 'article',
|
||||
image => $tw_data{image},
|
||||
url => $self->url_for->to_abs,
|
||||
site_name => 'travelynx',
|
||||
title => $title,
|
||||
description => $description,
|
||||
);
|
||||
|
||||
my $map_data = $self->journeys_to_map_data(
|
||||
journeys => [$journey],
|
||||
include_manual => 1,
|
||||
);
|
||||
if ( $journey->{user_data}{comment}
|
||||
and not $user->{public_level} & 0x04 )
|
||||
{
|
||||
delete $journey->{user_data}{comment};
|
||||
}
|
||||
$self->render(
|
||||
'journey',
|
||||
error => undef,
|
||||
journey => $journey,
|
||||
with_map => 1,
|
||||
username => $name,
|
||||
readonly => 1,
|
||||
twitter => \%tw_data,
|
||||
opengraph => \%og_data,
|
||||
%{$map_data},
|
||||
);
|
||||
}
|
||||
else {
|
||||
$self->render('not_found');
|
||||
}
|
||||
return;
|
||||
}
|
||||
else {
|
||||
$self->render('not_found');
|
||||
|
||||
# TODO re-add age check unless status_token_ok (helper function?)
|
||||
|
||||
my $title = sprintf( 'Fahrt von %s nach %s am %s',
|
||||
$journey->{from_name}, $journey->{to_name},
|
||||
$journey->{rt_arrival}->strftime('%d.%m.%Y') );
|
||||
my $delay = 'pünktlich ';
|
||||
if ( $journey->{rt_arrival} != $journey->{sched_arrival} ) {
|
||||
$delay = sprintf(
|
||||
'mit %+d ',
|
||||
(
|
||||
$journey->{rt_arrival}->epoch
|
||||
- $journey->{sched_arrival}->epoch
|
||||
) / 60
|
||||
);
|
||||
}
|
||||
my $description = sprintf( 'Ankunft mit %s %s %s',
|
||||
$journey->{type}, $journey->{no},
|
||||
$journey->{rt_arrival}->strftime('um %H:%M') );
|
||||
if ( $journey->{km_route} > 0.1 ) {
|
||||
$description = sprintf( '%.0f km mit %s %s – Ankunft %sum %s',
|
||||
$journey->{km_route}, $journey->{type}, $journey->{no},
|
||||
$delay, $journey->{rt_arrival}->strftime('%H:%M') );
|
||||
}
|
||||
my %tw_data = (
|
||||
card => 'summary',
|
||||
site => '@derfnull',
|
||||
image => $self->url_for('/static/icons/icon-512x512.png')
|
||||
->to_abs->scheme('https'),
|
||||
title => $title,
|
||||
description => $description,
|
||||
);
|
||||
my %og_data = (
|
||||
type => 'article',
|
||||
image => $tw_data{image},
|
||||
url => $self->url_for->to_abs,
|
||||
site_name => 'travelynx',
|
||||
title => $title,
|
||||
description => $description,
|
||||
);
|
||||
|
||||
my $map_data = $self->journeys_to_map_data(
|
||||
journeys => [$journey],
|
||||
include_manual => 1,
|
||||
);
|
||||
if ( $journey->{user_data}{comment}
|
||||
and not $user->{public_level} & 0x04 )
|
||||
{
|
||||
delete $journey->{user_data}{comment};
|
||||
}
|
||||
$self->render(
|
||||
'journey',
|
||||
error => undef,
|
||||
journey => $journey,
|
||||
with_map => 1,
|
||||
username => $name,
|
||||
readonly => 1,
|
||||
twitter => \%tw_data,
|
||||
opengraph => \%og_data,
|
||||
journey_visibility => $visibility,
|
||||
%{$map_data},
|
||||
);
|
||||
}
|
||||
|
||||
sub public_status_card {
|
||||
|
@ -743,26 +797,42 @@ sub public_status_card {
|
|||
|
||||
delete $self->stash->{layout};
|
||||
|
||||
if (
|
||||
$user
|
||||
and (
|
||||
$user->{public_level} & 0x02
|
||||
or ( $user->{public_level} & 0x01
|
||||
and $self->is_user_authenticated )
|
||||
)
|
||||
)
|
||||
{
|
||||
my $status = $self->get_user_status( $user->{id} );
|
||||
$self->render(
|
||||
'_public_status_card',
|
||||
name => $name,
|
||||
public_level => $user->{public_level},
|
||||
journey => $status
|
||||
);
|
||||
}
|
||||
else {
|
||||
if ( not $user ) {
|
||||
$self->render('not_found');
|
||||
return;
|
||||
}
|
||||
|
||||
my $status = $self->get_user_status( $user->{id} );
|
||||
my $visibility;
|
||||
if ( $status->{checked_in} ) {
|
||||
$visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$user->{default_visibility_str},
|
||||
$status->{visibility_str} );
|
||||
if (
|
||||
not(
|
||||
$visibility eq 'public'
|
||||
or ( $visibility eq 'unlisted'
|
||||
and $self->status_token_ok($status) )
|
||||
or (
|
||||
$visibility eq 'travelynx'
|
||||
and ( $self->is_user_authenticated
|
||||
or $self->status_token_ok($status) )
|
||||
)
|
||||
)
|
||||
)
|
||||
{
|
||||
$status->{checked_in} = 0;
|
||||
}
|
||||
}
|
||||
|
||||
$self->render(
|
||||
'_public_status_card',
|
||||
name => $name,
|
||||
public_level => $user->{public_level},
|
||||
journey => $status,
|
||||
journey_visibility => $visibility,
|
||||
);
|
||||
}
|
||||
|
||||
sub status_card {
|
||||
|
@ -772,6 +842,10 @@ sub status_card {
|
|||
delete $self->stash->{layout};
|
||||
|
||||
if ( $status->{checked_in} ) {
|
||||
my $journey_visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$self->current_user->{default_visibility_str},
|
||||
$status->{visibility_str} );
|
||||
if ( defined $status->{arrival_countdown}
|
||||
and $status->{arrival_countdown} < ( 40 * 60 ) )
|
||||
{
|
||||
|
@ -781,19 +855,28 @@ sub status_card {
|
|||
my ( $connecting_trains, $transit_fyi ) = @_;
|
||||
$self->render(
|
||||
'_checked_in',
|
||||
journey => $status,
|
||||
connections => $connecting_trains,
|
||||
transit_fyi => $transit_fyi
|
||||
journey => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
connections => $connecting_trains,
|
||||
transit_fyi => $transit_fyi
|
||||
);
|
||||
}
|
||||
)->catch(
|
||||
sub {
|
||||
$self->render( '_checked_in', journey => $status );
|
||||
$self->render(
|
||||
'_checked_in',
|
||||
journey => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
);
|
||||
}
|
||||
)->wait;
|
||||
return;
|
||||
}
|
||||
$self->render( '_checked_in', journey => $status );
|
||||
$self->render(
|
||||
'_checked_in',
|
||||
journey => $status,
|
||||
journey_visibility => $journey_visibility,
|
||||
);
|
||||
}
|
||||
elsif ( $status->{cancellation} ) {
|
||||
$self->render_later;
|
||||
|
@ -1693,11 +1776,12 @@ sub journey_details {
|
|||
}
|
||||
|
||||
my $journey = $self->journeys->get_single(
|
||||
uid => $uid,
|
||||
journey_id => $journey_id,
|
||||
verbose => 1,
|
||||
with_datetime => 1,
|
||||
with_polyline => 1,
|
||||
uid => $uid,
|
||||
journey_id => $journey_id,
|
||||
verbose => 1,
|
||||
with_datetime => 1,
|
||||
with_polyline => 1,
|
||||
with_visibility => 1,
|
||||
);
|
||||
|
||||
if ($journey) {
|
||||
|
@ -1705,15 +1789,18 @@ sub journey_details {
|
|||
journeys => [$journey],
|
||||
include_manual => 1,
|
||||
);
|
||||
my $with_share;
|
||||
my $share_text;
|
||||
my $with_share = $user->{is_public} & 0x40 ? 1 : 0;
|
||||
if ( not $with_share and $user->{is_public} & 0x20 ) {
|
||||
my $month_ago = DateTime->now( time_zone => 'Europe/Berlin' )
|
||||
->subtract( weeks => 4 )->epoch;
|
||||
$with_share = $journey->{rt_dep_ts} > $month_ago ? 1 : 0;
|
||||
}
|
||||
|
||||
if ($with_share) {
|
||||
my $visibility
|
||||
= $self->compute_effective_visibility(
|
||||
$user->{default_visibility_str},
|
||||
$journey->{visibility_str} );
|
||||
|
||||
if ( $visibility eq 'public'
|
||||
or $visibility eq 'travelynx'
|
||||
or $visibility eq 'unlisted' )
|
||||
{
|
||||
my $delay = 'pünktlich ';
|
||||
if ( $journey->{rt_arrival} != $journey->{sched_arrival} ) {
|
||||
$delay = sprintf(
|
||||
|
@ -1724,6 +1811,7 @@ sub journey_details {
|
|||
) / 60
|
||||
);
|
||||
}
|
||||
$with_share = 1;
|
||||
$share_text
|
||||
= $journey->{km_route}
|
||||
? sprintf( '%.0f km', $journey->{km_route} )
|
||||
|
@ -1733,13 +1821,15 @@ sub journey_details {
|
|||
$delay, $journey->{rt_arrival}->strftime('%H:%M') );
|
||||
}
|
||||
|
||||
# TODO add token if visibility != public
|
||||
$self->render(
|
||||
'journey',
|
||||
error => undef,
|
||||
journey => $journey,
|
||||
with_map => 1,
|
||||
with_share => $with_share,
|
||||
share_text => $share_text,
|
||||
error => undef,
|
||||
journey => $journey,
|
||||
journey_visibility => $visibility,
|
||||
with_map => 1,
|
||||
with_share => $with_share,
|
||||
share_text => $share_text,
|
||||
%{$map_data},
|
||||
);
|
||||
}
|
||||
|
@ -1754,6 +1844,112 @@ sub journey_details {
|
|||
|
||||
}
|
||||
|
||||
sub visibility_form {
|
||||
my ($self) = @_;
|
||||
my $dep_ts = $self->param('dep_ts');
|
||||
my $journey_id = $self->param('id');
|
||||
my $action = $self->param('action') // 'none';
|
||||
my $user = $self->current_user;
|
||||
my $user_level = $user->{default_visibility_str};
|
||||
my $uid = $user->{id};
|
||||
my $status = $self->get_user_status;
|
||||
my $visibility = $status->{visibility};
|
||||
my $journey;
|
||||
|
||||
if ($journey_id) {
|
||||
$journey = $self->journeys->get_single(
|
||||
uid => $uid,
|
||||
journey_id => $journey_id,
|
||||
with_datetime => 1,
|
||||
with_visibility => 1,
|
||||
);
|
||||
$visibility = $journey->{visibility};
|
||||
}
|
||||
|
||||
if ( $action eq 'save' ) {
|
||||
if ( $self->validation->csrf_protect->has_error('csrf_token') ) {
|
||||
$self->render(
|
||||
'edit_visibility',
|
||||
error => 'csrf',
|
||||
user_level => $user_level,
|
||||
journey => {}
|
||||
);
|
||||
}
|
||||
elsif ( $dep_ts and $dep_ts != $status->{sched_departure}->epoch ) {
|
||||
|
||||
# TODO find and update appropriate past journey (if it exists)
|
||||
$self->render(
|
||||
'edit_visibility',
|
||||
error => 'old',
|
||||
user_level => $user_level,
|
||||
journey => {}
|
||||
);
|
||||
}
|
||||
else {
|
||||
$self->app->log->debug("set visibility");
|
||||
if ($dep_ts) {
|
||||
$self->in_transit->update_visibility(
|
||||
uid => $uid,
|
||||
visibility => $self->param('status_level'),
|
||||
);
|
||||
$self->redirect_to('/');
|
||||
}
|
||||
elsif ($journey_id) {
|
||||
$self->journeys->update_visibility(
|
||||
uid => $uid,
|
||||
id => $journey_id,
|
||||
visibility => $self->param('status_level'),
|
||||
);
|
||||
$self->redirect_to( '/journey/' . $journey_id );
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
# todo use visibility_str
|
||||
if ( not defined $visibility ) {
|
||||
$self->param( status_level => 'default' );
|
||||
}
|
||||
elsif ( $visibility == 100 ) {
|
||||
$self->param( status_level => 'public' );
|
||||
}
|
||||
elsif ( $visibility == 80 ) {
|
||||
$self->param( status_level => 'travelynx' );
|
||||
}
|
||||
elsif ( $visibility == 30 ) {
|
||||
$self->param( status_level => 'unlisted' );
|
||||
}
|
||||
elsif ( $visibility == 10 ) {
|
||||
$self->param( status_level => 'private' );
|
||||
}
|
||||
|
||||
if ($journey_id) {
|
||||
$self->render(
|
||||
'edit_visibility',
|
||||
error => undef,
|
||||
user_level => $user_level,
|
||||
journey => $journey
|
||||
);
|
||||
}
|
||||
elsif ( $status->{checked_in} ) {
|
||||
$self->param( dep_ts => $status->{sched_departure}->epoch );
|
||||
$self->render(
|
||||
'edit_visibility',
|
||||
error => undef,
|
||||
user_level => $user_level,
|
||||
journey => $status
|
||||
);
|
||||
}
|
||||
else {
|
||||
$self->render(
|
||||
'edit_visibility',
|
||||
error => 'notfound',
|
||||
user_level => $user_level,
|
||||
journey => {}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
sub comment_form {
|
||||
my ($self) = @_;
|
||||
my $dep_ts = $self->param('dep_ts');
|
||||
|
|
|
@ -11,6 +11,22 @@ use 5.020;
|
|||
use DateTime;
|
||||
use JSON;
|
||||
|
||||
my %visibility_itoa = (
|
||||
100 => 'public',
|
||||
80 => 'travelynx',
|
||||
60 => 'followers',
|
||||
30 => 'unlisted',
|
||||
10 => 'private',
|
||||
);
|
||||
|
||||
my %visibility_atoi = (
|
||||
public => 100,
|
||||
travelynx => 80,
|
||||
followers => 60,
|
||||
unlisted => 30,
|
||||
private => 10,
|
||||
);
|
||||
|
||||
sub new {
|
||||
my ( $class, %opt ) = @_;
|
||||
|
||||
|
@ -117,11 +133,23 @@ sub get {
|
|||
}
|
||||
|
||||
my $res = $db->select( $table, '*', { user_id => $uid } );
|
||||
my $ret;
|
||||
|
||||
if ( $opt{with_data} ) {
|
||||
return $res->expand->hash;
|
||||
$ret = $res->expand->hash;
|
||||
}
|
||||
return $res->hash;
|
||||
else {
|
||||
$ret = $res->hash;
|
||||
}
|
||||
|
||||
if ( $opt{with_visibility} and $ret ) {
|
||||
$ret->{visibility_str}
|
||||
= $ret->{visibility}
|
||||
? $visibility_itoa{ $ret->{visibility} }
|
||||
: 'default';
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
sub get_all_active {
|
||||
|
@ -449,4 +477,23 @@ sub update_user_data {
|
|||
);
|
||||
}
|
||||
|
||||
sub update_visibility {
|
||||
my ( $self, %opt ) = @_;
|
||||
|
||||
my $uid = $opt{uid};
|
||||
my $db = $opt{db} // $self->{pg}->db;
|
||||
|
||||
my $visibility;
|
||||
|
||||
if ( $opt{visibility} and $visibility_atoi{ $opt{visibility} } ) {
|
||||
$visibility = $visibility_atoi{ $opt{visibility} };
|
||||
}
|
||||
|
||||
$db->update(
|
||||
'in_transit',
|
||||
{ visibility => $visibility },
|
||||
{ user_id => $uid }
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -15,6 +15,22 @@ use utf8;
|
|||
use DateTime;
|
||||
use JSON;
|
||||
|
||||
my %visibility_itoa = (
|
||||
100 => 'public',
|
||||
80 => 'travelynx',
|
||||
60 => 'followers',
|
||||
30 => 'unlisted',
|
||||
10 => 'private',
|
||||
);
|
||||
|
||||
my %visibility_atoi = (
|
||||
public => 100,
|
||||
travelynx => 80,
|
||||
followers => 60,
|
||||
unlisted => 30,
|
||||
private => 10,
|
||||
);
|
||||
|
||||
my @month_name
|
||||
= (
|
||||
qw(Januar Februar März April Mai Juni Juli August September Oktober November Dezember)
|
||||
|
@ -509,7 +525,7 @@ sub get {
|
|||
|
||||
my @select
|
||||
= (
|
||||
qw(journey_id train_type train_line train_no checkin_ts sched_dep_ts real_dep_ts dep_eva dep_ds100 dep_name dep_lat dep_lon checkout_ts sched_arr_ts real_arr_ts arr_eva arr_ds100 arr_name arr_lat arr_lon cancelled edited route messages user_data)
|
||||
qw(journey_id train_type train_line train_no checkin_ts sched_dep_ts real_dep_ts dep_eva dep_ds100 dep_name dep_lat dep_lon checkout_ts sched_arr_ts real_arr_ts arr_eva arr_ds100 arr_name arr_lat arr_lon cancelled edited route messages user_data visibility)
|
||||
);
|
||||
my %where = (
|
||||
user_id => $uid,
|
||||
|
@ -548,6 +564,24 @@ sub get {
|
|||
push( @select, 'polyline' );
|
||||
}
|
||||
|
||||
if ( $opt{min_visibility} ) {
|
||||
if ( $visibility_atoi{ $opt{min_visibility} } ) {
|
||||
$opt{min_visibility} = $visibility_atoi{ $opt{min_visibility} };
|
||||
}
|
||||
if ( $opt{with_default_visibility} ) {
|
||||
$where{visibility} = [
|
||||
-or => { '=', undef },
|
||||
{ '>=', $opt{min_visibility} }
|
||||
];
|
||||
}
|
||||
else {
|
||||
$where{visibility} = [
|
||||
-and => { '!=', undef },
|
||||
{ '>=', $opt{min_visibility} }
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
my @travels;
|
||||
|
||||
my $res = $db->select( 'journeys_str', \@select, \%where, \%order );
|
||||
|
@ -577,8 +611,16 @@ sub get {
|
|||
route => $entry->{route},
|
||||
edited => $entry->{edited},
|
||||
user_data => $entry->{user_data},
|
||||
visibility => $entry->{visibility},
|
||||
};
|
||||
|
||||
if ( $opt{with_visibility} ) {
|
||||
$ref->{visibility_str}
|
||||
= $ref->{visibility}
|
||||
? $visibility_itoa{ $ref->{visibility} }
|
||||
: 'default';
|
||||
}
|
||||
|
||||
if ( $opt{with_polyline} ) {
|
||||
$ref->{polyline} = $entry->{polyline};
|
||||
}
|
||||
|
@ -1703,4 +1745,26 @@ sub get_connection_targets {
|
|||
return @destinations;
|
||||
}
|
||||
|
||||
sub update_visibility {
|
||||
my ( $self, %opt ) = @_;
|
||||
|
||||
my $uid = $opt{uid};
|
||||
my $db = $opt{db} // $self->{pg}->db;
|
||||
|
||||
my $visibility;
|
||||
|
||||
if ( $opt{visibility} and $visibility_atoi{ $opt{visibility} } ) {
|
||||
$visibility = $visibility_atoi{ $opt{visibility} };
|
||||
}
|
||||
|
||||
$db->update(
|
||||
'journeys',
|
||||
{ visibility => $visibility },
|
||||
{
|
||||
user_id => $uid,
|
||||
id => $opt{id}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
|
|
|
@ -11,6 +11,22 @@ use 5.020;
|
|||
use DateTime;
|
||||
use JSON;
|
||||
|
||||
my %visibility_itoa = (
|
||||
100 => 'public',
|
||||
80 => 'travelynx',
|
||||
60 => 'followers',
|
||||
30 => 'unlisted',
|
||||
10 => 'private',
|
||||
);
|
||||
|
||||
my %visibility_atoi = (
|
||||
public => 100,
|
||||
travelynx => 80,
|
||||
followers => 60,
|
||||
unlisted => 30,
|
||||
private => 10,
|
||||
);
|
||||
|
||||
my @sb_templates = (
|
||||
undef,
|
||||
[ 'DBF', 'https://dbf.finalrewind.org/{name}?rt=1#{tt}{tn}' ],
|
||||
|
@ -153,7 +169,16 @@ sub get_privacy_by_name {
|
|||
);
|
||||
|
||||
if ( my $user = $res->hash ) {
|
||||
return $user;
|
||||
return {
|
||||
id => $user->{id},
|
||||
public_level => $user->{public_level}, # todo remove?
|
||||
default_visibility => $user->{public_level} & 0x7f,
|
||||
default_visibility_str =>
|
||||
$visibility_itoa{ $user->{public_level} & 0x7f },
|
||||
comments_visible => $user->{public_level} & 0x80 ? 1 : 0,
|
||||
past_visible => ( $user->{public_level} & 0x300 ) >> 8,
|
||||
past_all => $user->{public_level} & 0x400 ? 1 : 0,
|
||||
};
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
@ -164,6 +189,14 @@ sub set_privacy {
|
|||
my $uid = $opt{uid};
|
||||
my $public_level = $opt{level};
|
||||
|
||||
if ( not defined $public_level and defined $opt{default_visibility} ) {
|
||||
$public_level
|
||||
= ( $opt{default_visibility} & 0x7f )
|
||||
| ( $opt{comments_visible} ? 0x80 : 0x00 )
|
||||
| ( ( ( $opt{past_visible} // 0 ) << 8 ) & 0x300 )
|
||||
| ( $opt{past_all} ? 0x400 : 0 );
|
||||
}
|
||||
|
||||
$db->update( 'users', { public_level => $public_level }, { id => $uid } );
|
||||
}
|
||||
|
||||
|
@ -333,12 +366,18 @@ sub get {
|
|||
)->hash;
|
||||
if ($user) {
|
||||
return {
|
||||
id => $user->{id},
|
||||
name => $user->{name},
|
||||
status => $user->{status},
|
||||
is_public => $user->{public_level},
|
||||
email => $user->{email},
|
||||
sb_name => $user->{external_services}
|
||||
id => $user->{id},
|
||||
name => $user->{name},
|
||||
status => $user->{status},
|
||||
is_public => $user->{public_level},
|
||||
default_visibility => $user->{public_level} & 0x7f,
|
||||
default_visibility_str =>
|
||||
$visibility_itoa{ $user->{public_level} & 0x7f },
|
||||
comments_visible => $user->{public_level} & 0x80 ? 1 : 0,
|
||||
past_visible => ( $user->{public_level} & 0x300 ) >> 8,
|
||||
past_all => $user->{public_level} & 0x400 ? 1 : 0,
|
||||
email => $user->{email},
|
||||
sb_name => $user->{external_services}
|
||||
? $sb_templates[ $user->{external_services} & 0x07 ][0]
|
||||
: undef,
|
||||
sb_template => $user->{external_services}
|
||||
|
|
|
@ -8,8 +8,13 @@ var j_duration = 0;
|
|||
var j_arrival = 0;
|
||||
var j_dest = '';
|
||||
var j_stops = [];
|
||||
var j_token = '';
|
||||
function upd_journey_data() {
|
||||
$('.countdown').each(function() {
|
||||
const journey_token = $(this).data('token');
|
||||
if (journey_token) {
|
||||
j_token = journey_token;
|
||||
}
|
||||
var journey_data = $(this).data('journey');
|
||||
if (journey_data) {
|
||||
journey_data = journey_data.split(';');
|
||||
|
@ -105,7 +110,7 @@ function tvly_update_public() {
|
|||
$('.publicstatuscol').each(function() {
|
||||
user_name = $(this).data('user');
|
||||
});
|
||||
$.get('/ajax/status/' + user_name + '.html', function(data) {
|
||||
$.get('/ajax/status/' + user_name + '.html', {token: j_token}, function(data) {
|
||||
$('.publicstatuscol').html(data);
|
||||
upd_journey_data();
|
||||
setTimeout(tvly_update_public, 40000);
|
||||
|
|
|
@ -244,13 +244,16 @@
|
|||
</div>
|
||||
<div class="card-action">
|
||||
% if ($journey->{arr_name}) {
|
||||
<a style="margin-right: 0;" href="/journey/comment">
|
||||
<i class="material-icons left" aria-hidden="true">comment</i> Kommentar
|
||||
<a href="/journey/comment">
|
||||
<i class="material-icons">comment</i>
|
||||
</a>
|
||||
<a style="margin-right: 0;" href="/journey/visibility">
|
||||
<i class="material-icons"><%= visibility_icon($journey_visibility) %></i>
|
||||
</a>
|
||||
% }
|
||||
% else {
|
||||
<a class="action-undo blue-text" data-id="in_transit" data-checkints="<%= $journey->{timestamp}->epoch %>" style="margin-right: 0;">
|
||||
<i class="material-icons left" aria-hidden="true">undo</i> Checkin Rückgängig
|
||||
<i class="material-icons left" aria-hidden="true">undo</i> Rückgängig
|
||||
</a>
|
||||
% }
|
||||
% if (defined $journey->{arrival_countdown} and $journey->{arrival_countdown} <= 0) {
|
||||
|
@ -259,7 +262,7 @@
|
|||
style="margin-right: 0;"
|
||||
data-station="<%= $journey->{arr_name}%>">
|
||||
<i class="material-icons left">done</i>
|
||||
Jetzt auschecken
|
||||
Auschecken
|
||||
</a>
|
||||
% }
|
||||
% elsif ($journey->{arr_name}) {
|
||||
|
@ -270,7 +273,7 @@
|
|||
<a class="action-share blue-text right"
|
||||
style="margin-right: 0;"
|
||||
% my $arr_text = q{};
|
||||
% if ($journey->{real_arrival}->epoch and not $user->{is_public} & 0x02) {
|
||||
% if ($journey->{real_arrival}->epoch and $journey_visibility eq 'private') {
|
||||
% $arr_text = $journey->{real_arrival}->strftime(' – Ankunft gegen %H:%M Uhr');
|
||||
% }
|
||||
% if ($user->{is_public} & 0x04 and $journey->{comment}) {
|
||||
|
@ -279,13 +282,21 @@
|
|||
% else {
|
||||
data-text="Ich bin gerade <%= $attrib %> <%= $journey->{train_type} %> <%= $journey->{train_no} %> nach <%= $journey->{arr_name} . $arr_text %> #travelynx"
|
||||
% }
|
||||
% if ($user->{is_public} & 0x02) {
|
||||
% if ($journey_visibility eq 'public') {
|
||||
data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= $user->{name} %>/<%= $journey->{sched_departure}->epoch %>"
|
||||
% }
|
||||
% elsif ($journey_visibility eq 'travelynx' or $journey_visibility eq 'unlisted') {
|
||||
data-url="<%= url_for('/status')->to_abs->scheme('https') %>/<%= $user->{name} %>/<%= $journey->{sched_departure}->epoch %>?token=<%= $journey->{dep_eva} %>-<%= $journey->{timestamp}->epoch %>"
|
||||
% }
|
||||
>
|
||||
<i class="material-icons left" aria-hidden="true">share</i> Teilen
|
||||
</a>
|
||||
% }
|
||||
% else {
|
||||
<a class="right" href="/journey/visibility">
|
||||
<i class="material-icons left"><%= visibility_icon($journey_visibility) %></i> Sichtbarkeit
|
||||
</a>
|
||||
% }
|
||||
</div>
|
||||
</div>
|
||||
% if ($journey->{arr_name}) {
|
||||
|
|
|
@ -3,7 +3,11 @@
|
|||
<div class="card">
|
||||
<div class="card-content">
|
||||
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
|
||||
<span class="card-title"><%= $name %> ist unterwegs</span>
|
||||
<span class="card-title"><%= $name %> ist unterwegs
|
||||
% if ($journey_visibility) {
|
||||
<i class="material-icons right"><%= visibility_icon($journey_visibility) %></i>
|
||||
% }
|
||||
</span>
|
||||
% if ($public_level & 0x04 and $journey->{comment}) {
|
||||
<p>„<%= $journey->{comment} %>“</p>
|
||||
% }
|
||||
|
@ -16,6 +20,9 @@
|
|||
% }
|
||||
<div class="center-align countdown"
|
||||
data-duration="<%= $journey->{journey_duration} // 0 %>"
|
||||
% if (param('token')) {
|
||||
data-token="<%= $journey->{dep_eva} %>-<%= $journey->{timestamp}->epoch %>-<%= $journey->{sched_departure}->epoch %>"
|
||||
% }
|
||||
data-arrival="<%= $journey->{real_arrival}->epoch %>">
|
||||
% if ($journey->{departure_countdown} > 120) {
|
||||
Abfahrt in <%= sprintf('%.f', $journey->{departure_countdown} / 60) %> Minuten
|
||||
|
@ -166,20 +173,6 @@
|
|||
<i class="material-icons small right sync-failed-marker grey-text" style="display: none;">sync_problem</i>
|
||||
<span class="card-title"><%= $name %> ist gerade nicht eingecheckt</span>
|
||||
<p>
|
||||
% if ($journey->{arr_name}) {
|
||||
Zuletzt gesehen
|
||||
% if ($journey->{real_arrival}->epoch and ($public_level & 0x20 or ($public_level & 0x10 and is_user_authenticated()))) {
|
||||
%= $journey->{real_arrival}->strftime('am %d.%m.%Y')
|
||||
in <b><%= $journey->{arr_name} %></b>
|
||||
%= $journey->{real_arrival}->strftime('(Ankunft um %H:%M Uhr)')
|
||||
% }
|
||||
% else {
|
||||
in <b><%= $journey->{arr_name} %></b>
|
||||
% }
|
||||
% }
|
||||
% else {
|
||||
Noch keine Zugfahrten geloggt.
|
||||
% }
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -70,36 +70,10 @@
|
|||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">Öffentliche Daten</th>
|
||||
<th scope="row">Sichtbarkeit</th>
|
||||
<td>
|
||||
<a href="/account/privacy"><i class="material-icons">edit</i></a>
|
||||
% if ($acc->{is_public} == 0) {
|
||||
<span style="color: #999999;">Keine</span>
|
||||
% }
|
||||
% if ($acc->{is_public} & 0x01) {
|
||||
Aktueller Status (nur mit Anmeldung)
|
||||
% }
|
||||
% elsif ($acc->{is_public} & 0x02) {
|
||||
Aktueller Status
|
||||
% }
|
||||
% if ($acc->{is_public} & 0x0f and $acc->{is_public} & 0xf0) {
|
||||
<br/>
|
||||
% }
|
||||
% if ($acc->{is_public} & 0x30) {
|
||||
% if ($acc->{is_public} & 0x40) {
|
||||
Vergangene Fahrten
|
||||
% }
|
||||
% else {
|
||||
Fahrten der letzten vier Wochen
|
||||
% }
|
||||
% if ($acc->{is_public} & 0x10) {
|
||||
(nur mit Anmeldung)
|
||||
% }
|
||||
% }
|
||||
% if ($acc->{is_public} & 0x04) {
|
||||
<br/>
|
||||
Kommentare
|
||||
% }
|
||||
<span><i class="material-icons"><%= visibility_icon($acc->{default_visibility_str}) %></i></span>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
|
|
@ -38,6 +38,16 @@
|
|||
% }
|
||||
am
|
||||
<b><%= $journey->{sched_departure}->strftime('%d.%m.%Y') %></b>
|
||||
% if ($journey_visibility) {
|
||||
% if (stash('username')) {
|
||||
<i class="material-icons right"><%= visibility_icon($journey_visibility) %></i>
|
||||
% }
|
||||
% else {
|
||||
<a class="right" href="/journey/visibility?id=<%= $journey->{id} %>">
|
||||
<i class="material-icons"><%= visibility_icon($journey_visibility) %></i>
|
||||
</a>
|
||||
% }
|
||||
% }
|
||||
</p>
|
||||
% if ($journey->{edited}) {
|
||||
<p>
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
<div class="row">
|
||||
<div class="col s12 statuscol">
|
||||
% if ($status->{checked_in}) {
|
||||
%= include '_checked_in', journey => $status;
|
||||
%= include '_checked_in', journey => $status, journey_visibility => stash('journey_visibility');
|
||||
% }
|
||||
% elsif ($status->{cancelled}) {
|
||||
<div class="card info-color">
|
||||
|
|
|
@ -1,10 +1,11 @@
|
|||
<h1>Öffentliche Daten</h1>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
Hier kannst du auswählen, welche Aspekte deines Accounts bzw. deiner
|
||||
Bahnfahrten öffentlich einsehbar sind. Öffentliche Daten sind
|
||||
grundsätzlich für <i>alle</i> einsehbar, die die (leicht erratbare) URL
|
||||
kennen.
|
||||
Hier kannst du auswählen, welche Personengruppen deine Fahrten bei
|
||||
travelynx einsehen können und ob dies auch für vergangene Fahrten
|
||||
gelten soll. Nach dem Einchecken in einen Zug hast du im
|
||||
Checkin-Fenster die Möglichkeit, für die aktuelle Fahrt eine
|
||||
abweichende Sichtbarkeit einzustellen.
|
||||
</div>
|
||||
</div>
|
||||
%= form_for '/account/privacy' => (method => 'POST') => begin
|
||||
|
@ -13,33 +14,62 @@
|
|||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<div>
|
||||
<label>
|
||||
%= radio_button status_level => 'private'
|
||||
<span>Nicht sichtbar</span>
|
||||
</label>
|
||||
</div><div>
|
||||
<label>
|
||||
%= radio_button status_level => 'intern'
|
||||
<span>Nur mit Anmeldung</span>
|
||||
</label>
|
||||
</div><div>
|
||||
<label>
|
||||
%= radio_button status_level => 'extern'
|
||||
<span>Öffentlich</span>
|
||||
</label>
|
||||
<label>
|
||||
%= radio_button status_level => 'public'
|
||||
<span><i class="material-icons left"><%= visibility_icon('public') %></i>Öffentlich: Im Profil verlinkt und beliebig zugänglich.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<div>
|
||||
<label>
|
||||
%= radio_button status_level => 'travelynx'
|
||||
<span><i class="material-icons left"><%= visibility_icon('travelynx') %></i>Lokal: Nur für<!-- Personen, die dir folgen oder auf dieser Seite angemeldet sind --> auf dieser Seite angemeldete Acounts sowie nicht angemeldete Personen, denen du mithilfe der Teilen-Funktion einen Link schickst.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<!--
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<div>
|
||||
<label>
|
||||
%= radio_button status_level => 'fedi'
|
||||
<span><i class="material-icons left"><%= visibility_icon('fedi') %></i>Fedi: nur für Personen, die deinem Account folgen.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
-->
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<div>
|
||||
<label>
|
||||
%= radio_button status_level => 'unlisted'
|
||||
<span><i class="material-icons left"><%= visibility_icon('unlisted') %></i>Verlinkbar: Nur für Personen zugänglich, denen du mithilfe der Teilen-Funktion einen Link schickst.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="input-field col s12">
|
||||
<div>
|
||||
<label>
|
||||
%= radio_button status_level => 'private'
|
||||
<span><i class="material-icons left"><%= visibility_icon('private') %></i>Privat: nur für dich sichtbar.</span>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
Hier kannst du auswählen, ob dein aktueller Status unter <a
|
||||
href="/status/<%= $name %>">/status/<%= $name %></a> sowie <a
|
||||
href="/p/<%= $name %>">/p/<%= $name %></a> abrufbar ist.
|
||||
Wenn du eingecheckt bist, werden dort Zug, Start- und Zielstation
|
||||
sowie Abfahrts- und Ankunftszeit gezeigt, andernfalls lediglich der
|
||||
Zielbahnhof der letzten Reise. Wann die letzte Reise beendet wurde,
|
||||
wird nur angegeben, wenn deine vergangenen Zugfahrten sichtbar sind
|
||||
(siehe unten).
|
||||
Wenn du (mit passender Sichtbarkeit) eingecheckt bist, werden unter
|
||||
<a href="/status/<%= $name %>">/status/<%= $name %></a> sowie <a
|
||||
href="/p/<%= $name %>">/p/<%= $name %></a> Zug, Start- und
|
||||
Zielstation sowie Abfahrts- und Ankunftszeit gezeigt. Andernfalls
|
||||
wird angegeben, dass du gerade nicht eingecheckt seist.
|
||||
</div>
|
||||
</div>
|
||||
<h2>Vergangene Zugfahrten</h2>
|
||||
|
@ -85,7 +115,10 @@
|
|||
dort nicht eingetragene Fahrten sind jedoch weiterhin über /p/<%=
|
||||
$name %>/j/ID zugänglich. Da die ID (mit Lücken) aufsteigend vergeben
|
||||
wird, sind effektiv alle deiner vergangenen Fahrten (oder alle Fahrten
|
||||
der letzten vier Wochen) öffentlich.
|
||||
der letzten vier Wochen) öffentlich. Auch hier besteht die
|
||||
Möglichkeit, für einzelne Fahrten eine abweichende Sichtbarkeit
|
||||
einzustellen. Sofern die Sichtbarkeit auf die letzten vier Wochen
|
||||
beschränkt ist, hat dies jedoch Vorrang.
|
||||
</div>
|
||||
</div>
|
||||
<h2>Sonstiges</h2>
|
||||
|
@ -101,6 +134,7 @@
|
|||
<div class="col s12">
|
||||
Wenn aktiv, sind von dir eingetragene Freitext-Kommentare in deinem
|
||||
aktuellen Status sowie bei deinen vergangenen Zugfahrten sichtbar.
|
||||
Diese Einstellung kann nicht pro Fahrt verändert werden.
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
|
|
|
@ -10,14 +10,12 @@
|
|||
</div>
|
||||
</div>
|
||||
% }
|
||||
% if ($public_level & 0x02 or ($public_level & 0x01 and is_user_authenticated())) {
|
||||
<div class="row">
|
||||
<div class="col s12 publicstatuscol" data-user="<%= $name %>">
|
||||
%= include '_public_status_card', name => $name, public_level => $public_level, journey => $journey
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col s12 publicstatuscol" data-user="<%= $name %>">
|
||||
%= include '_public_status_card', name => $name, public_level => $public_level, journey => $journey, journey_visibility => $journey_visibility
|
||||
</div>
|
||||
% }
|
||||
% if ($public_level & 0x20 or ($public_level & 0x10 and is_user_authenticated())) {
|
||||
</div>
|
||||
% if ($journeys and @{$journeys}) {
|
||||
<div class="row">
|
||||
<div class="col s12">
|
||||
<h2>Letzte Fahrten von <%= $name %></h1>
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<div class="row">
|
||||
<div class="col s12 publicstatuscol" data-user="<%= $name %>">
|
||||
%= include '_public_status_card', name => $name, public_level => $public_level, journey => $journey
|
||||
%= include '_public_status_card', name => $name, public_level => $public_level, journey => $journey, journey_visibility => $journey_visibility
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in a new issue