From e6b707d72263253a9db954228bf9e1cf11ceebdc Mon Sep 17 00:00:00 2001 From: Mia Date: Tue, 16 Sep 2025 20:55:51 +0100 Subject: [PATCH 01/11] fix(parakeet): fudge out preferences for now to stop PDS crash. --- parakeet/src/xrpc/app_bsky/mod.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/parakeet/src/xrpc/app_bsky/mod.rs b/parakeet/src/xrpc/app_bsky/mod.rs index 8c5a9b84..1fde8c8a 100644 --- a/parakeet/src/xrpc/app_bsky/mod.rs +++ b/parakeet/src/xrpc/app_bsky/mod.rs @@ -10,6 +10,8 @@ mod labeler; #[rustfmt::skip] pub fn routes() -> Router { Router::new() + .route("/app.bsky.actor.getPreferences", get(not_implemented)) + .route("/app.bsky.actor.putPreferences", post(not_implemented)) .route("/app.bsky.actor.getProfile", get(actor::get_profile)) .route("/app.bsky.actor.getProfiles", get(actor::get_profiles)) // TODO: app.bsky.actor.getSuggestions (recs) @@ -63,3 +65,7 @@ pub fn routes() -> Router { // TODO: app.bsky.notification.putPreferences // TODO: app.bsky.notification.putPreferencesV2 } + +async fn not_implemented() -> axum::http::StatusCode { + axum::http::StatusCode::NOT_IMPLEMENTED +} \ No newline at end of file -- 2.51.2 From e8510d7141b5320e2254c112211244a608c49bb5 Mon Sep 17 00:00:00 2001 From: Mia Date: Mon, 22 Sep 2025 20:40:25 +0100 Subject: [PATCH 02/11] feat(consumer): don't index pinned posts where the post isn't by the pinning did --- consumer/src/indexer/mod.rs | 20 +++++++++++++------- consumer/src/utils.rs | 6 ++++++ 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/consumer/src/indexer/mod.rs b/consumer/src/indexer/mod.rs index 0b8c6aba..a1cab307 100644 --- a/consumer/src/indexer/mod.rs +++ b/consumer/src/indexer/mod.rs @@ -7,6 +7,7 @@ use crate::firehose::{ use crate::indexer::types::{ AggregateDeltaStore, BackfillItem, BackfillItemInner, CollectionType, RecordTypes, }; +use crate::utils::at_uri_is_by; use deadpool_postgres::{Object, Pool, Transaction}; use did_resolver::Resolver; use foldhash::quality::RandomState; @@ -551,9 +552,17 @@ pub async fn index_op( rkey: &str, ) -> eyre::Result<()> { match record { - RecordTypes::AppBskyActorProfile(record) => { + RecordTypes::AppBskyActorProfile(mut record) => { if rkey == "self" { let labels = record.labels.clone(); + + // don't allow pinned posts that aren't by us. + if let Some(pinned) = &record.pinned_post { + if !at_uri_is_by(&pinned.uri, repo) { + record.pinned_post = None; + } + } + db::profile_upsert(conn, repo, cid, record).await?; if let Some(labels) = labels { @@ -629,8 +638,7 @@ pub async fn index_op( } } RecordTypes::AppBskyFeedPostgate(record) => { - let split_aturi = record.post.rsplitn(4, '/').collect::>(); - if repo != split_aturi[2] { + if !at_uri_is_by(&record.post, repo) { tracing::warn!("tried to create a postgate on a post we don't control!"); return Ok(()); } @@ -660,8 +668,7 @@ pub async fn index_op( db::repost_insert(conn, rkey, repo, record).await?; } RecordTypes::AppBskyFeedThreadgate(record) => { - let split_aturi = record.post.rsplitn(4, '/').collect::>(); - if repo != split_aturi[2] { + if !at_uri_is_by(&record.post, repo) { tracing::warn!("tried to create a threadgate on a post we don't control!"); return Ok(()); } @@ -701,8 +708,7 @@ pub async fn index_op( db::list_block_insert(conn, at_uri, repo, record).await?; } RecordTypes::AppBskyGraphListItem(record) => { - let split_aturi = record.list.rsplitn(4, '/').collect::>(); - if repo != split_aturi[2] { + if !at_uri_is_by(&record.list, repo) { // it's also probably a bad idea to log *all* the attempts to do this... tracing::warn!("tried to create a listitem on a list we don't control!"); return Ok(()); diff --git a/consumer/src/utils.rs b/consumer/src/utils.rs index cd74eea6..4be0db8d 100644 --- a/consumer/src/utils.rs +++ b/consumer/src/utils.rs @@ -35,3 +35,9 @@ pub fn u64_from_ivec(val: sled::IVec) -> Option { None } } + +pub fn at_uri_is_by(uri: &str, did: &str) -> bool { + let split_aturi = uri.rsplitn(4, '/').collect::>(); + + did == split_aturi[2] +} -- 2.51.2 From 9ca437552716336b21e719c6bab0aa0cb42884cd Mon Sep 17 00:00:00 2001 From: Mia Date: Mon, 22 Sep 2025 20:48:21 +0100 Subject: [PATCH 03/11] chore: formatting & clippy fixes i've been neglecting --- consumer/src/db/copy.rs | 9 ++------- consumer/src/db/record.rs | 9 ++++++++- consumer/src/firehose/mod.rs | 3 +-- consumer/src/indexer/mod.rs | 7 +++---- consumer/src/indexer/types.rs | 2 +- consumer/src/utils.rs | 6 ++---- lexica/src/app_bsky/feed.rs | 4 +--- lexica/src/community_lexicon/bookmarks.rs | 2 +- lexica/src/community_lexicon/mod.rs | 2 +- lexica/src/utils.rs | 4 ++-- parakeet-db/src/models.rs | 6 ++++-- parakeet-db/src/types.rs | 2 +- parakeet/src/xrpc/app_bsky/bookmark.rs | 15 ++++++++------- parakeet/src/xrpc/app_bsky/graph/relations.rs | 2 +- parakeet/src/xrpc/app_bsky/mod.rs | 2 +- 15 files changed, 37 insertions(+), 38 deletions(-) diff --git a/consumer/src/db/copy.rs b/consumer/src/db/copy.rs index 17db6f0f..68065703 100644 --- a/consumer/src/db/copy.rs +++ b/consumer/src/db/copy.rs @@ -5,9 +5,9 @@ use chrono::prelude::*; use deadpool_postgres::Transaction; use futures::pin_mut; use ipld_core::cid::Cid; +use lexica::StrongRef; use tokio_postgres::binary_copy::BinaryCopyInWriter; use tokio_postgres::types::Type; -use lexica::StrongRef; // StrongRefs are used in both likes and reposts const STRONGREF_TYPES: &[Type] = &[ @@ -19,12 +19,7 @@ const STRONGREF_TYPES: &[Type] = &[ Type::TEXT, Type::TIMESTAMP, ]; -type StrongRefRow = ( - String, - StrongRef, - Option, - DateTime, -); +type StrongRefRow = (String, StrongRef, Option, DateTime); // SubjectRefs are used in both blocks and follows const SUBJECT_TYPES: &[Type] = &[Type::TEXT, Type::TEXT, Type::TEXT, Type::TIMESTAMP]; diff --git a/consumer/src/db/record.rs b/consumer/src/db/record.rs index bca14047..3293170a 100644 --- a/consumer/src/db/record.rs +++ b/consumer/src/db/record.rs @@ -37,7 +37,14 @@ pub async fn bookmark_upsert( conn.execute( include_str!("sql/bookmarks_upsert.sql"), - &[&repo, &rkey, &rec.subject, &rec_type, &rec.tags, &rec.created_at], + &[ + &repo, + &rkey, + &rec.subject, + &rec_type, + &rec.tags, + &rec.created_at, + ], ) .await } diff --git a/consumer/src/firehose/mod.rs b/consumer/src/firehose/mod.rs index 1bb98c95..01395680 100644 --- a/consumer/src/firehose/mod.rs +++ b/consumer/src/firehose/mod.rs @@ -119,8 +119,7 @@ impl FirehoseConsumer { } "#sync" => { counter!("firehose_events.total", "event" => "sync").increment(1); - let event: AtpSyncEvent = - serde_ipld_dagcbor::from_reader(&mut reader)?; + let event: AtpSyncEvent = serde_ipld_dagcbor::from_reader(&mut reader)?; // increment the seq if self.seq < event.seq { diff --git a/consumer/src/indexer/mod.rs b/consumer/src/indexer/mod.rs index a1cab307..b0ee18b2 100644 --- a/consumer/src/indexer/mod.rs +++ b/consumer/src/indexer/mod.rs @@ -213,7 +213,8 @@ async fn process_sync( rc: &mut MultiplexedConnection, sync: AtpSyncEvent, ) -> eyre::Result<()> { - let Some((sync_state, Some(current_rev))) = db::actor_get_repo_status(conn, &sync.did).await? else { + let Some((sync_state, Some(current_rev))) = db::actor_get_repo_status(conn, &sync.did).await? + else { return Ok(()); }; @@ -866,9 +867,7 @@ pub async fn index_op_delete( redis::AsyncTypedCommands::del(rc, format!("profile#{repo}")).await?; db::chat_decl_delete(conn, repo).await? } - CollectionType::CommunityLexiconBookmark => { - db::bookmark_delete(conn, rkey, repo).await? - } + CollectionType::CommunityLexiconBookmark => db::bookmark_delete(conn, rkey, repo).await?, _ => unreachable!(), }; diff --git a/consumer/src/indexer/types.rs b/consumer/src/indexer/types.rs index 795b9e5d..de9181f1 100644 --- a/consumer/src/indexer/types.rs +++ b/consumer/src/indexer/types.rs @@ -42,7 +42,7 @@ pub enum RecordTypes { #[serde(rename = "chat.bsky.actor.declaration")] ChatBskyActorDeclaration(records::ChatBskyActorDeclaration), #[serde(rename = "community.lexicon.bookmarks.bookmark")] - CommunityLexiconBookmark(lexica::community_lexicon::bookmarks::Bookmark) + CommunityLexiconBookmark(lexica::community_lexicon::bookmarks::Bookmark), } #[derive(Debug, PartialOrd, PartialEq, Deserialize, Serialize)] diff --git a/consumer/src/utils.rs b/consumer/src/utils.rs index 4be0db8d..1e10a294 100644 --- a/consumer/src/utils.rs +++ b/consumer/src/utils.rs @@ -1,5 +1,5 @@ -use serde::{Deserialize, Deserializer}; use lexica::{Blob, StrongRef}; +use serde::{Deserialize, Deserializer}; // see https://deer.social/profile/did:plc:63y3oh7iakdueqhlj6trojbq/post/3ltuv4skhqs2h pub fn safe_string<'de, D: Deserializer<'de>>(deserializer: D) -> Result { @@ -12,9 +12,7 @@ pub fn blob_ref(blob: Option) -> Option { blob.map(|blob| blob.cid.to_string()) } -pub fn strongref_to_parts( - strongref: Option<&StrongRef>, -) -> (Option, Option) { +pub fn strongref_to_parts(strongref: Option<&StrongRef>) -> (Option, Option) { strongref .map(|sr| (sr.uri.clone(), sr.cid.to_string())) .unzip() diff --git a/lexica/src/app_bsky/feed.rs b/lexica/src/app_bsky/feed.rs index 45fd4c7f..3a71771c 100644 --- a/lexica/src/app_bsky/feed.rs +++ b/lexica/src/app_bsky/feed.rs @@ -219,7 +219,5 @@ pub enum SkeletonReason { #[serde(rename = "app.bsky.feed.defs#skeletonReasonPin")] Pin {}, #[serde(rename = "app.bsky.feed.defs#skeletonReasonRepost")] - Repost { - repost: String, - }, + Repost { repost: String }, } diff --git a/lexica/src/community_lexicon/bookmarks.rs b/lexica/src/community_lexicon/bookmarks.rs index f5cda6ea..d6d23eaa 100644 --- a/lexica/src/community_lexicon/bookmarks.rs +++ b/lexica/src/community_lexicon/bookmarks.rs @@ -11,4 +11,4 @@ pub struct Bookmark { #[serde(skip_serializing_if = "Vec::is_empty")] pub tags: Vec, pub created_at: DateTime, -} \ No newline at end of file +} diff --git a/lexica/src/community_lexicon/mod.rs b/lexica/src/community_lexicon/mod.rs index 3f736c29..bf3e8889 100644 --- a/lexica/src/community_lexicon/mod.rs +++ b/lexica/src/community_lexicon/mod.rs @@ -1 +1 @@ -pub mod bookmarks; \ No newline at end of file +pub mod bookmarks; diff --git a/lexica/src/utils.rs b/lexica/src/utils.rs index a78932b8..5d1e5fbd 100644 --- a/lexica/src/utils.rs +++ b/lexica/src/utils.rs @@ -27,5 +27,5 @@ where LinkRef { link: inp.to_string(), } - .serialize(serializer) -} \ No newline at end of file + .serialize(serializer) +} diff --git a/parakeet-db/src/models.rs b/parakeet-db/src/models.rs index 71a3a10d..c7cee709 100644 --- a/parakeet-db/src/models.rs +++ b/parakeet-db/src/models.rs @@ -292,7 +292,9 @@ pub struct LabelerService { pub indexed_at: NaiveDateTime, } -#[derive(Clone, Debug, Serialize, Deserialize, Queryable, Selectable, Identifiable, Associations)] +#[derive( + Clone, Debug, Serialize, Deserialize, Queryable, Selectable, Identifiable, Associations, +)] #[diesel(table_name = crate::schema::labeler_defs)] #[diesel(belongs_to(LabelerService, foreign_key = labeler))] #[diesel(check_for_backend(diesel::pg::Pg))] @@ -408,4 +410,4 @@ pub struct NewBookmark<'a> { pub subject_cid: Option, pub subject_type: &'a str, pub tags: Vec, -} \ No newline at end of file +} diff --git a/parakeet-db/src/types.rs b/parakeet-db/src/types.rs index 43bc2ea0..a9300cde 100644 --- a/parakeet-db/src/types.rs +++ b/parakeet-db/src/types.rs @@ -85,7 +85,7 @@ macro_rules! text_enum { use std::io::Write; let val = self.to_string(); - out.write(val.as_bytes())?; + out.write_all(val.as_bytes())?; Ok(diesel::serialize::IsNull::No) } } diff --git a/parakeet/src/xrpc/app_bsky/bookmark.rs b/parakeet/src/xrpc/app_bsky/bookmark.rs index 229393b9..5c117a34 100644 --- a/parakeet/src/xrpc/app_bsky/bookmark.rs +++ b/parakeet/src/xrpc/app_bsky/bookmark.rs @@ -8,9 +8,9 @@ use axum::Json; use diesel::prelude::*; use diesel_async::RunQueryDsl; use lexica::app_bsky::bookmark::{BookmarkView, BookmarkViewItem}; +use lexica::StrongRef; use parakeet_db::{models, schema}; use serde::{Deserialize, Serialize}; -use lexica::StrongRef; const BSKY_ALLOWED_TYPES: &[&str] = &["app.bsky.feed.post"]; @@ -125,12 +125,13 @@ pub async fn get_bookmarks( // otherwise just ditch. we should have one. let cid = bookmark.subject_cid.or(maybe_cid)?; - let item = maybe_item.map(BookmarkViewItem::Post).unwrap_or( - BookmarkViewItem::NotFound { - uri: bookmark.subject.clone(), - not_found: true, - }, - ); + let item = + maybe_item + .map(BookmarkViewItem::Post) + .unwrap_or(BookmarkViewItem::NotFound { + uri: bookmark.subject.clone(), + not_found: true, + }); let subject = StrongRef::new_from_str(bookmark.subject, &cid).ok()?; diff --git a/parakeet/src/xrpc/app_bsky/graph/relations.rs b/parakeet/src/xrpc/app_bsky/graph/relations.rs index 804686a3..2bd9af95 100644 --- a/parakeet/src/xrpc/app_bsky/graph/relations.rs +++ b/parakeet/src/xrpc/app_bsky/graph/relations.rs @@ -50,7 +50,7 @@ pub async fn get_blocks( .map(|(last, _)| last.timestamp_millis().to_string()); let dids = results.iter().map(|(_, did)| did.clone()).collect(); - + let profiles = hyd.hydrate_profiles(dids).await; let blocks = profiles.into_values().collect::>(); diff --git a/parakeet/src/xrpc/app_bsky/mod.rs b/parakeet/src/xrpc/app_bsky/mod.rs index 1fde8c8a..ca6a74d7 100644 --- a/parakeet/src/xrpc/app_bsky/mod.rs +++ b/parakeet/src/xrpc/app_bsky/mod.rs @@ -68,4 +68,4 @@ pub fn routes() -> Router { async fn not_implemented() -> axum::http::StatusCode { axum::http::StatusCode::NOT_IMPLEMENTED -} \ No newline at end of file +} -- 2.51.2 From b2548b8cb07c1514c55846b53b2f184716d2cc6d Mon Sep 17 00:00:00 2001 From: Mia Date: Wed, 24 Sep 2025 22:03:14 +0100 Subject: [PATCH 04/11] feat: pronouns and websites https://github.com/bluesky-social/atproto/pull/4224 --- consumer/src/db/record.rs | 2 ++ consumer/src/db/sql/profile_upsert.sql | 6 ++++-- consumer/src/indexer/records.rs | 4 ++++ lexica/src/app_bsky/actor.rs | 4 ++++ migrations/2025-09-24-205239_profiles-4224/down.sql | 3 +++ migrations/2025-09-24-205239_profiles-4224/up.sql | 3 +++ parakeet-db/src/models.rs | 3 +++ parakeet-db/src/schema.rs | 2 ++ parakeet/src/hydration/profile.rs | 2 ++ 9 files changed, 27 insertions(+), 2 deletions(-) create mode 100644 migrations/2025-09-24-205239_profiles-4224/down.sql create mode 100644 migrations/2025-09-24-205239_profiles-4224/up.sql diff --git a/consumer/src/db/record.rs b/consumer/src/db/record.rs index 3293170a..0d18a84f 100644 --- a/consumer/src/db/record.rs +++ b/consumer/src/db/record.rs @@ -576,6 +576,8 @@ pub async fn profile_upsert( &pinned_cid, &joined_sp_uri, &joined_sp_cid, + &rec.pronouns, + &rec.website, &rec.created_at.unwrap_or(Utc::now()).naive_utc(), ], ) diff --git a/consumer/src/db/sql/profile_upsert.sql b/consumer/src/db/sql/profile_upsert.sql index 70cb266f..016b6739 100644 --- a/consumer/src/db/sql/profile_upsert.sql +++ b/consumer/src/db/sql/profile_upsert.sql @@ -1,6 +1,6 @@ INSERT INTO profiles (did, cid, avatar_cid, banner_cid, display_name, description, pinned_uri, pinned_cid, - joined_sp_uri, joined_sp_cid, created_at) -VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11) + joined_sp_uri, joined_sp_cid, pronouns, website, created_at) +VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) ON CONFLICT (did) DO UPDATE SET cid=EXCLUDED.cid, avatar_cid=EXCLUDED.avatar_cid, banner_cid=EXCLUDED.banner_cid, @@ -10,4 +10,6 @@ ON CONFLICT (did) DO UPDATE SET cid=EXCLUDED.cid, pinned_cid=EXCLUDED.pinned_cid, joined_sp_uri=EXCLUDED.joined_sp_uri, joined_sp_cid=EXCLUDED.joined_sp_cid, + pronouns=EXCLUDED.pronouns, + website=EXCLUDED.website, indexed_at=NOW() \ No newline at end of file diff --git a/consumer/src/indexer/records.rs b/consumer/src/indexer/records.rs index 7d8f983a..39bcd4a3 100644 --- a/consumer/src/indexer/records.rs +++ b/consumer/src/indexer/records.rs @@ -23,6 +23,10 @@ pub struct AppBskyActorProfile { pub labels: Option, pub joined_via_starter_pack: Option, pub pinned_post: Option, + #[serde_as(as = "utils::safe_string")] + pub pronouns: Option, + #[serde_as(as = "utils::safe_string")] + pub website: Option, pub created_at: Option>, } diff --git a/lexica/src/app_bsky/actor.rs b/lexica/src/app_bsky/actor.rs index 59d57956..f85ce973 100644 --- a/lexica/src/app_bsky/actor.rs +++ b/lexica/src/app_bsky/actor.rs @@ -199,6 +199,10 @@ pub struct ProfileViewDetailed { pub verification: Option, #[serde(skip_serializing_if = "Option::is_none")] pub status: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub pronouns: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub website: Option, pub created_at: DateTime, pub indexed_at: NaiveDateTime, diff --git a/migrations/2025-09-24-205239_profiles-4224/down.sql b/migrations/2025-09-24-205239_profiles-4224/down.sql new file mode 100644 index 00000000..a465ab0c --- /dev/null +++ b/migrations/2025-09-24-205239_profiles-4224/down.sql @@ -0,0 +1,3 @@ +alter table profiles + drop column pronouns, + drop column website; \ No newline at end of file diff --git a/migrations/2025-09-24-205239_profiles-4224/up.sql b/migrations/2025-09-24-205239_profiles-4224/up.sql new file mode 100644 index 00000000..5c529a45 --- /dev/null +++ b/migrations/2025-09-24-205239_profiles-4224/up.sql @@ -0,0 +1,3 @@ +alter table profiles + add column pronouns text, + add column website text; \ No newline at end of file diff --git a/parakeet-db/src/models.rs b/parakeet-db/src/models.rs index c7cee709..1b1f2098 100644 --- a/parakeet-db/src/models.rs +++ b/parakeet-db/src/models.rs @@ -37,6 +37,9 @@ pub struct Profile { pub joined_sp_uri: Option, pub joined_sp_cid: Option, + pub pronouns: Option, + pub website: Option, + pub created_at: NaiveDateTime, pub indexed_at: NaiveDateTime, } diff --git a/parakeet-db/src/schema.rs b/parakeet-db/src/schema.rs index 8e9e3bb4..8efc3705 100644 --- a/parakeet-db/src/schema.rs +++ b/parakeet-db/src/schema.rs @@ -301,6 +301,8 @@ diesel::table! { joined_sp_cid -> Nullable, created_at -> Timestamp, indexed_at -> Timestamp, + pronouns -> Nullable, + website -> Nullable, } } diff --git a/parakeet/src/hydration/profile.rs b/parakeet/src/hydration/profile.rs index 965d9f9f..15fbe748 100644 --- a/parakeet/src/hydration/profile.rs +++ b/parakeet/src/hydration/profile.rs @@ -229,6 +229,8 @@ fn build_detailed( labels: map_labels(labels), verification, status, + pronouns: profile.pronouns, + website: profile.website, created_at: profile.created_at.and_utc(), indexed_at: profile.indexed_at, } -- 2.51.2 From 2e679c9336b30c4a769b85a4bc9612089365a966 Mon Sep 17 00:00:00 2001 From: Mia Date: Sat, 27 Sep 2025 13:12:51 +0000 Subject: [PATCH 05/11] feat: Viewer Interactions --- lexica/src/app_bsky/actor.rs | 34 +++- lexica/src/app_bsky/feed.rs | 35 +++- lexica/src/app_bsky/graph.rs | 16 +- lexica/src/app_bsky/labeler.rs | 15 +- .../down.sql | 17 ++ .../up.sql | 146 +++++++++++++++ parakeet-db/src/schema.rs | 13 ++ parakeet/src/db.rs | 167 ++++++++++++++++++ parakeet/src/hydration/feedgen.rs | 44 ++++- parakeet/src/hydration/labeler.rs | 59 ++++++- parakeet/src/hydration/list.rs | 54 +++++- parakeet/src/hydration/posts.rs | 92 +++++++++- parakeet/src/hydration/profile.rs | 116 +++++++++++- parakeet/src/loaders.rs | 131 ++++++++++++++ parakeet/src/sql/list_states.sql | 5 + parakeet/src/sql/post_state.sql | 16 ++ parakeet/src/sql/profile_state.sql | 20 +++ parakeet/src/xrpc/app_bsky/bookmark.rs | 28 ++- parakeet/src/xrpc/app_bsky/feed/posts.rs | 84 ++++++--- 19 files changed, 1018 insertions(+), 74 deletions(-) create mode 100644 migrations/2025-09-17-190406_viewer-interactions/down.sql create mode 100644 migrations/2025-09-17-190406_viewer-interactions/up.sql create mode 100644 parakeet/src/sql/list_states.sql create mode 100644 parakeet/src/sql/post_state.sql create mode 100644 parakeet/src/sql/profile_state.sql diff --git a/lexica/src/app_bsky/actor.rs b/lexica/src/app_bsky/actor.rs index f85ce973..62f3f489 100644 --- a/lexica/src/app_bsky/actor.rs +++ b/lexica/src/app_bsky/actor.rs @@ -1,10 +1,32 @@ use crate::app_bsky::embed::External; +use crate::app_bsky::graph::ListViewBasic; use crate::com_atproto::label::Label; use chrono::prelude::*; use serde::{Deserialize, Serialize}; use std::fmt::Display; use std::str::FromStr; +#[derive(Clone, Default, Debug, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ProfileViewerState { + pub muted: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub muted_by_list: Option, + pub blocked_by: bool, + #[serde(skip_serializing_if = "Option::is_none")] + pub blocking: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub blocking_by_list: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub following: Option, + #[serde(skip_serializing_if = "Option::is_none")] + pub followed_by: Option, + // #[serde(skip_serializing_if = "Option::is_none")] + // pub known_followers: Option<()>, + // #[serde(skip_serializing_if = "Option::is_none")] + // pub activity_subscriptions: Option<()>, +} + #[derive(Clone, Default, Debug, Serialize)] #[serde(rename_all = "camelCase")] pub struct ProfileAssociated { @@ -130,8 +152,8 @@ pub struct ProfileViewBasic { pub avatar: Option, #[serde(skip_serializing_if = "Option::is_none")] pub associated: Option, - // #[serde(skip_serializing_if = "Option::is_none")] - // pub viewer: Option<()>, + #[serde(skip_serializing_if = "Option::is_none")] + pub viewer: Option, #[serde(skip_serializing_if = "Vec::is_empty")] pub labels: Vec