Unverified Commit 00eb6af1 authored by Birte Kristina Friesel's avatar Birte Kristina Friesel
Browse files

expose follows / social interaction in frontend

parent 07fe4ecd
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -399,6 +399,9 @@ sub startup {
			if ( $visibility eq 'travelynx' ) {
				return 'lock_open';
			}
			if ( $visibility eq 'followers' ) {
				return 'group';
			}
			if ( $visibility eq 'unlisted' ) {
				return 'lock_outline';
			}
@@ -2213,6 +2216,8 @@ sub startup {

	$authed_r->get('/account')->to('account#account');
	$authed_r->get('/account/privacy')->to('account#privacy');
	$authed_r->get('/account/social')->to('account#social');
	$authed_r->get('/account/social/:kind')->to('account#social_list');
	$authed_r->get('/account/profile')->to('account#profile');
	$authed_r->get('/account/hooks')->to('account#webhook');
	$authed_r->get('/account/traewelling')->to('traewelling#settings');
@@ -2240,6 +2245,7 @@ sub startup {
	$authed_r->get('/s/*station')->to('traveling#station');
	$authed_r->get('/confirm_mail/:token')->to('account#confirm_mail');
	$authed_r->post('/account/privacy')->to('account#privacy');
	$authed_r->post('/account/social')->to('account#social');
	$authed_r->post('/account/profile')->to('account#profile');
	$authed_r->post('/account/hooks')->to('account#webhook');
	$authed_r->post('/account/traewelling')->to('traewelling#settings');
@@ -2254,6 +2260,7 @@ sub startup {
	$authed_r->post('/account/password')->to('account#change_password');
	$authed_r->post('/account/mail')->to('account#change_mail');
	$authed_r->post('/account/name')->to('account#change_name');
	$authed_r->post('/social-action')->to('account#social_action');
	$authed_r->post('/delete')->to('account#delete');
	$authed_r->post('/logout')->to('account#do_logout');
	$authed_r->post('/set_token')->to('api#set_token');
+21 −0
Original line number Diff line number Diff line
@@ -1545,6 +1545,27 @@ my @migrations = (
			}
		);
	},

	# v37 -> v38
	sub {
		my ($db) = @_;
		$db->query(
			qq{
				drop view followers;
				create view followers as select
					relations.object_id as self_id,
					users.id as id,
					users.name as name,
					users.accept_follows as accept_follows,
					r2.predicate as inverse_predicate
					from relations
					join users on relations.subject_id = users.id
					left join relations as r2 on relations.subject_id = r2.object_id
					where relations.predicate = 1;
				update schema_version set version = 38;
			}
		);
	},
);

# TODO add 'hafas' column to in_transit (and maybe journeys? undo/redo needs something to work with...)
+240 −14
Original line number Diff line number Diff line
@@ -408,11 +408,8 @@ sub delete {
	my ($self) = @_;
	my $uid = $self->current_user->{id};
	if ( $self->validation->csrf_protect->has_error('csrf_token') ) {
		$self->render(
			'account',
			api_token => $self->users->get_api_token( uid => $uid ),
			invalid   => 'csrf',
		);
		$self->flash( invalid => 'csrf' );
		$self->redirect_to('account');
		return;
	}

@@ -424,11 +421,8 @@ sub delete {
			)
		  )
		{
			$self->render(
				'account',
				api_token => $self->users->get_api_token( uid => $uid ),
				invalid   => 'deletion password'
			);
			$self->flash( invalid => 'deletion password' );
			$self->redirect_to('account');
			return;
		}
		$self->users->flag_deletion( uid => $uid );
@@ -501,6 +495,228 @@ sub privacy {
	}
}

sub social {
	my ($self) = @_;

	my $user = $self->current_user;

	if ( $self->param('action') and $self->param('action') eq 'save' ) {
		if ( $self->validation->csrf_protect->has_error('csrf_token') ) {
			$self->render(
				'social',
				invalid => 'csrf',
			);
			return;
		}

		my %opt;
		my $accept_follow = $self->param('accept_follow');

		if ( $accept_follow eq 'yes' ) {
			$opt{accept_follows} = 1;
		}
		elsif ( $accept_follow eq 'request' ) {
			$opt{accept_follow_requests} = 1;
		}

		$self->users->set_social(
			uid => $user->{id},
			%opt
		);

		$self->flash( success => 'social' );
		$self->redirect_to('account');
	}
	else {
		if ( $user->{accept_follows} ) {
			$self->param( accept_follow => 'yes' );
		}
		elsif ( $user->{accept_follow_requests} ) {
			$self->param( accept_follow => 'request' );
		}
		else {
			$self->param( accept_follow => 'no' );
		}
		$self->render( 'social', name => $user->{name} );
	}
}

sub social_list {
	my ($self) = @_;

	my $kind = $self->stash('kind');
	my $user = $self->current_user;

	if ( $kind eq 'follow-requests' ) {
		my @follow_reqs
		  = $self->users->get_follow_requests( uid => $user->{id} );
		$self->render(
			'social_list',
			type          => 'follow-requests',
			entries       => [@follow_reqs],
			notifications => $user->{notifications},
		);
	}
	elsif ( $kind eq 'followers' ) {
		my @followers = $self->users->get_followers( uid => $user->{id} );
		$self->render(
			'social_list',
			type          => 'followers',
			entries       => [@followers],
			notifications => $user->{notifications},
		);
	}
	elsif ( $kind eq 'follows' ) {
		my @following = $self->users->get_followees( uid => $user->{id} );
		$self->render(
			'social_list',
			type          => 'follows',
			entries       => [@following],
			notifications => $user->{notifications},
		);
	}
	elsif ( $kind eq 'blocks' ) {
		my @blocked = $self->users->get_blocked_users( uid => $user->{id} );
		$self->render(
			'social_list',
			type          => 'blocks',
			entries       => [@blocked],
			notifications => $user->{notifications},
		);
	}
	else {
		$self->render( 'not_found', status => 404 );
	}
}

sub social_action {
	my ($self) = @_;

	my $user        = $self->current_user;
	my $action      = $self->param('action');
	my $target_ids  = $self->param('target');
	my $redirect_to = $self->param('redirect_to');

	for my $key (
		qw(follow request_follow follow_or_request unfollow remove_follower cancel_follow_request accept_follow_request reject_follow_request block unblock)
	  )
	{
		if ( $self->param($key) ) {
			$action     = $key;
			$target_ids = $self->param($key);
		}
	}

	if ( $self->validation->csrf_protect->has_error('csrf_token') ) {
		$self->redirect_to('/');
		return;
	}

	if ( $action and $action eq 'clear_notifications' ) {
		$self->users->update_notifications(
			db                  => $self->pg->db,
			uid                 => $user->{id},
			has_follow_requests => 0
		);
		$self->flash( success => 'clear_notifications' );
		$self->redirect_to('account');
		return;
	}

	if ( not( $action and $target_ids and $redirect_to ) ) {
		$self->redirect_to('/');
		return;
	}

	for my $target_id ( split( qr{,}, $target_ids ) ) {
		my $target = $self->users->get_privacy_by( uid => $target_id );

		if ( not $target ) {
			next;
		}

		if ( $action eq 'follow' and $target->{accept_follows} ) {
			$self->users->follow(
				uid    => $user->{id},
				target => $target->{id}
			);
		}
		elsif ( $action eq 'request_follow'
			and $target->{accept_follow_requests} )
		{
			$self->users->request_follow(
				uid    => $user->{id},
				target => $target->{id}
			);
		}
		elsif ( $action eq 'follow_or_request' ) {
			if ( $target->{accept_follows} ) {
				$self->users->follow(
					uid    => $user->{id},
					target => $target->{id}
				);
			}
			elsif ( $target->{accept_follow_requests} ) {
				$self->users->request_follow(
					uid    => $user->{id},
					target => $target->{id}
				);
			}
		}
		elsif ( $action eq 'unfollow' ) {
			$self->users->unfollow(
				uid    => $user->{id},
				target => $target->{id}
			);
		}
		elsif ( $action eq 'remove_follower' ) {
			$self->users->remove_follower(
				uid      => $user->{id},
				follower => $target->{id}
			);
		}
		elsif ( $action eq 'cancel_follow_request' ) {
			$self->users->cancel_follow_request(
				uid    => $user->{id},
				target => $target->{id}
			);
		}
		elsif ( $action eq 'accept_follow_request' ) {
			$self->users->accept_follow_request(
				uid       => $user->{id},
				applicant => $target->{id}
			);
		}
		elsif ( $action eq 'reject_follow_request' ) {
			$self->users->reject_follow_request(
				uid       => $user->{id},
				applicant => $target->{id}
			);
		}
		elsif ( $action eq 'block' ) {
			$self->users->block(
				uid    => $user->{id},
				target => $target->{id}
			);
		}
		elsif ( $action eq 'unblock' ) {
			$self->users->unblock(
				uid    => $user->{id},
				target => $target->{id}
			);
		}

		if ( $redirect_to eq 'profile' ) {

			# profile links do not perform bulk actions
			$self->redirect_to( '/p/' . $target->{name} );
			return;
		}
	}

	$self->redirect_to($redirect_to);
}

sub profile {
	my ($self) = @_;
	my $user = $self->current_user;
@@ -1014,9 +1230,19 @@ sub confirm_mail {
sub account {
	my ($self)          = @_;
	my $uid             = $self->current_user->{id};
	my $follow_requests = $self->users->has_follow_requests( uid => $uid );
	my $followers       = $self->users->has_followers( uid => $uid );
	my $following       = $self->users->has_followees( uid => $uid );
	my $blocked         = $self->users->has_blocked_users( uid => $uid );

	$self->render( 'account',
		api_token => $self->users->get_api_token( uid => $uid ) );
	$self->render(
		'account',
		api_token           => $self->users->get_api_token( uid => $uid ),
		num_follow_requests => $follow_requests,
		num_followers       => $followers,
		num_following       => $following,
		num_blocked         => $blocked,
	);
	$self->users->mark_seen( uid => $uid );
}

+96 −4
Original line number Diff line number Diff line
@@ -186,6 +186,23 @@ sub profile {
		metadata         => $profile->{metadata},
		public_level     => $user->{public_level},
		is_self          => $is_self,
		following        => ( $relation and $relation eq 'follows' ) ? 1 : 0,
		follow_requested => ( $relation and $relation eq 'requests_follow' )
		? 1
		: 0,
		can_follow => ( $my_user and $user->{accept_follows} and not $relation )
		? 1
		: 0,
		can_request_follow =>
		  ( $my_user and $user->{accept_follow_requests} and not $relation )
		? 1
		: 0,
		follows_me => ( $inverse_relation and $inverse_relation eq 'follows' )
		? 1
		: 0,
		follow_reqs_me =>
		  ( $inverse_relation and $inverse_relation eq 'requests_follow' ) ? 1
		: 0,
		journey            => $status,
		journey_visibility => $visibility,
		journeys           => [@journeys],
@@ -201,6 +218,24 @@ sub journey_details {

	$self->param( journey_id => $journey_id );

	my $my_user;
	my $relation;
	my $inverse_relation;
	my $is_self;
	if ( $self->is_user_authenticated ) {
		$my_user = $self->current_user;
		if ( $my_user->{id} == $user->{id} ) {
			$is_self = 1;
			$my_user = undef;
		}
		else {
			$relation = $self->users->get_relation(
				subject => $my_user->{id},
				object  => $user->{id}
			);
		}
	}

	if ( not( $user and $journey_id and $journey_id =~ m{ ^ \d+ $ }x ) ) {
		$self->render(
			'journey',
@@ -249,7 +284,12 @@ sub journey_details {
				and $self->journey_token_ok($journey) )
			or (
				$visibility eq 'travelynx'
				and ( ( $self->is_user_authenticated and not $is_past )
				and ( ( $my_user and not $is_past )
					or $self->journey_token_ok($journey) )
			)
			or (
				$visibility eq 'followers'
				and ( ( $relation and $relation eq 'follows' )
					or $self->journey_token_ok($journey) )
			)
		)
@@ -337,6 +377,24 @@ sub user_status {
		return;
	}

	my $my_user;
	my $relation;
	my $inverse_relation;
	my $is_self;
	if ( $self->is_user_authenticated ) {
		$my_user = $self->current_user;
		if ( $my_user->{id} == $user->{id} ) {
			$is_self = 1;
			$my_user = undef;
		}
		else {
			$relation = $self->users->get_relation(
				subject => $my_user->{id},
				object  => $user->{id}
			);
		}
	}

	my $status = $self->get_user_status( $user->{id} );

	if (
@@ -364,7 +422,12 @@ sub user_status {
					and $self->journey_token_ok( $journey, $ts ) )
				or (
					$visibility eq 'travelynx'
					and (  $self->is_user_authenticated
					and (  $my_user
						or $self->journey_token_ok( $journey, $ts ) )
				)
				or (
					$visibility eq 'followers'
					and ( ( $relation and $relation eq 'follows' )
						or $self->journey_token_ok( $journey, $ts ) )
				)
			  )
@@ -408,7 +471,12 @@ sub user_status {
					and $self->status_token_ok( $status, $ts ) )
				or (
					$visibility eq 'travelynx'
					and (  $self->is_user_authenticated
					and (  $my_user
						or $self->status_token_ok( $status, $ts ) )
				)
				or (
					$visibility eq 'followers'
					and ( ( $relation and $relation eq 'follows' )
						or $self->status_token_ok( $status, $ts ) )
				)
			)
@@ -486,6 +554,24 @@ sub status_card {
		return;
	}

	my $my_user;
	my $relation;
	my $inverse_relation;
	my $is_self;
	if ( $self->is_user_authenticated ) {
		$my_user = $self->current_user;
		if ( $my_user->{id} == $user->{id} ) {
			$is_self = 1;
			$my_user = undef;
		}
		else {
			$relation = $self->users->get_relation(
				subject => $my_user->{id},
				object  => $user->{id}
			);
		}
	}

	my $status = $self->get_user_status( $user->{id} );
	my $visibility;
	if ( $status->{checked_in} or $status->{arr_name} ) {
@@ -500,7 +586,12 @@ sub status_card {
					and $self->status_token_ok($status) )
				or (
					$visibility eq 'travelynx'
					and (  $self->is_user_authenticated
					and (  $my_user
						or $self->status_token_ok($status) )
				)
				or (
					$visibility eq 'followers'
					and ( ( $relation and $relation eq 'follows' )
						or $self->status_token_ok($status) )
				)
			)
@@ -523,6 +614,7 @@ sub status_card {
		public_level       => $user->{public_level},
		journey            => $status,
		journey_visibility => $visibility,
		from_profile       => $self->param('profile') ? 1 : 0,
	);
}

+1 −0
Original line number Diff line number Diff line
@@ -1459,6 +1459,7 @@ sub journey_details {

		if (   $visibility eq 'public'
			or $visibility eq 'travelynx'
			or $visibility eq 'followers'
			or $visibility eq 'unlisted' )
		{
			my $delay = 'pünktlich ';
Loading