perlsky is a Perl 5 implementation of an AT Protocol Personal Data Server.
13
fork

Configure Feed

Select the types of activity you want to include in your feed.

Limit local appview fields to authoritative data

alice 70d8c1c4 eca10ae9

+23 -40
-2
lib/ATProto/PDS/ServiceProxy/Profile.pm
··· 7 7 8 8 use Exporter 'import'; 9 9 use JSON::PP (); 10 - use Mojo::URL; 11 10 12 11 use ATProto::PDS::API::Util qw(iso8601 resolve_repo xrpc_error); 13 12 ··· 109 108 %{ $self->_profile_view_basic($c, $account, $profile_value) }, 110 109 createdAt => iso8601($account->{created_at}), 111 110 indexedAt => iso8601($account->{created_at}), 112 - followersCount => 0 + ($follow_index->{followers_by_subject}{ $account->{did} } // 0), 113 111 followsCount => 0 + ($follow_index->{follows_by_actor}{ $account->{did} } // 0), 114 112 postsCount => 0 + $c->store->count_records_by_collection($account->{did}, 'app.bsky.feed.post'), 115 113 };
+15 -33
lib/ATProto/PDS/ServiceProxy/Threads.pm
··· 109 109 110 110 sub _post_view ($self, $c, $account, $row, $profile_value = undef, $viewer = undef, $depth = 0) { 111 111 my $uri = $self->_post_uri($account, $row); 112 - my $counts = $self->_post_counts_and_viewer($c, $uri, $viewer); 113 112 my $post = { 114 - uri => $uri, 115 - cid => $row->{cid}, 116 - author => $self->_profile_view_basic($c, $account, $profile_value, $viewer), 117 - record => $row->{value}, 118 - bookmarkCount => 0, 119 - replyCount => $counts->{replyCount}, 120 - repostCount => $counts->{repostCount}, 121 - likeCount => $counts->{likeCount}, 122 - quoteCount => $counts->{quoteCount}, 123 - indexedAt => $self->_post_indexed_at($row), 124 - labels => [], 113 + uri => $uri, 114 + cid => $row->{cid}, 115 + author => $self->_profile_view_basic($c, $account, $profile_value, $viewer), 116 + record => $row->{value}, 117 + indexedAt => $self->_post_indexed_at($row), 118 + labels => [], 125 119 }; 126 120 if ($depth < 2) { 127 121 my $embed = $self->_post_embed_view($c, $account, $row->{value}, $viewer, $depth + 1); 128 122 $post->{embed} = $embed if defined $embed; 129 123 } 130 - $post->{viewer} = $counts->{viewer} if %{ $counts->{viewer} }; 124 + my $viewer_state = $self->_post_counts_and_viewer($c, $uri, $viewer)->{viewer} || {}; 125 + $post->{viewer} = $viewer_state if %$viewer_state; 131 126 return $post; 132 127 } 133 128 ··· 184 179 sub _post_counts_and_viewer ($self, $c, $post_uri, $viewer = undef) { 185 180 my $index = $self->_local_post_index($c); 186 181 my $viewer_did = $viewer ? $viewer->{did} : undef; 187 - my $base = $index->{stats}{$post_uri} || { 188 - likeCount => 0, 189 - repostCount => 0, 190 - replyCount => 0, 191 - quoteCount => 0, 192 - }; 193 - my $stats = { 194 - %$base, 195 - viewer => {}, 196 - }; 182 + my $viewer_state = {}; 197 183 if (defined $viewer_did) { 198 - my $viewer = $index->{viewer}{$post_uri} || {}; 199 - $stats->{viewer}{like} = $viewer->{like}{$viewer_did} 200 - if defined $viewer->{like}{$viewer_did}; 201 - $stats->{viewer}{repost} = $viewer->{repost}{$viewer_did} 202 - if defined $viewer->{repost}{$viewer_did}; 184 + my $state = $index->{viewer}{$post_uri} || {}; 185 + $viewer_state->{like} = $state->{like}{$viewer_did} 186 + if defined $state->{like}{$viewer_did}; 187 + $viewer_state->{repost} = $state->{repost}{$viewer_did} 188 + if defined $state->{repost}{$viewer_did}; 203 189 } 204 - return $stats; 190 + return { viewer => $viewer_state }; 205 191 } 206 192 207 193 sub _local_post_index ($self, $c) { ··· 435 421 indexedAt => $post_view->{indexedAt}, 436 422 ); 437 423 $record_view{labels} = $post_view->{labels} if $post_view->{labels}; 438 - $record_view{replyCount} = $post_view->{replyCount} if defined $post_view->{replyCount}; 439 - $record_view{repostCount} = $post_view->{repostCount} if defined $post_view->{repostCount}; 440 - $record_view{likeCount} = $post_view->{likeCount} if defined $post_view->{likeCount}; 441 - $record_view{quoteCount} = $post_view->{quoteCount} if defined $post_view->{quoteCount}; 442 424 $record_view{embeds} = [ $post_view->{embed} ] if defined $post_view->{embed}; 443 425 return \%record_view; 444 426 }
+8 -5
t/service-proxy.t
··· 215 215 ->json_is('/labels' => []) 216 216 ->json_has('/createdAt') 217 217 ->json_has('/indexedAt') 218 - ->json_is('/followersCount' => 0) 219 218 ->json_is('/followsCount' => 0) 220 219 ->json_is('/postsCount' => 0); 220 + ok(!exists($t->tx->res->json->{followersCount}), 'local profile omits non-authoritative followersCount'); 221 221 222 222 $t->post_ok('/xrpc/com.atproto.repo.createRecord' => { 223 223 Authorization => "Bearer $access", ··· 250 250 $t->get_ok("/xrpc/app.bsky.actor.getProfile?actor=$did" => { 251 251 Authorization => "Bearer $access", 252 252 })->status_is(200) 253 - ->json_is('/followersCount' => 1) 254 - ->json_is('/followsCount' => 1); 253 + ->json_is('/followsCount' => 1) 254 + ->json_hasnt('/viewer/knownFollowers'); 255 + ok(!exists($t->tx->res->json->{followersCount}), 'local profile still omits followersCount after remote-follow-capable activity'); 255 256 256 257 $t->get_ok("/xrpc/app.bsky.actor.getProfile?actor=$bob_did" => { 257 258 Authorization => "Bearer $access", 258 259 })->status_is(200) 259 - ->json_is('/followersCount' => 1) 260 260 ->json_is('/followsCount' => 1) 261 261 ->json_is('/viewer/following' => "at://$did/app.bsky.graph.follow/follow-bob") 262 262 ->json_is('/viewer/followedBy' => "at://$bob_did/app.bsky.graph.follow/follow-alice"); 263 + ok(!exists($t->tx->res->json->{followersCount}), 'remote-follower-dependent followersCount is omitted for followed local profiles'); 263 264 264 265 $t->post_ok('/xrpc/com.atproto.repo.createRecord' => { 265 266 Authorization => "Bearer $bob_access", ··· 309 310 })->status_is(200) 310 311 ->json_is('/feed/0/post/uri' => $post_uri) 311 312 ->json_is('/feed/0/post/record/text' => 'browser smoke post') 312 - ->json_is('/feed/0/post/bookmarkCount' => 0) 313 313 ->json_is('/feed/0/post/author/associated/chat/allowIncoming' => 'all') 314 314 ->json_is('/feed/0/post/author/associated/activitySubscription/allowSubscriptions' => 'followers') 315 315 ->json_is('/feed/0/post/author/labels' => []) 316 316 ->json_has('/feed/0/post/author/createdAt'); 317 + ok(!exists($t->tx->res->json->{feed}[0]{post}{bookmarkCount}), 'local post view omits non-authoritative bookmarkCount'); 318 + ok(!exists($t->tx->res->json->{feed}[0]{post}{replyCount}), 'local post view omits non-authoritative replyCount'); 319 + ok(!exists($t->tx->res->json->{feed}[0]{post}{likeCount}), 'local post view omits non-authoritative likeCount'); 317 320 318 321 $t->get_ok('/xrpc/app.bsky.feed.getPostThread?uri=' . _uri_escape($post_uri) => { 319 322 Authorization => "Bearer $access",