Something went wrong. Try again.
A lexicon-driven AppView for ATProto. happyview.dev
backfill firehose jetstream atproto appview oauth lexicon
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160//! What the setup wizard would otherwise ask a local instance.
use sqlx::AnyPool;
use crate::db::DatabaseBackend;use crate::error::AppError;use crate::service_identity::{self, IdentityMode};
pub async fn seed(db: &AnyPool, backend: DatabaseBackend) -> Result<(), AppError> { let status = service_identity::get_setup_status(db, backend).await?; // An identity already completed, by an earlier boot or by the developer // through the wizard, is theirs to keep. if status.setup_complete { return Ok(()); } // So is one the wizard started and did not finish: replacing it would // discard whatever the developer chose. An unfinished not-exposed row is // the exception, since it is what an earlier seed leaves if it stops // before marking setup complete, and leaving it would show the wizard on // every boot after. if status .identity_mode .as_ref() .is_some_and(|mode| *mode != IdentityMode::NotExposed) { tracing::info!("setup is unfinished; the dashboard's setup wizard can complete it"); return Ok(()); } service_identity::upsert_identity( db, backend, &IdentityMode::NotExposed, None, None, None, None, ) .await?; // Written before setup is marked complete, so the early return above // implies the marker exists. A database created by this version has // nothing stranded to vacuum. crate::maintenance::vacuum::mark_not_needed(db, backend).await?; service_identity::mark_setup_complete(db, backend).await}
#[cfg(test)]mod tests { use super::*; use crate::db::DatabaseBackend; use crate::service_identity::{IdentityMode, get_identity}; use crate::test_support::migrated_memory_pool;
#[tokio::test] async fn an_empty_instance_is_not_exposed_and_set_up() { let db = migrated_memory_pool().await; seed(&db, DatabaseBackend::Sqlite).await.unwrap(); let identity = get_identity(&db, DatabaseBackend::Sqlite) .await .unwrap() .unwrap(); assert_eq!(identity.mode, IdentityMode::NotExposed); assert!(identity.setup_complete); let vacuum = crate::maintenance::vacuum::read_status(&db, DatabaseBackend::Sqlite) .await .unwrap(); assert!(vacuum.completed_at.is_some()); }
/// A wizard the developer started and did not finish is left as it was, /// whichever mode they chose other than not-exposed. #[tokio::test] async fn an_unfinished_identity_is_left_alone() { for mode in [ IdentityMode::DidWeb, IdentityMode::DidPlc, IdentityMode::AttachAccount, ] { let db = migrated_memory_pool().await; crate::service_identity::upsert_identity( &db, DatabaseBackend::Sqlite, &mode, Some("did:plc:acct"), Some("enc-signing"), None, Some("did:plc:acct"), ) .await .unwrap();
seed(&db, DatabaseBackend::Sqlite).await.unwrap();
let identity = get_identity(&db, DatabaseBackend::Sqlite) .await .unwrap() .unwrap(); assert_eq!(identity.mode, mode); assert_eq!(identity.signing_key_enc.as_deref(), Some("enc-signing")); assert!(!identity.setup_complete, "{mode:?}"); } }
/// A seed that stopped between writing the identity and marking setup /// complete is finished by the next boot. #[tokio::test] async fn an_interrupted_seed_is_finished() { let db = migrated_memory_pool().await; crate::service_identity::upsert_identity( &db, DatabaseBackend::Sqlite, &IdentityMode::NotExposed, None, None, None, None, ) .await .unwrap();
seed(&db, DatabaseBackend::Sqlite).await.unwrap();
let identity = get_identity(&db, DatabaseBackend::Sqlite) .await .unwrap() .unwrap(); assert_eq!(identity.mode, IdentityMode::NotExposed); assert!(identity.setup_complete); }
/// An identity a developer completed through the wizard is theirs, and a /// second boot changes nothing. #[tokio::test] async fn a_completed_identity_is_kept() { let db = migrated_memory_pool().await; crate::service_identity::upsert_identity( &db, DatabaseBackend::Sqlite, &IdentityMode::AttachAccount, Some("did:plc:acct"), None, None, Some("did:plc:acct"), ) .await .unwrap(); crate::service_identity::mark_setup_complete(&db, DatabaseBackend::Sqlite) .await .unwrap();
seed(&db, DatabaseBackend::Sqlite).await.unwrap(); seed(&db, DatabaseBackend::Sqlite).await.unwrap();
let identity = get_identity(&db, DatabaseBackend::Sqlite) .await .unwrap() .unwrap(); assert_eq!(identity.mode, IdentityMode::AttachAccount); }}