Parakeet is a Rust-based Bluesky AppServer aiming to implement most of the functionality required to support the Bluesky client
appview atproto bluesky rust appserver
66
fork

Configure Feed

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

feat(parakeet): handle no-unauthenticated in getPostThreadV2 correctly

Mia 51779a93 b17cf503

+33
+1
crates/parakeet/src/loaders.rs
··· 626 626 schema::labels::table 627 627 .select(models::Label::as_select()) 628 628 .filter(schema::labels::uri.eq(uri).and(label_filter(&services))) 629 + .order_by(schema::labels::label) 629 630 .load(&mut conn) 630 631 .await 631 632 .unwrap_or_else(|e| {
+32
crates/parakeet/src/xrpc/app_bsky/unspecced/thread_v2.rs
··· 9 9 use itertools::Itertools; 10 10 use lexica::app_bsky::feed::{BlockedAuthor, PostView, ThreadgateView}; 11 11 use lexica::app_bsky::unspecced::{ThreadItemPost, ThreadV2Item, ThreadV2ItemType}; 12 + use lexica::com_atproto::label::Label; 12 13 use serde::{Deserialize, Serialize}; 13 14 use std::cmp::Ordering; 14 15 use std::collections::{HashMap, HashSet}; ··· 53 54 Query(query): Query<GetPostThreadV2Req>, 54 55 ) -> XrpcResult<Json<GetPostThreadV2Res>> { 55 56 let mut conn = state.pool.get().await?; 57 + let is_authed = maybe_auth.is_some(); 56 58 let maybe_did = maybe_auth.clone().map(|v| v.0); 57 59 let hyd = StatefulHydrator::new(&state.dataloaders, &state.cdn, &labelers, maybe_auth); 58 60 ··· 89 91 } 90 92 } 91 93 94 + if labels_has_nounauth(&anchor.author.labels) && !is_authed { 95 + return Ok(Json(GetPostThreadV2Res { 96 + thread: vec![ThreadV2Item { 97 + uri, 98 + depth: 0, 99 + value: ThreadV2ItemType::NoUnauthenticated {}, 100 + }], 101 + threadgate: None, 102 + has_other_replies: false, 103 + })); 104 + } 105 + 92 106 // get the root post URI (if there is one) and return its author's DID. 93 107 let root_uri = crate::db::get_root_post(&mut conn, &uri) 94 108 .await? ··· 151 165 } 152 166 } 153 167 168 + if labels_has_nounauth(&post.author.labels) && !is_authed { 169 + return ThreadV2ItemType::NoUnauthenticated {}; 170 + } 171 + 154 172 let op_thread = (is_op_thread 155 173 || item.root_uri.is_none() && item.parent_uri.is_none()) 156 174 && post.author.did == root_did; ··· 205 223 sort: query.sort, 206 224 maybe_did: &maybe_did, 207 225 max_depth: depth, 226 + is_authed, 208 227 }, 209 228 ); 210 229 thread.extend(children); ··· 281 300 sort: PostThreadSort, 282 301 maybe_did: &'a Option<String>, 283 302 max_depth: i32, 303 + is_authed: bool, 284 304 } 285 305 286 306 fn build_thread_children( ··· 321 341 } 322 342 } 323 343 344 + // much like block relations, Bsky doesn't push the relevant type here 345 + if labels_has_nounauth(&post.author.labels) && !opts.is_authed { 346 + continue; 347 + } 348 + 324 349 // check if the post is hidden AND we're NOT the author (hidden posts still show for their author) 325 350 if hidden.contains(&post.uri) && !did_is_cur(opts.maybe_did, &post.author.did) { 326 351 // post is hidden - do not ~pass go~ push to the thread. ··· 377 402 None => false, 378 403 } 379 404 } 405 + 406 + fn labels_has_nounauth(labels: &[Label]) -> bool { 407 + labels 408 + .iter() 409 + .find(|label| label.val == "!no-unauthenticated") 410 + .is_some() 411 + }