Parakeet is a Rust-based Bluesky AppView aiming to implement most of the functionality required to support the Bluesky client

fix!: labeler subjectTypes and subjectCollections

Changed files
+54 -8
consumer
src
indexer
lexica
src
com_atproto
migrations
2025-04-11-155301_labels
parakeet
src
hydration
parakeet-db
+6
consumer/src/indexer/db.rs
··· 798 798 .reason_types 799 799 .as_ref() 800 800 .map(|v| v.iter().map(|v| v.to_string()).collect()); 801 + let subject_types = rec 802 + .subject_types 803 + .as_ref() 804 + .map(|v| v.iter().map(|v| v.to_string()).collect()); 801 805 802 806 let data = models::UpsertLabelerService { 803 807 did: repo, 804 808 cid: cid.to_string(), 805 809 reasons, 810 + subject_types, 811 + subject_collections: rec.subject_collections.as_ref(), 806 812 indexed_at: Utc::now().naive_utc(), 807 813 }; 808 814
+23
lexica/src/com_atproto/moderation.rs
··· 58 58 Record, 59 59 Chat, 60 60 } 61 + 62 + impl Display for SubjectType { 63 + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { 64 + match self { 65 + SubjectType::Account => write!(f, "account"), 66 + SubjectType::Record => write!(f, "record"), 67 + SubjectType::Chat => write!(f, "chat"), 68 + } 69 + } 70 + } 71 + 72 + impl FromStr for SubjectType { 73 + type Err = String; 74 + 75 + fn from_str(s: &str) -> Result<Self, Self::Err> { 76 + match s { 77 + "account" => Ok(SubjectType::Account), 78 + "record" => Ok(SubjectType::Record), 79 + "chat" => Ok(SubjectType::Chat), 80 + x => Err(format!("Unrecognized variant {}", x)), 81 + } 82 + } 83 + }
+7 -5
migrations/2025-04-11-155301_labels/up.sql
··· 1 1 create table labelers 2 2 ( 3 - did text primary key references actors (did) on delete cascade, 4 - cid text not null, 3 + did text primary key references actors (did) on delete cascade, 4 + cid text not null, 5 5 6 - reasons text[], 6 + reasons text[], 7 + subject_types text[], 8 + subject_collections text[], 7 9 8 - created_at timestamp not null default now(), 9 - indexed_at timestamp not null default now() 10 + created_at timestamp not null default now(), 11 + indexed_at timestamp not null default now() 10 12 ); 11 13 12 14 create table labeler_defs
+4
parakeet-db/src/models.rs
··· 593 593 pub cid: String, 594 594 595 595 pub reasons: Option<Vec<Option<String>>>, 596 + pub subject_types: Option<Vec<Option<String>>>, 597 + pub subject_collections: Option<Vec<Option<String>>>, 596 598 597 599 pub created_at: NaiveDateTime, 598 600 pub indexed_at: NaiveDateTime, ··· 606 608 pub cid: String, 607 609 608 610 pub reasons: Option<Vec<String>>, 611 + pub subject_types: Option<Vec<String>>, 612 + pub subject_collections: Option<&'a Vec<String>>, 609 613 610 614 pub indexed_at: NaiveDateTime, 611 615 }
+2
parakeet-db/src/schema.rs
··· 95 95 did -> Text, 96 96 cid -> Text, 97 97 reasons -> Nullable<Array<Nullable<Text>>>, 98 + subject_types -> Nullable<Array<Nullable<Text>>>, 99 + subject_collections -> Nullable<Array<Nullable<Text>>>, 98 100 created_at -> Timestamp, 99 101 indexed_at -> Timestamp, 100 102 }
+12 -3
parakeet/src/hydration/labeler.rs
··· 2 2 use lexica::app_bsky::actor::ProfileView; 3 3 use lexica::app_bsky::labeler::{LabelerPolicy, LabelerView, LabelerViewDetailed}; 4 4 use lexica::com_atproto::label::{Blurs, LabelValueDefinition, Severity}; 5 - use lexica::com_atproto::moderation::ReasonType; 5 + use lexica::com_atproto::moderation::{ReasonType, SubjectType}; 6 6 use parakeet_db::models; 7 7 use std::collections::HashMap; 8 8 use std::str::FromStr; ··· 62 62 }) 63 63 }) 64 64 .collect(); 65 + let subject_types = labeler.subject_types.map(|v| { 66 + v.into_iter() 67 + .flatten() 68 + .filter_map(|v| SubjectType::from_str(&v).ok()) 69 + .collect() 70 + }); 71 + let subject_collections = labeler 72 + .subject_collections 73 + .map(|v| v.into_iter().flatten().collect()); 65 74 66 75 LabelerViewDetailed { 67 76 uri: format!("at://{}/app.bsky.labeler.service/self", labeler.did), ··· 73 82 label_value_definitions, 74 83 }, 75 84 reason_types, 76 - subject_types: None, 77 - subject_collections: None, 85 + subject_types, 86 + subject_collections, 78 87 labels: map_labels(labels), 79 88 indexed_at: labeler.indexed_at, 80 89 }