diff --git a/src/cli/faker.rs b/src/cli/faker.rs index 5d8899e..858c0c0 100644 --- a/src/cli/faker.rs +++ b/src/cli/faker.rs @@ -1,15 +1,16 @@ -use crate::model::{addressing, config, credential, activity, object, user, Audience}; +use crate::model::{addressing, config, credential, activity, object, actor, Audience}; use openssl::rsa::Rsa; -use sea_orm::IntoActiveModel; +use sea_orm::{ActiveValue::NotSet, IntoActiveModel}; -pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_orm::DbErr> { +pub async fn faker(ctx: crate::server::Context, count: i64) -> Result<(), sea_orm::DbErr> { use sea_orm::{EntityTrait, Set}; let domain = ctx.domain(); let db = ctx.db(); let key = Rsa::generate(2048).unwrap(); - let test_user = user::Model { + let test_user = actor::Model { + internal: 42, id: format!("{domain}/users/test"), name: Some("μpub".into()), domain: clean_domain(domain), @@ -19,24 +20,25 @@ pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_or following_count: 0, followers: None, followers_count: 0, - statuses_count: count as i64, + statuses_count: count as i32, icon: Some("https://cdn.alemi.dev/social/circle-square.png".to_string()), image: Some("https://cdn.alemi.dev/social/someriver-xs.jpg".to_string()), inbox: None, shared_inbox: None, outbox: None, actor_type: apb::ActorType::Person, - created: chrono::Utc::now(), + published: chrono::Utc::now(), updated: chrono::Utc::now(), private_key: Some(std::str::from_utf8(&key.private_key_to_pem().unwrap()).unwrap().to_string()), // TODO generate a fresh one every time public_key: std::str::from_utf8(&key.public_key_to_pem().unwrap()).unwrap().to_string(), }; - user::Entity::insert(test_user.clone().into_active_model()).exec(db).await?; + actor::Entity::insert(test_user.clone().into_active_model()).exec(db).await?; config::Entity::insert(config::ActiveModel { - id: Set(test_user.id.clone()), + internal: NotSet, + actor: Set(test_user.id.clone()), accept_follow_requests: Set(true), show_followers: Set(true), show_following: Set(true), @@ -45,8 +47,9 @@ pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_or }).exec(db).await?; credential::Entity::insert(credential::ActiveModel { - id: Set(test_user.id.clone()), - email: Set("mail@example.net".to_string()), + internal: NotSet, + actor: Set(test_user.id.clone()), + login: Set("mail@example.net".to_string()), password: Set(sha256::digest("very-strong-password")), }).exec(db).await?; @@ -57,15 +60,16 @@ pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_or let aid = uuid::Uuid::new_v4(); addressing::Entity::insert(addressing::ActiveModel { - actor: Set(apb::target::PUBLIC.to_string()), - server: Set("www.w3.org".to_string()), - activity: Set(Some(format!("{domain}/activities/{aid}"))), - object: Set(Some(format!("{domain}/objects/{oid}"))), + actor: Set(None), + instance: Set(None), + activity: Set(Some(42 + i)), + object: Set(Some(42 + i)), published: Set(chrono::Utc::now()), ..Default::default() }).exec(db).await?; object::Entity::insert(object::ActiveModel { + internal: Set(42 + i), id: Set(format!("{domain}/objects/{oid}")), name: Set(None), object_type: Set(apb::ObjectType::Note), @@ -74,11 +78,11 @@ pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_or context: Set(Some(context.clone())), in_reply_to: Set(None), content: Set(Some(format!("[{i}] Tic(k). Quasiparticle of intensive multiplicity. Tics (or ticks) are intrinsically several components of autonomously numbering anorganic populations, propagating by contagion between segmentary divisions in the order of nature. Ticks - as nonqualitative differentially-decomposable counting marks - each designate a multitude comprehended as a singular variation in tic(k)-density."))), - published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)), - updated: Set(None), - comments: Set(0), + published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i as u64)), + updated: Set(chrono::Utc::now()), + replies: Set(0), likes: Set(0), - shares: Set(0), + announces: Set(0), to: Set(Audience(vec![apb::target::PUBLIC.to_string()])), bto: Set(Audience::default()), cc: Set(Audience(vec![])), @@ -88,12 +92,13 @@ pub async fn faker(ctx: crate::server::Context, count: u64) -> Result<(), sea_or }).exec(db).await?; activity::Entity::insert(activity::ActiveModel { + internal: Set(42 + i), id: Set(format!("{domain}/activities/{aid}")), activity_type: Set(apb::ActivityType::Create), actor: Set(format!("{domain}/users/test")), object: Set(Some(format!("{domain}/objects/{oid}"))), target: Set(None), - published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i)), + published: Set(chrono::Utc::now() - std::time::Duration::from_secs(60*i as u64)), to: Set(Audience(vec![apb::target::PUBLIC.to_string()])), bto: Set(Audience::default()), cc: Set(Audience(vec![])), diff --git a/src/cli/fetch.rs b/src/cli/fetch.rs index 0f1c4f7..ef2230d 100644 --- a/src/cli/fetch.rs +++ b/src/cli/fetch.rs @@ -1,4 +1,4 @@ -use sea_orm::{EntityTrait, IntoActiveModel}; +use sea_orm::EntityTrait; use crate::server::fetcher::Fetchable; @@ -13,18 +13,18 @@ pub async fn fetch(ctx: crate::server::Context, uri: String, save: bool) -> crat if save { match obj.base_type() { Some(apb::BaseType::Object(apb::ObjectType::Actor(_))) => { - crate::model::user::Entity::insert( - crate::model::user::Model::new(obj).unwrap().into_active_model() + crate::model::actor::Entity::insert( + crate::model::actor::ActiveModel::new(obj).unwrap() ).exec(ctx.db()).await.unwrap(); }, Some(apb::BaseType::Object(apb::ObjectType::Activity(_))) => { crate::model::activity::Entity::insert( - crate::model::activity::Model::new(obj).unwrap().into_active_model() + crate::model::activity::ActiveModel::new(obj).unwrap() ).exec(ctx.db()).await.unwrap(); }, Some(apb::BaseType::Object(apb::ObjectType::Note)) => { crate::model::object::Entity::insert( - crate::model::object::Model::new(obj).unwrap().into_active_model() + crate::model::object::ActiveModel::new(obj).unwrap() ).exec(ctx.db()).await.unwrap(); }, Some(apb::BaseType::Object(t)) => tracing::warn!("not implemented: {:?}", t), diff --git a/src/cli/fix.rs b/src/cli/fix.rs index 9ad85d8..a7d7a1a 100644 --- a/src/cli/fix.rs +++ b/src/cli/fix.rs @@ -11,13 +11,13 @@ pub async fn fix(ctx: crate::server::Context, likes: bool, shares: bool, replies { let mut stream = crate::model::like::Entity::find().stream(db).await?; while let Some(like) = stream.try_next().await? { - store.insert(like.likes.clone(), store.get(&like.likes).unwrap_or(&0) + 1); + store.insert(like.object, store.get(&like.object).unwrap_or(&0) + 1); } } for (k, v) in store { let m = crate::model::object::ActiveModel { - id: sea_orm::Set(k.clone()), + internal: sea_orm::Set(k), likes: sea_orm::Set(v), ..Default::default() }; @@ -34,16 +34,16 @@ pub async fn fix(ctx: crate::server::Context, likes: bool, shares: bool, replies tracing::info!("fixing shares..."); let mut store = std::collections::HashMap::new(); { - let mut stream = crate::model::share::Entity::find().stream(db).await?; + let mut stream = crate::model::announce::Entity::find().stream(db).await?; while let Some(share) = stream.try_next().await? { - store.insert(share.shares.clone(), store.get(&share.shares).unwrap_or(&0) + 1); + store.insert(share.object.clone(), store.get(&share.object).unwrap_or(&0) + 1); } } for (k, v) in store { let m = crate::model::object::ActiveModel { - id: sea_orm::Set(k.clone()), - shares: sea_orm::Set(v), + internal: sea_orm::Set(k), + announces: sea_orm::Set(v), ..Default::default() }; if let Err(e) = crate::model::object::Entity::update(m) @@ -71,7 +71,7 @@ pub async fn fix(ctx: crate::server::Context, likes: bool, shares: bool, replies for (k, v) in store { let m = crate::model::object::ActiveModel { id: sea_orm::Set(k.clone()), - comments: sea_orm::Set(v), + replies: sea_orm::Set(v), ..Default::default() }; if let Err(e) = crate::model::object::Entity::update(m) diff --git a/src/cli/mod.rs b/src/cli/mod.rs index 293646e..bcf8eea 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -104,7 +104,7 @@ pub async fn run( ).await?; match command { CliCommand::Faker { count } => - Ok(faker(ctx, count).await?), + Ok(faker(ctx, count as i64).await?), CliCommand::Fetch { uri, save } => Ok(fetch(ctx, uri, save).await?), CliCommand::Relay { actor, accept } => diff --git a/src/cli/relay.rs b/src/cli/relay.rs index 850a84f..4203499 100644 --- a/src/cli/relay.rs +++ b/src/cli/relay.rs @@ -1,19 +1,20 @@ -use sea_orm::{ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter, QueryOrder}; +use sea_orm::{ActiveValue::{Set, NotSet}, ColumnTrait, EntityTrait, QueryFilter, QueryOrder}; pub async fn relay(ctx: crate::server::Context, actor: String, accept: bool) -> crate::Result<()> { let aid = ctx.aid(&uuid::Uuid::new_v4().to_string()); - let mut activity_model = crate::model::activity::Model { - id: aid.clone(), - activity_type: apb::ActivityType::Follow, - actor: ctx.base().to_string(), - object: Some(actor.clone()), - target: None, - published: chrono::Utc::now(), - to: crate::model::Audience(vec![actor.clone()]), - bto: crate::model::Audience::default(), - cc: crate::model::Audience(vec![apb::target::PUBLIC.to_string()]), - bcc: crate::model::Audience::default(), + let mut activity_model = crate::model::activity::ActiveModel { + internal: NotSet, + id: Set(aid.clone()), + activity_type: Set(apb::ActivityType::Follow), + actor: Set(ctx.base().to_string()), + object: Set(Some(actor.clone())), + target: Set(None), + published: Set(chrono::Utc::now()), + to: Set(crate::model::Audience(vec![actor.clone()])), + bto: Set(crate::model::Audience::default()), + cc: Set(crate::model::Audience(vec![apb::target::PUBLIC.to_string()])), + bcc: Set(crate::model::Audience::default()), }; if accept { @@ -25,11 +26,11 @@ pub async fn relay(ctx: crate::server::Context, actor: String, accept: bool) -> .one(ctx.db()) .await? .expect("no follow request to accept"); - activity_model.activity_type = apb::ActivityType::Accept(apb::AcceptType::Accept); - activity_model.object = Some(follow_req.id); + activity_model.activity_type = Set(apb::ActivityType::Accept(apb::AcceptType::Accept)); + activity_model.object = Set(Some(follow_req.id)); }; - crate::model::activity::Entity::insert(activity_model.into_active_model()) + crate::model::activity::Entity::insert(activity_model) .exec(ctx.db()).await?; ctx.dispatch(ctx.base(), vec![actor, apb::target::PUBLIC.to_string()], &aid, None).await?; diff --git a/src/cli/update.rs b/src/cli/update.rs index d5318ce..f43c9b2 100644 --- a/src/cli/update.rs +++ b/src/cli/update.rs @@ -1,5 +1,5 @@ use futures::TryStreamExt; -use sea_orm::{ColumnTrait, EntityTrait, IntoActiveModel, QueryFilter}; +use sea_orm::{ColumnTrait, EntityTrait, QueryFilter}; use crate::server::fetcher::Fetcher; @@ -8,8 +8,8 @@ pub async fn update_users(ctx: crate::server::Context, days: i64) -> crate::Resu let mut insertions = Vec::new(); { - let mut stream = crate::model::user::Entity::find() - .filter(crate::model::user::Column::Updated.lt(chrono::Utc::now() - chrono::Duration::days(days))) + let mut stream = crate::model::actor::Entity::find() + .filter(crate::model::actor::Column::Updated.lt(chrono::Utc::now() - chrono::Duration::days(days))) .stream(ctx.db()) .await?; @@ -18,18 +18,21 @@ pub async fn update_users(ctx: crate::server::Context, days: i64) -> crate::Resu if ctx.is_local(&user.id) { continue } match ctx.pull_user(&user.id).await { Err(e) => tracing::warn!("could not update user {}: {e}", user.id), - Ok(u) => { - insertions.push(u); - count += 1; + Ok(doc) => match crate::model::actor::ActiveModel::new(&doc) { + Ok(u) => { + insertions.push((user.id, u)); + count += 1; + }, + Err(e) => tracing::warn!("failed deserializing user '{}': {e}", user.id), }, } } } - for u in insertions { - tracing::info!("updating user {}", u.id); - crate::model::user::Entity::delete_by_id(&u.id).exec(ctx.db()).await?; - crate::model::user::Entity::insert(u.into_active_model()).exec(ctx.db()).await?; + for (uid, user_model) in insertions { + tracing::info!("updating user {}", uid); + crate::model::actor::Entity::delete_by_ap_id(&uid).exec(ctx.db()).await?; + crate::model::actor::Entity::insert(user_model).exec(ctx.db()).await?; } tracing::info!("updated {count} users"); diff --git a/src/model/actor.rs b/src/model/actor.rs index 6a8086f..59a1732 100644 --- a/src/model/actor.rs +++ b/src/model/actor.rs @@ -138,6 +138,10 @@ impl Entity { Entity::find().filter(Column::Id.eq(id)) } + pub fn delete_by_ap_id(id: &str) -> sea_orm::DeleteMany { + Entity::delete_many().filter(Column::Id.eq(id)) + } + pub async fn ap_to_internal(id: &str, db: &DatabaseConnection) -> crate::Result { Entity::find() .filter(Column::Id.eq(id))