Loading lib/Travelynx/Command/database.pm +48 −0 Original line number Diff line number Diff line Loading @@ -1470,6 +1470,54 @@ my @migrations = ( } ); }, # v34 -> v35 sub { my ($db) = @_; # 1 : follows # 2 : follow requested # 3 : is blocked by $db->query( qq{ create table relations ( subject_id integer not null references users (id), predicate smallint not null, object_id integer not null references users (id), primary key (subject_id, object_id) ); create view followers as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 1; create view followees as select relations.subject_id as self_id, users.id as id, users.name as name from relations join users on relations.object_id = users.id where predicate = 1; create view follow_requests as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 2; create view blocked_users as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 3; update schema_version set version = 35; } ); }, ); sub sync_stations { Loading lib/Travelynx/Model/Users.pm +194 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ my %visibility_atoi = ( private => 10, ); my %predicate_itoa = ( 1 => 'follows', 2 => 'requests_follow', 3 => 'is_blocked_by', ); my %predicate_atoi = ( follows => 1, requests_follow => 2, is_blocked_by => 3, ); my @sb_templates = ( undef, [ 'DBF', 'https://dbf.finalrewind.org/{name}?rt=1#{tt}{tn}' ], Loading Loading @@ -710,4 +722,186 @@ sub update_webhook_status { ); } # TODO irgendwo muss auch noch ne einstellung rein, um follows / follow requests global zu deaktivieren sub get_relation { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; my $res_h = $db->select( 'relations', ['predicate'], { subject_id => $uid, object_id => $target } )->hash; if ($res_h) { return $predicate_itoa{ $res_h->{predicate} }; } return; #my $res_h = $db->select( 'relations', ['subject_id', 'predicate'], # { subject_id => [$uid, $target], object_id => [$target, $target] } )->hash; } sub request_follow { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->insert( 'relations', { subject_id => $uid, predicate => $predicate_atoi{requests_follow}, object_id => $target, } ); } sub accept_follow_request { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $applicant = $opt{applicant}; $db->update( 'relations', { predicate => $predicate_atoi{follows}, }, { subject_id => $applicant, predicate => $predicate_atoi{requests_follow}, object_id => $uid } ); } sub reject_follow_request { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $applicant = $opt{applicant}; $db->delete( 'relations', { subject_id => $applicant, predicate => $predicate_atoi{requests_follow}, object_id => $uid } ); } sub remove_follower { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $follower = $opt{follower}; $db->delete( 'relations', { subject_id => $follower, predicate => $predicate_atoi{follows}, object_id => $uid } ); } sub block { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->insert( 'relations', { subject_id => $target, predicate => $predicate_atoi{is_blocked_by}, object_id => $uid }, { on_conflict => \ '(subject_id, object_id) do update set predicate = EXCLUDED.predicate' }, ); } sub unblock { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->delete( 'relations', { subject_id => $target, predicate => $predicate_atoi{is_blocked_by}, object_id => $uid }, ); } sub get_followers { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'followers', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_follow_requests { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'follow_requests', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_followees { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'followees', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_blocked_users { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'blocked_users', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } 1; t/21-relations.t 0 → 100644 +375 −0 Original line number Diff line number Diff line #!/usr/bin/env perl # Copyright (C) 2023 Birthe Friesel <derf@finalrewind.org> # # SPDX-License-Identifier: MIT use Mojo::Base -strict; # Tests journey entry and statistics use Test::More; use Test::Mojo; # Include application use FindBin; require "$FindBin::Bin/../index.pl"; my $t = Test::Mojo->new('Travelynx'); if ( not $t->app->config->{db} ) { plan( skip_all => 'No database configured' ); } $t->app->pg->db->query('drop schema if exists travelynx_test_21 cascade'); $t->app->pg->db->query('create schema travelynx_test_21'); $t->app->pg->db->query('set search_path to travelynx_test_21'); $t->app->pg->on( connection => sub { my ( $pg, $dbh ) = @_; $dbh->do('set search_path to travelynx_test_21'); } ); $t->app->config->{mail}->{disabled} = 1; $t->app->start( 'database', 'migrate' ); my $u = $t->app->users; my $uid1 = $u->add( name => 'test1', email => 'test1@example.org', token => 'abcd', password => q{}, ); my $uid2 = $u->add( name => 'test2', email => 'test2@example.org', token => 'efgh', password => q{}, ); $u->verify_registration_token( uid => $uid1, token => 'abcd' ); $u->verify_registration_token( uid => $uid2, token => 'efgh' ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 1 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_follow_requests( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->reject_follow_request( uid => $uid2, applicant => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 1 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_follow_requests( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->accept_follow_request( uid => $uid2, applicant => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'follows' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 1 ); is( scalar $u->get_followees( uid => $uid1 ), 1 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_followers( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); is_deeply( [ $u->get_followees( uid => $uid1 ) ], [ { id => $uid2, name => 'test2' } ] ); $u->remove_follower( uid => $uid2, follower => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); $u->block( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'is_blocked_by' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 1 ); is_deeply( [ $u->get_blocked_users( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->unblock( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->block( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'is_blocked_by' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 1 ); is_deeply( [ $u->get_blocked_users( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->unblock( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); $t->app->pg->db->query('drop schema travelynx_test_21 cascade'); done_testing(); Loading
lib/Travelynx/Command/database.pm +48 −0 Original line number Diff line number Diff line Loading @@ -1470,6 +1470,54 @@ my @migrations = ( } ); }, # v34 -> v35 sub { my ($db) = @_; # 1 : follows # 2 : follow requested # 3 : is blocked by $db->query( qq{ create table relations ( subject_id integer not null references users (id), predicate smallint not null, object_id integer not null references users (id), primary key (subject_id, object_id) ); create view followers as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 1; create view followees as select relations.subject_id as self_id, users.id as id, users.name as name from relations join users on relations.object_id = users.id where predicate = 1; create view follow_requests as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 2; create view blocked_users as select relations.object_id as self_id, users.id as id, users.name as name from relations join users on relations.subject_id = users.id where predicate = 3; update schema_version set version = 35; } ); }, ); sub sync_stations { Loading
lib/Travelynx/Model/Users.pm +194 −0 Original line number Diff line number Diff line Loading @@ -27,6 +27,18 @@ my %visibility_atoi = ( private => 10, ); my %predicate_itoa = ( 1 => 'follows', 2 => 'requests_follow', 3 => 'is_blocked_by', ); my %predicate_atoi = ( follows => 1, requests_follow => 2, is_blocked_by => 3, ); my @sb_templates = ( undef, [ 'DBF', 'https://dbf.finalrewind.org/{name}?rt=1#{tt}{tn}' ], Loading Loading @@ -710,4 +722,186 @@ sub update_webhook_status { ); } # TODO irgendwo muss auch noch ne einstellung rein, um follows / follow requests global zu deaktivieren sub get_relation { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; my $res_h = $db->select( 'relations', ['predicate'], { subject_id => $uid, object_id => $target } )->hash; if ($res_h) { return $predicate_itoa{ $res_h->{predicate} }; } return; #my $res_h = $db->select( 'relations', ['subject_id', 'predicate'], # { subject_id => [$uid, $target], object_id => [$target, $target] } )->hash; } sub request_follow { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->insert( 'relations', { subject_id => $uid, predicate => $predicate_atoi{requests_follow}, object_id => $target, } ); } sub accept_follow_request { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $applicant = $opt{applicant}; $db->update( 'relations', { predicate => $predicate_atoi{follows}, }, { subject_id => $applicant, predicate => $predicate_atoi{requests_follow}, object_id => $uid } ); } sub reject_follow_request { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $applicant = $opt{applicant}; $db->delete( 'relations', { subject_id => $applicant, predicate => $predicate_atoi{requests_follow}, object_id => $uid } ); } sub remove_follower { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $follower = $opt{follower}; $db->delete( 'relations', { subject_id => $follower, predicate => $predicate_atoi{follows}, object_id => $uid } ); } sub block { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->insert( 'relations', { subject_id => $target, predicate => $predicate_atoi{is_blocked_by}, object_id => $uid }, { on_conflict => \ '(subject_id, object_id) do update set predicate = EXCLUDED.predicate' }, ); } sub unblock { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $target = $opt{target}; $db->delete( 'relations', { subject_id => $target, predicate => $predicate_atoi{is_blocked_by}, object_id => $uid }, ); } sub get_followers { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'followers', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_follow_requests { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'follow_requests', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_followees { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'followees', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } sub get_blocked_users { my ( $self, %opt ) = @_; my $db = $opt{db} // $self->{pg}->db; my $uid = $opt{uid}; my $res = $db->select( 'blocked_users', [ 'id', 'name' ], { self_id => $uid } ); return $res->hashes->each; } 1;
t/21-relations.t 0 → 100644 +375 −0 Original line number Diff line number Diff line #!/usr/bin/env perl # Copyright (C) 2023 Birthe Friesel <derf@finalrewind.org> # # SPDX-License-Identifier: MIT use Mojo::Base -strict; # Tests journey entry and statistics use Test::More; use Test::Mojo; # Include application use FindBin; require "$FindBin::Bin/../index.pl"; my $t = Test::Mojo->new('Travelynx'); if ( not $t->app->config->{db} ) { plan( skip_all => 'No database configured' ); } $t->app->pg->db->query('drop schema if exists travelynx_test_21 cascade'); $t->app->pg->db->query('create schema travelynx_test_21'); $t->app->pg->db->query('set search_path to travelynx_test_21'); $t->app->pg->on( connection => sub { my ( $pg, $dbh ) = @_; $dbh->do('set search_path to travelynx_test_21'); } ); $t->app->config->{mail}->{disabled} = 1; $t->app->start( 'database', 'migrate' ); my $u = $t->app->users; my $uid1 = $u->add( name => 'test1', email => 'test1@example.org', token => 'abcd', password => q{}, ); my $uid2 = $u->add( name => 'test2', email => 'test2@example.org', token => 'efgh', password => q{}, ); $u->verify_registration_token( uid => $uid1, token => 'abcd' ); $u->verify_registration_token( uid => $uid2, token => 'efgh' ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 1 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_follow_requests( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->reject_follow_request( uid => $uid2, applicant => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 1 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_follow_requests( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->accept_follow_request( uid => $uid2, applicant => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'follows' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 1 ); is( scalar $u->get_followees( uid => $uid1 ), 1 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); is_deeply( [ $u->get_followers( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); is_deeply( [ $u->get_followees( uid => $uid1 ) ], [ { id => $uid2, name => 'test2' } ] ); $u->remove_follower( uid => $uid2, follower => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->request_follow( uid => $uid1, target => $uid2 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'requests_follow' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); $u->block( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'is_blocked_by' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 1 ); is_deeply( [ $u->get_blocked_users( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->unblock( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 0 ); $u->block( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), 'is_blocked_by' ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); is( scalar $u->get_followers( uid => $uid1 ), 0 ); is( scalar $u->get_followers( uid => $uid2 ), 0 ); is( scalar $u->get_followees( uid => $uid1 ), 0 ); is( scalar $u->get_followees( uid => $uid2 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid1 ), 0 ); is( scalar $u->get_follow_requests( uid => $uid2 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid1 ), 0 ); is( scalar $u->get_blocked_users( uid => $uid2 ), 1 ); is_deeply( [ $u->get_blocked_users( uid => $uid2 ) ], [ { id => $uid1, name => 'test1' } ] ); $u->unblock( uid => $uid2, target => $uid1 ); is( $u->get_relation( uid => $uid1, target => $uid2 ), undef ); is( $u->get_relation( uid => $uid2, target => $uid1 ), undef ); $t->app->pg->db->query('drop schema travelynx_test_21 cascade'); done_testing();