dialtone_sqlx 0.1.0

Dialtone SQLx Back-End
Documentation
use crate::db::actor::insert::{insert_actor, InsertActor};
use crate::db::actor::{ActorDbType, ActorVisibilityType};
use crate::db::actor_owner::insert::insert_actor_owner;
use crate::db::ap_object::fetch_random::fetch_random_ap_object_by_actor;
use crate::db::user_principal::insert::insert_user_principal;
use crate::logic::actor::new_actor::{
    banner_from_ap_object, icon_from_ap_object, new_actor, new_actor_with_images, NewActor,
};
use crate::logic::user::auth::new_auth;
use dialtone_common::ap::ap_object::ApObjectType;
use dialtone_common::ap::pun::create_preferred_user_name;
use dialtone_common::ap::ActorType;
use dialtone_common::containers::credentialed_actor::CredentialedActor;
use dialtone_common::media::{system_banners_actor_id, system_icons_actor_id};
use dialtone_common::utils::make_acct::make_acct;
use sqlx::PgPool;

pub async fn create_user_with_default_actor(
    pool: &PgPool,
    user_name: &str,
    host_name: &str,
    password: &str,
) -> anyhow::Result<CredentialedActor> {
    // in a more perfect world, this could re-use the create_user
    // functions. However, the sqlx API does not make passing around transactions easy.
    // See this pending feature: https://github.com/launchbadge/sqlx/discussions/1136
    // which is itself waiting on a Rust lang feature called Generic Associated Types (GAT)

    // create new user data
    let acct_name = make_acct(&user_name.to_lowercase(), host_name);
    let auth_data = new_auth(&acct_name, password)?;

    let preferred_user_name = create_preferred_user_name(user_name, &ActorType::Person);

    // begin transaction
    let mut tx = pool.begin().await?;

    // create new actor data
    let new_actor_info = NewActor {
        preferred_user_name: preferred_user_name.as_str(),
        actor_type: ActorType::Person,
        owner: &acct_name,
        name: None,
        summary: None,
        icon: None,
        image: None,
    };

    let banner_ap_object = fetch_random_ap_object_by_actor(
        &mut tx,
        &ApObjectType::Image,
        &system_banners_actor_id(host_name),
    )
    .await?;
    let banner = banner_from_ap_object(banner_ap_object);

    let icon_ap_object = fetch_random_ap_object_by_actor(
        &mut tx,
        &ApObjectType::Image,
        &system_icons_actor_id(host_name),
    )
    .await?;
    let icon = icon_from_ap_object(icon_ap_object);

    let new_actor_info = new_actor_with_images(&new_actor_info, &icon, &banner);

    let credentialed_actor = new_actor(host_name, &new_actor_info);
    let webfinger_jrd = credentialed_actor.owned_actor.jrd.as_ref();
    let actor_acct = Option::from(webfinger_jrd.unwrap().subject.as_str());
    let insert_actor_data = InsertActor {
        actor_id: &credentialed_actor.owned_actor.ap.id,
        actor_type: &ActorDbType::from(&credentialed_actor.owned_actor.ap.ap_type),
        actor_acct,
        webfinger_jrd,
        activity_pub: &credentialed_actor.owned_actor.ap,
        private_key_pem: Option::from(credentialed_actor.private_key_pem.as_str()),
        visibility: &ActorVisibilityType::Visible,
        system_data: None,
        owner_data: None,
    };

    // insert the new user in the database
    insert_user_principal(&mut tx, &acct_name, auth_data).await?;

    //insert actor
    insert_actor(&mut tx, insert_actor_data).await?;

    // insert actor_owner, which links actor to owner
    insert_actor_owner(
        &mut tx,
        &credentialed_actor.owned_actor.ap.id,
        &acct_name,
        true,
    )
    .await?;

    //commit transaction
    tx.commit().await?;

    //return result
    Ok(credentialed_actor)
}