diff --git a/Cargo.lock b/Cargo.lock index c213cdc..dee9f1c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5,7 +5,7 @@ version = 3 [[package]] name = "activitypub_federation" version = "0.5.0-beta.5" -source = "git+https://github.com/LemmyNet/activitypub-federation-rust.git?branch=parse-impl#2aa64ad1de7943840677f4b96a20a11d38e2be56" +source = "git+https://github.com/LemmyNet/activitypub-federation-rust.git?branch=diesel-feature#ca42d891b10888c0dcc666140385d380c664a978" dependencies = [ "activitystreams-kinds", "async-trait", @@ -14,6 +14,7 @@ dependencies = [ "bytes", "chrono", "derive_builder", + "diesel", "dyn-clone", "enum_delegate", "futures", diff --git a/Cargo.toml b/Cargo.toml index 3b37342..53fff7c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,7 +4,7 @@ version = "0.1.0" edition = "2021" [dependencies] -activitypub_federation = { git = "https://github.com/LemmyNet/activitypub-federation-rust.git", branch = "parse-impl", features = ["axum"], default-features = false } +activitypub_federation = { git = "https://github.com/LemmyNet/activitypub-federation-rust.git", branch = "diesel-feature", features = ["axum", "diesel"], default-features = false } anyhow = "1.0.75" async-trait = "0.1.74" axum = "0.6.20" diff --git a/src/api.rs b/src/api.rs index 40f695e..96bd76d 100644 --- a/src/api.rs +++ b/src/api.rs @@ -1,5 +1,4 @@ use crate::database::article::{DbArticle, DbArticleForm}; -use crate::database::dburl::DbUrl; use crate::database::edit::{DbEdit, EditVersion}; use crate::database::{DbConflict, MyDataHandle}; use crate::error::MyResult; @@ -56,11 +55,11 @@ async fn create_article( } } - let instance_id: DbUrl = data.local_instance().ap_id.into(); - let ap_id = Url::parse(&format!( + let instance_id = data.local_instance().ap_id; + let ap_id = ObjectId::parse(&format!( "http://{}:{}/article/{}", - instance_id.domain().unwrap(), - instance_id.port().unwrap(), + instance_id.inner().domain().unwrap(), + instance_id.inner().port().unwrap(), create_article.title ))? .into(); @@ -287,11 +286,11 @@ async fn fork_article( .clone() }; - let instance_id: DbUrl = data.local_instance().ap_id.into(); - let ap_id = Url::parse(&format!( + let instance_id = data.local_instance().ap_id; + let ap_id = ObjectId::parse(&format!( "http://{}:{}/article/{}", - instance_id.domain().unwrap(), - instance_id.port().unwrap(), + instance_id.inner().domain().unwrap(), + instance_id.inner().port().unwrap(), original_article.title ))? .into(); diff --git a/src/database/article.rs b/src/database/article.rs index 8d82754..b7e6bb4 100644 --- a/src/database/article.rs +++ b/src/database/article.rs @@ -1,9 +1,10 @@ -use crate::database::dburl::DbUrl; use crate::database::edit::EditVersion; use crate::database::schema::article; use crate::error::MyResult; use crate::federation::objects::edits_collection::DbEditCollection; +use crate::federation::objects::instance::DbInstance; use activitypub_federation::fetch::collection_id::CollectionId; +use activitypub_federation::fetch::object_id::ObjectId; use diesel::pg::PgConnection; use diesel::ExpressionMethods; use diesel::{ @@ -20,8 +21,8 @@ pub struct DbArticle { pub id: i32, pub title: String, pub text: String, - pub ap_id: DbUrl, - pub instance_id: DbUrl, + pub ap_id: ObjectId, + pub instance_id: ObjectId, /// List of all edits which make up this article, oldest first. // TODO //pub edits: Vec, @@ -34,9 +35,9 @@ pub struct DbArticle { pub struct DbArticleForm { pub title: String, pub text: String, - pub ap_id: DbUrl, + pub ap_id: ObjectId, // TODO: change to foreign key - pub instance_id: DbUrl, + pub instance_id: ObjectId, // TODO: instead of this we can use latest entry in edits table pub latest_version: String, pub local: bool, @@ -47,32 +48,35 @@ impl DbArticle { Ok(CollectionId::parse(&format!("{}/edits", self.ap_id))?) } - pub fn create(form: &DbArticleForm, conn: &Mutex) -> MyResult { - let mut conn = conn.lock().unwrap().deref_mut(); + pub fn create(form: &DbArticleForm, conn: &Mutex) -> MyResult { + let mut conn = conn.lock().unwrap(); Ok(insert_into(article::table) .values(form) .on_conflict(article::dsl::ap_id) .do_update() .set(form) - .get_result(conn)?) + .get_result(conn.deref_mut())?) } pub fn update_text(id: i32, text: &str, conn: &Mutex) -> MyResult { let mut conn = conn.lock().unwrap(); Ok(diesel::update(article::dsl::article.find(id)) .set(article::dsl::text.eq(text)) - .get_result::(&mut conn)?) + .get_result::(conn.deref_mut())?) } pub fn read(id: i32, conn: &Mutex) -> MyResult { let mut conn = conn.lock().unwrap(); - Ok(article::table.find(id).get_result(&mut conn)?) + Ok(article::table.find(id).get_result(conn.deref_mut())?) } - pub fn read_from_ap_id(ap_id: &DbUrl, conn: &Mutex) -> MyResult { + pub fn read_from_ap_id( + ap_id: &ObjectId, + conn: &Mutex, + ) -> MyResult { let mut conn = conn.lock().unwrap(); Ok(article::table .filter(article::dsl::ap_id.eq(ap_id)) - .get_result(&mut conn)?) + .get_result(conn.deref_mut())?) } } diff --git a/src/database/dburl.rs b/src/database/dburl.rs deleted file mode 100644 index 0931038..0000000 --- a/src/database/dburl.rs +++ /dev/null @@ -1,96 +0,0 @@ -use activitypub_federation::fetch::collection_id::CollectionId; -use activitypub_federation::fetch::object_id::ObjectId; -use activitypub_federation::traits::{Collection, Object}; -use diesel::backend::Backend; -use diesel::deserialize::FromSql; -use diesel::pg::Pg; -use diesel::{AsExpression, FromSqlRow}; -use serde::{Deserialize, Serialize}; -use std::fmt::{Display, Formatter}; -use std::ops::Deref; -use url::Url; - -/// Copied from lemmy, could be moved into common library -#[repr(transparent)] -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Debug, Hash, AsExpression, FromSqlRow)] -#[diesel(sql_type = diesel::sql_types::Text)] -pub struct DbUrl(pub(crate) Box); - -// TODO: Lemmy doesnt need this, but for some reason derive fails to generate it -impl FromSql for DbUrl { - fn from_sql(bytes: ::RawValue<'_>) -> diesel::deserialize::Result { - todo!() - } -} - -impl Display for DbUrl { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - self.clone().0.fmt(f) - } -} - -// the project doesnt compile with From -#[allow(clippy::from_over_into)] -impl Into for Url { - fn into(self) -> DbUrl { - DbUrl(Box::new(self)) - } -} -#[allow(clippy::from_over_into)] -impl Into for DbUrl { - fn into(self) -> Url { - *self.0 - } -} - -impl From for ObjectId -where - T: Object + Send + 'static, - for<'de2> ::Kind: Deserialize<'de2>, -{ - fn from(value: DbUrl) -> Self { - let url: Url = value.into(); - ObjectId::from(url) - } -} - -impl From for CollectionId -where - T: Collection + Send + 'static, - for<'de2> ::Kind: Deserialize<'de2>, -{ - fn from(value: DbUrl) -> Self { - let url: Url = value.into(); - CollectionId::from(url) - } -} - -impl From> for DbUrl -where - T: Collection, - for<'de2> ::Kind: Deserialize<'de2>, -{ - fn from(value: CollectionId) -> Self { - let url: Url = value.into(); - url.into() - } -} - -impl From> for DbUrl -where - T: Object, - for<'de2> ::Kind: Deserialize<'de2>, -{ - fn from(value: ObjectId) -> Self { - let url: Url = value.into(); - url.into() - } -} - -impl Deref for DbUrl { - type Target = Url; - - fn deref(&self) -> &Self::Target { - &self.0 - } -} diff --git a/src/database/edit.rs b/src/database/edit.rs index bc94ad6..949049a 100644 --- a/src/database/edit.rs +++ b/src/database/edit.rs @@ -1,5 +1,4 @@ use crate::database::article::DbArticle; -use crate::database::dburl::DbUrl; use crate::database::schema::edit; use crate::error::MyResult; use activitypub_federation::fetch::object_id::ObjectId; @@ -12,14 +11,16 @@ use diesel_derive_newtype::DieselNewType; use diffy::create_patch; use serde::{Deserialize, Serialize}; use sha2::{Digest, Sha224}; +use std::ops::DerefMut; use std::sync::Mutex; +use url::Url; /// Represents a single change to the article. #[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Queryable, Selectable, Identifiable)] #[diesel(table_name = edit, check_for_backend(diesel::pg::Pg))] pub struct DbEdit { pub id: i32, - pub ap_id: DbUrl, + pub ap_id: ObjectId, pub diff: String, pub article_id: i32, pub version: EditVersion, @@ -30,7 +31,7 @@ pub struct DbEdit { #[derive(Debug, Clone, Insertable, AsChangeset)] #[diesel(table_name = edit, check_for_backend(diesel::pg::Pg))] pub struct DbEditForm { - pub ap_id: DbUrl, + pub ap_id: ObjectId, pub diff: String, pub article_id: i32, pub version: EditVersion, @@ -43,11 +44,11 @@ impl DbEditForm { let mut sha224 = Sha224::new(); sha224.update(diff.to_bytes()); let hash = format!("{:X}", sha224.finalize()); - let edit_id = ObjectId::parse(&format!("{}/{}", original_article.ap_id, hash))?; + let edit_id = Url::parse(&format!("{}/{}", original_article.ap_id, hash))?; Ok(DbEditForm { ap_id: edit_id.into(), diff: diff.to_string(), - article_id: original_article.ap_id.clone(), + article_id: original_article.id, version: EditVersion(hash), local: true, }) @@ -62,7 +63,7 @@ impl DbEdit { .on_conflict(edit::dsl::ap_id) .do_update() .set(form) - .get_result(&mut conn)?) + .get_result(conn.deref_mut())?) } pub fn for_article(id: i32, conn: &Mutex) -> MyResult> { @@ -70,7 +71,7 @@ impl DbEdit { Ok(edit::table .filter(edit::dsl::id.eq(id)) .order_by(edit::dsl::id.asc()) - .get_results(&mut conn)?) + .get_results(conn.deref_mut())?) } } diff --git a/src/database/mod.rs b/src/database/mod.rs index 4001edc..b486949 100644 --- a/src/database/mod.rs +++ b/src/database/mod.rs @@ -7,7 +7,7 @@ use crate::federation::objects::instance::DbInstance; use crate::utils::generate_article_version; use activitypub_federation::config::Data; use activitypub_federation::fetch::object_id::ObjectId; -use diesel::{Identifiable, PgConnection, QueryDsl}; +use diesel::PgConnection; use diffy::{apply, merge, Patch}; use edit::EditVersion; use std::collections::HashMap; @@ -16,7 +16,6 @@ use std::sync::{Arc, Mutex}; use url::Url; pub mod article; -pub mod dburl; pub mod edit; mod schema; @@ -62,11 +61,8 @@ impl DbConflict { &self, data: &Data, ) -> MyResult> { - let original_article = { - let mut lock = data.articles.lock().unwrap(); - let article = lock.get_mut(self.article_id.inner()).unwrap(); - article.clone() - }; + let original_article = + DbArticle::read_from_ap_id(&self.article_id.clone().into(), &data.db_connection)?; // create common ancestor version let edits = DbEdit::for_article(original_article.id, &data.db_connection)?; diff --git a/src/federation/activities/mod.rs b/src/federation/activities/mod.rs index ca86d97..24231e4 100644 --- a/src/federation/activities/mod.rs +++ b/src/federation/activities/mod.rs @@ -25,7 +25,7 @@ pub async fn submit_article_update( if original_article.local { let updated_article = { let mut lock = data.articles.lock().unwrap(); - let article = lock.get_mut(&original_article.ap_id).unwrap(); + let article = lock.get_mut(original_article.ap_id.inner()).unwrap(); article.text = new_text; article.latest_version = edit.version.clone(); article.clone() diff --git a/src/federation/activities/update_remote_article.rs b/src/federation/activities/update_remote_article.rs index 0481501..5c4703a 100644 --- a/src/federation/activities/update_remote_article.rs +++ b/src/federation/activities/update_remote_article.rs @@ -84,7 +84,7 @@ impl ActivityHandler for UpdateRemoteArticle { Ok(applied) => { let edit = DbEdit::from_json(self.object.clone(), data).await?; let article = - DbArticle::update_text(edit.article_id, &applied, &mut data.db_connection)?; + DbArticle::update_text(edit.article_id, &applied, &data.db_connection)?; UpdateLocalArticle::send(article, vec![self.actor.dereference(data).await?], data) .await?; } diff --git a/src/federation/objects/article.rs b/src/federation/objects/article.rs index 533d2ad..e248ecd 100644 --- a/src/federation/objects/article.rs +++ b/src/federation/objects/article.rs @@ -40,18 +40,18 @@ impl Object for DbArticle { object_id: Url, data: &Data, ) -> Result, Self::Error> { - let article = DbArticle::read_from_ap_id(&object_id.into(), &mut data.db_connection).ok(); + let article = DbArticle::read_from_ap_id(&object_id.into(), &data.db_connection).ok(); Ok(article) } async fn into_json(self, data: &Data) -> Result { - let instance: DbInstance = ObjectId::from(self.instance_id) + let instance: DbInstance = ObjectId::from(self.instance_id.clone()) .dereference_local(data) .await?; Ok(ApubArticle { kind: Default::default(), id: self.ap_id.clone().into(), - attributed_to: self.instance_id.clone().into(), + attributed_to: instance.ap_id.clone().into(), to: vec![public(), instance.followers_url()?], edits: self.edits_id()?, latest_version: self.latest_version, @@ -78,7 +78,7 @@ impl Object for DbArticle { local: false, instance_id: json.attributed_to.into(), }; - let mut article = DbArticle::create(&form, &data.db_connection)?; + let article = DbArticle::create(&form, &data.db_connection)?; { let mut lock = data.articles.lock().unwrap(); diff --git a/src/federation/objects/edit.rs b/src/federation/objects/edit.rs index c26ee90..8ee4aa7 100644 --- a/src/federation/objects/edit.rs +++ b/src/federation/objects/edit.rs @@ -39,7 +39,7 @@ impl Object for DbEdit { } async fn into_json(self, data: &Data) -> Result { - let article = DbArticle::read(self.article_id, &mut data.db_connection)?; + let article = DbArticle::read(self.article_id, &data.db_connection)?; Ok(ApubEdit { kind: EditType::Edit, id: self.ap_id.into(), @@ -68,7 +68,7 @@ impl Object for DbEdit { version: json.version, local: false, }; - let edit = DbEdit::create(&form, &mut data.db_connection)?; + let edit = DbEdit::create(&form, &data.db_connection)?; Ok(edit) } } diff --git a/src/federation/objects/edits_collection.rs b/src/federation/objects/edits_collection.rs index f879f3d..b1cb9a5 100644 --- a/src/federation/objects/edits_collection.rs +++ b/src/federation/objects/edits_collection.rs @@ -37,7 +37,7 @@ impl Collection for DbEditCollection { owner: &Self::Owner, data: &Data, ) -> Result { - let edits = DbEditCollection(DbEdit::for_article(owner.id, &mut data.db_connection)?); + let edits = DbEditCollection(DbEdit::for_article(owner.id, &data.db_connection)?); let edits = future::try_join_all( edits