//! One-time labeler setup. //! //! `cargo run --bin setup -- declare` publishes the labeler declaration //! (`app.bsky.labeler.service/self`) with one label per city. This is what //! gives the account a Subscribe button. Safe to re-run after editing the list. use anyhow::{Result, bail}; use cities_labeler::cities::Cities; use cities_labeler::config::Config; use cities_labeler::login; use jacquard::api::app_bsky::labeler::LabelerPolicies; use jacquard::api::app_bsky::labeler::service::Service; use jacquard::api::com_atproto::label::{ LabelValue, LabelValueDefinition, LabelValueDefinitionBlurs, LabelValueDefinitionDefaultSetting, LabelValueDefinitionSeverity, LabelValueDefinitionStrings, }; use jacquard::prelude::*; use jacquard::types::language::Language; use jacquard::types::recordkey::RecordKey; use jacquard::types::string::Datetime; #[tokio::main] async fn main() -> Result<()> { let config = Config::from_env()?; match std::env::args().nth(1).as_deref() { Some("declare") => declare(&config).await, _ => bail!("usage: setup declare"), } } async fn declare(config: &Config) -> Result<()> { let cities = Cities::load(&config.cities_path)?; let (agent, did) = login(&config.handle, &config.app_password).await?; let definitions: Vec = cities .iter() .map(|city| LabelValueDefinition { identifier: city.id.as_str().into(), // a neutral badge, shown by default, never hiding content severity: LabelValueDefinitionSeverity::Inform, blurs: LabelValueDefinitionBlurs::None, default_setting: Some(LabelValueDefinitionDefaultSetting::Warn), adult_only: Some(false), locales: vec![LabelValueDefinitionStrings { lang: Language::new_static("en").expect("valid language tag"), name: city.display().into(), description: format!("Chose {} as their city.", city.display()).into(), extra_data: None, }], extra_data: None, }) .collect(); let service: Service = Service { created_at: Datetime::now(), labels: None, policies: LabelerPolicies { label_values: cities .iter() .map(|c| LabelValue::Other(c.id.as_str().into())) .collect(), label_value_definitions: Some(definitions), extra_data: None, }, // these declare which reports the labeler reviews: none reason_types: Some(vec![]), subject_types: Some(vec![]), subject_collections: None, extra_data: None, }; let output = agent .put_record(RecordKey::any_static("self")?, service) .await?; println!( "published {} with {} labels for {did}", output.uri, cities.len() ); Ok(()) }