diff options
Diffstat (limited to 'lib')
| -rwxr-xr-x | lib/Travelynx.pm | 12 | ||||
| -rwxr-xr-x | lib/Travelynx/Controller/Profile.pm | 475 | ||||
| -rwxr-xr-x | lib/Travelynx/Controller/Traveling.pm | 453 | 
3 files changed, 481 insertions, 459 deletions
| diff --git a/lib/Travelynx.pm b/lib/Travelynx.pm index 8ec3c8e..3ae9327 100755 --- a/lib/Travelynx.pm +++ b/lib/Travelynx.pm @@ -2153,13 +2153,13 @@ sub startup {  	$r->get('/recover')->to('account#request_password_reset');  	$r->get('/recover/:id/:token')->to('account#recover_password');  	$r->get('/reg/:id/:token')->to('account#verify'); -	$r->get('/status/:name')->to('traveling#user_status'); -	$r->get('/status/:name/:ts')->to('traveling#user_status'); -	$r->get('/ajax/status/#name')->to('traveling#public_status_card'); -	$r->get('/ajax/status/:name/:ts')->to('traveling#public_status_card'); -	$r->get('/p/:name')->to('traveling#public_profile'); +	$r->get('/status/:name')->to('profile#user_status'); +	$r->get('/status/:name/:ts')->to('profile#user_status'); +	$r->get('/ajax/status/#name')->to('profile#status_card'); +	$r->get('/ajax/status/:name/:ts')->to('profile#status_card'); +	$r->get('/p/:name')->to('profile#profile');  	$r->get( '/p/:name/j/:id' => 'public_journey' ) -	  ->to('traveling#public_journey_details'); +	  ->to('profile#journey_details');  	$r->get('/.well-known/webfinger')->to('account#webfinger');  	$r->post('/api/v1/import')->to('api#import_v1');  	$r->post('/api/v1/travel')->to('api#travel_v1'); diff --git a/lib/Travelynx/Controller/Profile.pm b/lib/Travelynx/Controller/Profile.pm new file mode 100755 index 0000000..182c90d --- /dev/null +++ b/lib/Travelynx/Controller/Profile.pm @@ -0,0 +1,475 @@ +package Travelynx::Controller::Profile; + +# Copyright (C) 2020-2023 Daniel Friesel +# +# SPDX-License-Identifier: AGPL-3.0-or-later +use Mojo::Base 'Mojolicious::Controller'; + +use DateTime; + +# Internal Helpers + +sub compute_effective_visibility { +	my ( $self, $default_visibility, $journey_visibility ) = @_; +	if ( $journey_visibility eq 'default' ) { +		return $default_visibility; +	} +	return $journey_visibility; +} + +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 % 337 +		and $ts2 == $status->{sched_departure}->epoch ) +	{ +		return 1; +	} +	return; +} + +sub journey_token_ok { +	my ( $self, $journey, $ts2_ext ) = @_; +	my $token = $self->param('token') // q{}; + +	my ( $eva, $ts, $ts2 ) = split( qr{-}, $token ); +	if ( not $ts ) { +		return; +	} + +	$ts2 //= $ts2_ext; + +	if (    $eva == $journey->{from_eva} +		and $ts == $journey->{checkin_ts} % 337 +		and $ts2 == $journey->{sched_dep_ts} ) +	{ +		return 1; +	} +	return; +} + +# Controllers + +sub profile { +	my ($self) = @_; + +	my $name = $self->stash('name'); +	my $user = $self->users->get_privacy_by_name( name => $name ); + +	if ( not $user ) { +		$self->render('not_found'); +		return; +	} + +	my $status = $self->get_user_status( $user->{id} ); +	my $visibility; +	if ( $status->{checked_in} or $status->{arr_name} ) { +		$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; +			$status->{arr_name}   = undef; +		} +	} +	if (    not $status->{checked_in} +		and $status->{arr_name} +		and not $user->{past_status} ) +	{ +		$status->{arr_name} = undef; +	} + +	my @journeys; + +	if ( $user->{past_visible} == 2 +		or ( $user->{past_visible} == 1 and $self->is_user_authenticated ) ) +	{ + +		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'; +		} + +		@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 journey_details { +	my ($self)     = @_; +	my $name       = $self->stash('name'); +	my $journey_id = $self->stash('id'); +	my $user       = $self->users->get_privacy_by_name( name => $name ); + +	$self->param( journey_id => $journey_id ); + +	if ( not( $user and $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) { +		$self->render( +			'journey', +			status  => 404, +			error   => 'notfound', +			journey => {} +		); +		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 $is_past; +	if ( not $user->{past_all} ) { +		my $now = DateTime->now( time_zone => 'Europe/Berlin' ); +		if ( $journey->{sched_dep_ts} < $now->subtract( weeks => 4 )->epoch ) { +			$is_past = 1; +		} +	} + +	my $visibility +	  = $self->compute_effective_visibility( $user->{default_visibility_str}, +		$journey->{visibility_str} ); + +	if ( +		not( +			( $visibility eq 'public' and not $is_past ) +			or (    $visibility eq 'unlisted' +				and $self->journey_token_ok($journey) ) +			or ( +				$visibility eq 'travelynx' +				and ( ( $self->is_user_authenticated and not $is_past ) +					or $self->journey_token_ok($journey) ) +			) +		) +	  ) +	{ +		$self->render( +			'journey', +			status  => 404, +			error   => 'notfound', +			journey => {} +		); +		return; +	} + +	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->{comments_visible} ) +	{ +		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 user_status { +	my ($self) = @_; + +	my $name = $self->stash('name'); +	my $ts   = $self->stash('ts') // 0; +	my $user = $self->users->get_privacy_by_name( name => $name ); + +	if ( not $user ) { +		$self->render('not_found'); +		return; +	} + +	my $status = $self->get_user_status( $user->{id} ); + +	if ( +		$ts +		and ( not $status->{checked_in} +			or $status->{sched_departure}->epoch != $ts ) +	  ) +	{ +		for my $journey ( +			$self->journeys->get( +				uid             => $user->{id}, +				sched_dep_ts    => $ts, +				limit           => 1, +				with_visibility => 1, +			) +		  ) +		{ +			my $visibility +			  = $self->compute_effective_visibility( +				$user->{default_visibility_str}, +				$journey->{visibility_str} ); +			if ( +				$visibility eq 'public' +				or (    $visibility eq 'unlisted' +					and $self->journey_token_ok( $journey, $ts ) ) +				or ( +					$visibility eq 'travelynx' +					and (  $self->is_user_authenticated +						or $self->journey_token_ok( $journey, $ts ) ) +				) +			  ) +			{ +				my $token = $self->param('token') // q{}; +				$self->redirect_to( +					"/p/${name}/j/$journey->{id}?token=${token}-${ts}"); +			} +			else { +				$self->render('not_found'); +			} +			return; +		} +		$self->render('not_found'); +		return; +	} + +	my %tw_data = ( +		card  => 'summary', +		site  => '@derfnull', +		image => $self->url_for('/static/icons/icon-512x512.png') +		  ->to_abs->scheme('https'), +	); +	my %og_data = ( +		type      => 'article', +		image     => $tw_data{image}, +		url       => $self->url_for("/status/${name}")->to_abs->scheme('https'), +		site_name => 'travelynx', +	); + +	my $visibility; +	if ( $status->{checked_in} or $status->{arr_name} ) { +		$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; +			$status->{arr_name}   = undef; +		} +	} +	if (    not $status->{checked_in} +		and $status->{arr_name} +		and not $user->{past_status} ) +	{ +		$status->{arr_name} = undef; +	} + +	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( +			'%s %s von %s nach %s', +			$status->{train_type}, $status->{train_line} // $status->{train_no}, +			$status->{dep_name},   $status->{arr_name}   // 'irgendwo' +		); +		if ( $status->{real_arrival}->epoch ) { +			$tw_data{description} .= $status->{real_arrival} +			  ->strftime(' – Ankunft gegen %H:%M Uhr'); +			$og_data{description} .= $status->{real_arrival} +			  ->strftime(' – Ankunft gegen %H:%M Uhr'); +		} +	} +	else { +		$og_data{title} = $tw_data{title} +		  = "${name} ist gerade nicht eingecheckt"; +		$og_data{description} = $tw_data{description} = q{}; +	} + +	$self->render( +		'user_status', +		name               => $name, +		public_level       => $user->{public_level}, +		journey            => $status, +		journey_visibility => $visibility, +		twitter            => \%tw_data, +		opengraph          => \%og_data, +		version            => $self->app->config->{version} // 'UNKNOWN', +	); +} + +sub status_card { +	my ($self) = @_; + +	my $name = $self->stash('name'); +	$name =~ s{[.]html$}{}; +	my $user = $self->users->get_privacy_by_name( name => $name ); + +	delete $self->stash->{layout}; + +	if ( not $user ) { +		$self->render('not_found'); +		return; +	} + +	my $status = $self->get_user_status( $user->{id} ); +	my $visibility; +	if ( $status->{checked_in} or $status->{arr_name} ) { +		$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; +			$status->{arr_name}   = undef; +		} +	} +	if (    not $status->{checked_in} +		and $status->{arr_name} +		and not $user->{past_status} ) +	{ +		$status->{arr_name} = undef; +	} + +	$self->render( +		'_public_status_card', +		name               => $name, +		public_level       => $user->{public_level}, +		journey            => $status, +		journey_visibility => $visibility, +	); +} + +1; diff --git a/lib/Travelynx/Controller/Traveling.pm b/lib/Travelynx/Controller/Traveling.pm index 1580bb6..00cc02a 100755 --- a/lib/Travelynx/Controller/Traveling.pm +++ b/lib/Travelynx/Controller/Traveling.pm @@ -459,459 +459,6 @@ 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 % 337 -		and $ts2 == $status->{sched_departure}->epoch ) -	{ -		return 1; -	} -	return; -} - -sub journey_token_ok { -	my ( $self, $journey, $ts2_ext ) = @_; -	my $token = $self->param('token') // q{}; - -	my ( $eva, $ts, $ts2 ) = split( qr{-}, $token ); -	if ( not $ts ) { -		return; -	} - -	$ts2 //= $ts2_ext; - -	if (    $eva == $journey->{from_eva} -		and $ts == $journey->{checkin_ts} % 337 -		and $ts2 == $journey->{sched_dep_ts} ) -	{ -		return 1; -	} -	return; -} - -sub user_status { -	my ($self) = @_; - -	my $name = $self->stash('name'); -	my $ts   = $self->stash('ts') // 0; -	my $user = $self->users->get_privacy_by_name( name => $name ); - -	if ( not $user ) { -		$self->render('not_found'); -		return; -	} - -	my $status = $self->get_user_status( $user->{id} ); - -	if ( -		$ts -		and ( not $status->{checked_in} -			or $status->{sched_departure}->epoch != $ts ) -	  ) -	{ -		for my $journey ( -			$self->journeys->get( -				uid             => $user->{id}, -				sched_dep_ts    => $ts, -				limit           => 1, -				with_visibility => 1, -			) -		  ) -		{ -			my $visibility -			  = $self->compute_effective_visibility( -				$user->{default_visibility_str}, -				$journey->{visibility_str} ); -			if ( -				$visibility eq 'public' -				or (    $visibility eq 'unlisted' -					and $self->journey_token_ok( $journey, $ts ) ) -				or ( -					$visibility eq 'travelynx' -					and (  $self->is_user_authenticated -						or $self->journey_token_ok( $journey, $ts ) ) -				) -			  ) -			{ -				my $token = $self->param('token') // q{}; -				$self->redirect_to( -					"/p/${name}/j/$journey->{id}?token=${token}-${ts}"); -			} -			else { -				$self->render('not_found'); -			} -			return; -		} -		$self->render('not_found'); -		return; -	} - -	my %tw_data = ( -		card  => 'summary', -		site  => '@derfnull', -		image => $self->url_for('/static/icons/icon-512x512.png') -		  ->to_abs->scheme('https'), -	); -	my %og_data = ( -		type      => 'article', -		image     => $tw_data{image}, -		url       => $self->url_for("/status/${name}")->to_abs->scheme('https'), -		site_name => 'travelynx', -	); - -	my $visibility; -	if ( $status->{checked_in} or $status->{arr_name} ) { -		$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; -			$status->{arr_name}   = undef; -		} -	} -	if (    not $status->{checked_in} -		and $status->{arr_name} -		and not $user->{past_status} ) -	{ -		$status->{arr_name} = undef; -	} - -	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( -			'%s %s von %s nach %s', -			$status->{train_type}, $status->{train_line} // $status->{train_no}, -			$status->{dep_name},   $status->{arr_name}   // 'irgendwo' -		); -		if ( $status->{real_arrival}->epoch ) { -			$tw_data{description} .= $status->{real_arrival} -			  ->strftime(' – Ankunft gegen %H:%M Uhr'); -			$og_data{description} .= $status->{real_arrival} -			  ->strftime(' – Ankunft gegen %H:%M Uhr'); -		} -	} -	else { -		$og_data{title} = $tw_data{title} -		  = "${name} ist gerade nicht eingecheckt"; -		$og_data{description} = $tw_data{description} = q{}; -	} - -	$self->render( -		'user_status', -		name               => $name, -		public_level       => $user->{public_level}, -		journey            => $status, -		journey_visibility => $visibility, -		twitter            => \%tw_data, -		opengraph          => \%og_data, -		version            => $self->app->config->{version} // 'UNKNOWN', -	); -} - -sub public_profile { -	my ($self) = @_; - -	my $name = $self->stash('name'); -	my $user = $self->users->get_privacy_by_name( name => $name ); - -	if ( not $user ) { -		$self->render('not_found'); -		return; -	} - -	my $status = $self->get_user_status( $user->{id} ); -	my $visibility; -	if ( $status->{checked_in} or $status->{arr_name} ) { -		$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; -			$status->{arr_name}   = undef; -		} -	} -	if (    not $status->{checked_in} -		and $status->{arr_name} -		and not $user->{past_status} ) -	{ -		$status->{arr_name} = undef; -	} - -	my @journeys; - -	if ( $user->{past_visible} == 2 -		or ( $user->{past_visible} == 1 and $self->is_user_authenticated ) ) -	{ - -		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'; -		} - -		@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 { -	my ($self)     = @_; -	my $name       = $self->stash('name'); -	my $journey_id = $self->stash('id'); -	my $user       = $self->users->get_privacy_by_name( name => $name ); - -	$self->param( journey_id => $journey_id ); - -	if ( not( $user and $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) { -		$self->render( -			'journey', -			status  => 404, -			error   => 'notfound', -			journey => {} -		); -		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 $is_past; -	if ( not $user->{past_all} ) { -		my $now = DateTime->now( time_zone => 'Europe/Berlin' ); -		if ( $journey->{sched_dep_ts} < $now->subtract( weeks => 4 )->epoch ) { -			$is_past = 1; -		} -	} - -	my $visibility -	  = $self->compute_effective_visibility( $user->{default_visibility_str}, -		$journey->{visibility_str} ); - -	if ( -		not( -			( $visibility eq 'public' and not $is_past ) -			or (    $visibility eq 'unlisted' -				and $self->journey_token_ok($journey) ) -			or ( -				$visibility eq 'travelynx' -				and ( ( $self->is_user_authenticated and not $is_past ) -					or $self->journey_token_ok($journey) ) -			) -		) -	  ) -	{ -		$self->render( -			'journey', -			status  => 404, -			error   => 'notfound', -			journey => {} -		); -		return; -	} - -	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->{comments_visible} ) -	{ -		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 { -	my ($self) = @_; - -	my $name = $self->stash('name'); -	$name =~ s{[.]html$}{}; -	my $user = $self->users->get_privacy_by_name( name => $name ); - -	delete $self->stash->{layout}; - -	if ( not $user ) { -		$self->render('not_found'); -		return; -	} - -	my $status = $self->get_user_status( $user->{id} ); -	my $visibility; -	if ( $status->{checked_in} or $status->{arr_name} ) { -		$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; -			$status->{arr_name}   = undef; -		} -	} -	if (    not $status->{checked_in} -		and $status->{arr_name} -		and not $user->{past_status} ) -	{ -		$status->{arr_name} = undef; -	} - -	$self->render( -		'_public_status_card', -		name               => $name, -		public_level       => $user->{public_level}, -		journey            => $status, -		journey_visibility => $visibility, -	); -} -  sub status_card {  	my ($self) = @_;  	my $status = $self->get_user_status; | 
