diff --git a/plume-common/src/activity_pub/inbox.rs b/plume-common/src/activity_pub/inbox.rs index ec63d4fb..513603d2 100644 --- a/plume-common/src/activity_pub/inbox.rs +++ b/plume-common/src/activity_pub/inbox.rs @@ -86,7 +86,7 @@ where /// - the context to be passed to each handler. /// - the activity /// - the reason it has not been handled yet - NotHandled(&'a C, serde_json::Value, InboxError), + NotHandled(&'a mut C, serde_json::Value, InboxError), /// A matching handler have been found but failed /// @@ -139,16 +139,16 @@ where /// /// - `ctx`: the context to pass to each handler /// - `json`: the JSON representation of the incoming activity - pub fn handle(ctx: &'a C, json: serde_json::Value) -> Inbox<'a, C, E, R> { + pub fn handle(ctx: &'a mut C, json: serde_json::Value) -> Inbox<'a, C, E, R> { Inbox::NotHandled(ctx, json, InboxError::NoMatch) } /// Registers an handler on this Inbox. pub fn with(self) -> Inbox<'a, C, E, R> where - A: AsActor<&'a C> + FromId, + A: AsActor<&'a mut C> + FromId, V: activitypub::Activity, - M: AsObject + FromId, + M: AsObject + FromId, M::Output: Into, { if let Inbox::NotHandled(ctx, mut act, e) = self { @@ -264,7 +264,7 @@ pub trait FromId: Sized { /// - `object`: optional object that will be used if the object was not found in the database /// If absent, the ID will be dereferenced. fn from_id( - ctx: &C, + ctx: &mut C, id: &str, object: Option, ) -> Result, Self::Error)> { @@ -308,10 +308,10 @@ pub trait FromId: Sized { } /// Builds a `Self` from its ActivityPub representation - fn from_activity(ctx: &C, activity: Self::Object) -> Result; + fn from_activity(ctx: &mut C, activity: Self::Object) -> Result; /// Tries to find a `Self` with a given ID (`id`), using `ctx` (a database) - fn from_db(ctx: &C, id: &str) -> Result; + fn from_db(ctx: &mut C, id: &str) -> Result; } /// Should be implemented by anything representing an ActivityPub actor. diff --git a/plume-models/src/blogs.rs b/plume-models/src/blogs.rs index 2999e31c..db262005 100644 --- a/plume-models/src/blogs.rs +++ b/plume-models/src/blogs.rs @@ -132,7 +132,7 @@ impl Blog { .map_err(Error::from) } - pub async fn find_by_fqn(c: &PlumeRocket, fqn: &str) -> Result { + pub async fn find_by_fqn(c: &mut PlumeRocket, fqn: &str) -> Result { let from_db = blogs::table .filter(blogs::fqn.eq(fqn)) .first(&*c.conn) @@ -144,7 +144,7 @@ impl Blog { } } - async fn fetch_from_webfinger(c: &PlumeRocket, acct: &str) -> Result { + async fn fetch_from_webfinger(c: &mut PlumeRocket, acct: &str) -> Result { resolve_with_prefix(Prefix::Group, acct.to_owned(), true) .await? .links @@ -340,11 +340,11 @@ impl FromId for Blog { type Error = Error; type Object = CustomGroup; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Self::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, acct: CustomGroup) -> Result { + fn from_activity(c: &mut PlumeRocket, acct: CustomGroup) -> Result { let url = Url::parse(&acct.object.object_props.id_string()?)?; let inst = url.host_str()?; let instance = Instance::find_by_domain(&c.conn, inst).or_else(|_| { @@ -436,7 +436,7 @@ impl FromId for Blog { } } -impl AsActor<&PlumeRocket> for Blog { +impl AsActor<&mut PlumeRocket> for Blog { fn get_inbox_url(&self) -> String { self.inbox_url.clone() } diff --git a/plume-models/src/comments.rs b/plume-models/src/comments.rs index 7bfc2ff3..03a01b2f 100644 --- a/plume-models/src/comments.rs +++ b/plume-models/src/comments.rs @@ -105,7 +105,7 @@ impl Comment { .unwrap_or(false) } - pub async fn to_activity(&self, c: &PlumeRocket) -> Result { + pub async fn to_activity(&self, c: &mut PlumeRocket) -> Result { let author = User::get(&c.conn, self.author_id)?; let (html, mentions, _hashtags) = utils::md_to_html( self.content.get().as_ref(), @@ -140,7 +140,7 @@ impl Comment { Ok(note) } - pub async fn create_activity(&self, c: &PlumeRocket) -> Result { + pub async fn create_activity(&self, c: &mut PlumeRocket) -> Result { let author = User::get(&c.conn, self.author_id)?; let note = self.to_activity(c).await?; @@ -198,11 +198,11 @@ impl FromId for Comment { type Error = Error; type Object = Note; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Self::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, note: Note) -> Result { + fn from_activity(c: &mut PlumeRocket, note: Note) -> Result { let conn = &*c.conn; let comm = { let previous_url = note.object_props.in_reply_to.as_ref()?.as_str()?; @@ -322,21 +322,21 @@ impl FromId for Comment { } } -impl AsObject for Comment { +impl AsObject for Comment { type Error = Error; type Output = Self; - fn activity(self, _c: &PlumeRocket, _actor: User, _id: &str) -> Result { + fn activity(self, _c: &mut PlumeRocket, _actor: User, _id: &str) -> Result { // The actual creation takes place in the FromId impl Ok(self) } } -impl AsObject for Comment { +impl AsObject for Comment { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { if self.author_id != actor.id { return Err(Error::Unauthorized); } diff --git a/plume-models/src/follows.rs b/plume-models/src/follows.rs index d371e04e..28c3ffa8 100644 --- a/plume-models/src/follows.rs +++ b/plume-models/src/follows.rs @@ -136,11 +136,11 @@ impl Follow { } } -impl AsObject for User { +impl AsObject for User { type Error = Error; type Output = Follow; - fn activity(self, c: &PlumeRocket, actor: User, id: &str) -> Result { + fn activity(self, c: &mut PlumeRocket, actor: User, id: &str) -> Result { // Mastodon (at least) requires the full Follow object when accepting it, // so we rebuilt it here let mut follow = FollowAct::default(); @@ -156,11 +156,11 @@ impl FromId for Follow { type Error = Error; type Object = FollowAct; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Follow::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, follow: FollowAct) -> Result { + fn from_activity(c: &mut PlumeRocket, follow: FollowAct) -> Result { let actor = User::from_id(c, &follow.follow_props.actor_link::()?, None).map_err(|(_, e)| e)?; @@ -170,11 +170,11 @@ impl FromId for Follow { } } -impl AsObject for Follow { +impl AsObject for Follow { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { let conn = &*c.conn; if self.follower_id == actor.id { diesel::delete(&self).execute(conn)?; diff --git a/plume-models/src/inbox.rs b/plume-models/src/inbox.rs index 9229f0a4..ca2a4733 100644 --- a/plume-models/src/inbox.rs +++ b/plume-models/src/inbox.rs @@ -45,7 +45,7 @@ impl_into_inbox_result! { Reshare => Reshared } -pub fn inbox(ctx: &PlumeRocket, act: serde_json::Value) -> Result { +pub fn inbox(ctx: &mut PlumeRocket, act: serde_json::Value) -> Result { Inbox::handle(ctx, act) .with::() .with::() @@ -72,7 +72,7 @@ pub(crate) mod tests { use diesel::Connection; pub fn fill_database( - rockets: &PlumeRocket, + rockets: &mut PlumeRocket, ) -> ( Vec, Vec, diff --git a/plume-models/src/likes.rs b/plume-models/src/likes.rs index bbb13596..d9d11cb7 100644 --- a/plume-models/src/likes.rs +++ b/plume-models/src/likes.rs @@ -83,11 +83,11 @@ impl Like { } } -impl AsObject for Post { +impl AsObject for Post { type Error = Error; type Output = Like; - fn activity(self, c: &PlumeRocket, actor: User, id: &str) -> Result { + fn activity(self, c: &mut PlumeRocket, actor: User, id: &str) -> Result { let res = Like::insert( &c.conn, NewLike { @@ -107,11 +107,11 @@ impl FromId for Like { type Error = Error; type Object = activity::Like; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Like::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, act: activity::Like) -> Result { + fn from_activity(c: &mut PlumeRocket, act: activity::Like) -> Result { let res = Like::insert( &c.conn, NewLike { @@ -129,11 +129,11 @@ impl FromId for Like { } } -impl AsObject for Like { +impl AsObject for Like { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { let conn = &*c.conn; if actor.id == self.user_id { diesel::delete(&self).execute(conn)?; diff --git a/plume-models/src/medias.rs b/plume-models/src/medias.rs index e0480f4d..38471ea9 100644 --- a/plume-models/src/medias.rs +++ b/plume-models/src/medias.rs @@ -197,8 +197,7 @@ impl Media { } // TODO: merge with save_remote? - pub async fn from_activity(c: &PlumeRocket, image: &Image) -> Result { - let conn = &*c.conn; + pub async fn from_activity(c: &mut PlumeRocket, image: &Image) -> Result { let remote_url = image.object_props.url_string().ok()?; let ext = remote_url .rsplit('.') @@ -215,8 +214,22 @@ impl Media { let contents = reqwest::get(remote_url.as_str()).await?.bytes().await?; dest.write_all(&contents).await?; + let owner_id = User::from_id( + c, + image + .object_props + .attributed_to_link_vec::() + .ok()? + .into_iter() + .next()? + .as_ref(), + None, + ) + .map_err(|(_, e)| e)? + .id; + Media::insert( - conn, + &mut c.conn, NewMedia { file_path: path.to_str()?.to_string(), alt_text: image.object_props.content_string().ok()?, @@ -224,19 +237,7 @@ impl Media { remote_url: None, sensitive: image.object_props.summary_string().is_ok(), content_warning: image.object_props.summary_string().ok(), - owner_id: User::from_id( - c, - image - .object_props - .attributed_to_link_vec::() - .ok()? - .into_iter() - .next()? - .as_ref(), - None, - ) - .map_err(|(_, e)| e)? - .id, + owner_id }, ) } diff --git a/plume-models/src/mentions.rs b/plume-models/src/mentions.rs index e65a16cb..cdb46f9e 100644 --- a/plume-models/src/mentions.rs +++ b/plume-models/src/mentions.rs @@ -52,7 +52,7 @@ impl Mention { } } - pub async fn build_activity(c: &PlumeRocket, ment: &str) -> Result { + pub async fn build_activity(c: &mut PlumeRocket, ment: &str) -> Result { let user = User::find_by_fqn(c, ment).await?; let mut mention = link::Mention::default(); mention.link_props.set_href_string(user.ap_url)?; diff --git a/plume-models/src/posts.rs b/plume-models/src/posts.rs index 3a580a4c..35b464dc 100644 --- a/plume-models/src/posts.rs +++ b/plume-models/src/posts.rs @@ -554,12 +554,11 @@ impl FromId for Post { type Error = Error; type Object = LicensedArticle; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Self::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, article: LicensedArticle) -> Result { - let conn = &*c.conn; + fn from_activity(c: &mut PlumeRocket, article: LicensedArticle) -> Result { let searcher = &c.searcher; let license = article.custom_props.license_string().unwrap_or_default(); let article = article.object; @@ -570,12 +569,12 @@ impl FromId for Post { .into_iter() .fold((None, vec![]), |(blog, mut authors), link| { let url = link; - match User::from_id(&c, &url, None) { + match User::from_id(&mut c, &url, None) { Ok(u) => { authors.push(u); (blog, authors) } - Err(_) => (blog.or_else(|| Blog::from_id(&c, &url, None).ok()), authors), + Err(_) => (blog.or_else(|| Blog::from_id(&mut c, &url, None).ok()), authors), } }); @@ -583,11 +582,11 @@ impl FromId for Post { let mut r = Runtime::new().unwrap(); let cover = - Some(r.block_on(async { Media::from_activity(&c, &image).await.ok().unwrap().id })); + Some(r.block_on(async { Media::from_activity(&mut c, &image).await.ok().unwrap().id })); let title = article.object_props.name_string()?; let post = Post::insert( - conn, + &mut c.conn, NewPost { blog_id: blog?.id, slug: title.to_kebab_case(), @@ -610,7 +609,7 @@ impl FromId for Post { for author in authors { PostAuthor::insert( - conn, + &mut c.conn, NewPostAuthor { post_id: post.id, author_id: author.id, @@ -627,7 +626,7 @@ impl FromId for Post { if let Some(serde_json::Value::Array(tags)) = article.object_props.tag { for tag in tags { serde_json::from_value::(tag.clone()) - .map(|m| Mention::from_activity(conn, &m, post.id, true, true)) + .map(|m| Mention::from_activity(&mut c.conn, &m, post.id, true, true)) .ok(); serde_json::from_value::(tag.clone()) @@ -635,7 +634,7 @@ impl FromId for Post { .and_then(|t| { let tag_name = t.name_string()?; Ok(Tag::from_activity( - conn, + &mut c.conn, &t, post.id, hashtags.remove(&tag_name), @@ -651,21 +650,21 @@ impl FromId for Post { } } -impl AsObject for Post { +impl AsObject for Post { type Error = Error; type Output = Post; - fn activity(self, _c: &PlumeRocket, _actor: User, _id: &str) -> Result { + fn activity(self, _c: &mut PlumeRocket, _actor: User, _id: &str) -> Result { // TODO: check that _actor is actually one of the author? Ok(self) } } -impl AsObject for Post { +impl AsObject for Post { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { let can_delete = self .get_authors(&c.conn)? .into_iter() @@ -693,12 +692,12 @@ impl FromId for PostUpdate { type Error = Error; type Object = LicensedArticle; - fn from_db(_: &PlumeRocket, _: &str) -> Result { + fn from_db(_: &mut PlumeRocket, _: &str) -> Result { // Always fail because we always want to deserialize the AP object Err(Error::NotFound) } - fn from_activity(c: &PlumeRocket, updated: LicensedArticle) -> Result { + fn from_activity(c: &mut PlumeRocket, updated: LicensedArticle) -> Result { let image = updated .object .object_props @@ -707,7 +706,7 @@ impl FromId for PostUpdate { .unwrap(); let mut r = Runtime::new().unwrap(); let cover = - Some(r.block_on(async { Media::from_activity(&c, &image).await.ok().unwrap().id })); + Some(r.block_on(async { Media::from_activity(&mut c, &image).await.ok().unwrap().id })); Ok(PostUpdate { ap_url: updated.object.object_props.id_string()?, @@ -727,11 +726,11 @@ impl FromId for PostUpdate { } } -impl AsObject for PostUpdate { +impl AsObject for PostUpdate { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { let conn = &*c.conn; let searcher = &c.searcher; let mut post = Post::from_id(c, &self.ap_url, None).map_err(|(_, e)| e)?; diff --git a/plume-models/src/reshares.rs b/plume-models/src/reshares.rs index 3621cc17..19e391f1 100644 --- a/plume-models/src/reshares.rs +++ b/plume-models/src/reshares.rs @@ -107,11 +107,11 @@ impl Reshare { } } -impl AsObject for Post { +impl AsObject for Post { type Error = Error; type Output = Reshare; - fn activity(self, c: &PlumeRocket, actor: User, id: &str) -> Result { + fn activity(self, c: &mut PlumeRocket, actor: User, id: &str) -> Result { let conn = &*c.conn; let reshare = Reshare::insert( conn, @@ -132,11 +132,11 @@ impl FromId for Reshare { type Error = Error; type Object = Announce; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Reshare::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, act: Announce) -> Result { + fn from_activity(c: &mut PlumeRocket, act: Announce) -> Result { let res = Reshare::insert( &c.conn, NewReshare { @@ -154,11 +154,11 @@ impl FromId for Reshare { } } -impl AsObject for Reshare { +impl AsObject for Reshare { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { let conn = &*c.conn; if actor.id == self.user_id { diesel::delete(&self).execute(conn)?; diff --git a/plume-models/src/timeline/mod.rs b/plume-models/src/timeline/mod.rs index 426c228b..aa0e8871 100644 --- a/plume-models/src/timeline/mod.rs +++ b/plume-models/src/timeline/mod.rs @@ -208,7 +208,7 @@ impl Timeline { .map_err(Error::from) } - pub fn add_to_all_timelines(rocket: &PlumeRocket, post: &Post, kind: Kind<'_>) -> Result<()> { + pub fn add_to_all_timelines(rocket: &mut PlumeRocket, post: &Post, kind: Kind<'_>) -> Result<()> { let timelines = timeline_definition::table .load::(rocket.conn.deref()) .map_err(Error::from)?; @@ -231,7 +231,7 @@ impl Timeline { Ok(()) } - pub fn matches(&self, rocket: &PlumeRocket, post: &Post, kind: Kind<'_>) -> Result { + pub fn matches(&self, rocket: &mut PlumeRocket, post: &Post, kind: Kind<'_>) -> Result { let query = TimelineQuery::parse(&self.query)?; query.matches(rocket, self, post, kind) } diff --git a/plume-models/src/timeline/query.rs b/plume-models/src/timeline/query.rs index c9a051c7..97161be3 100644 --- a/plume-models/src/timeline/query.rs +++ b/plume-models/src/timeline/query.rs @@ -162,7 +162,7 @@ enum TQ<'a> { impl<'a> TQ<'a> { fn matches( &self, - rocket: &PlumeRocket, + rocket: &mut PlumeRocket, timeline: &Timeline, post: &Post, kind: Kind<'_>, @@ -207,7 +207,7 @@ enum Arg<'a> { impl<'a> Arg<'a> { pub fn matches( &self, - rocket: &PlumeRocket, + rocket: &mut PlumeRocket, timeline: &Timeline, post: &Post, kind: Kind<'_>, @@ -232,7 +232,7 @@ enum WithList { impl WithList { pub fn matches( &self, - rocket: &PlumeRocket, + rocket: &mut PlumeRocket, timeline: &Timeline, post: &Post, list: &List<'_>, @@ -391,7 +391,7 @@ enum Bool { impl Bool { pub fn matches( &self, - rocket: &PlumeRocket, + rocket: &mut PlumeRocket, timeline: &Timeline, post: &Post, kind: Kind<'_>, @@ -662,7 +662,7 @@ impl<'a> TimelineQuery<'a> { pub fn matches( &self, - rocket: &PlumeRocket, + rocket: &mut PlumeRocket, timeline: &Timeline, post: &Post, kind: Kind<'_>, diff --git a/plume-models/src/users.rs b/plume-models/src/users.rs index 6135da86..fbcb6012 100644 --- a/plume-models/src/users.rs +++ b/plume-models/src/users.rs @@ -189,7 +189,7 @@ impl User { .map_err(Error::from) } - pub async fn find_by_fqn(c: &PlumeRocket, fqn: &str) -> Result { + pub async fn find_by_fqn(c: &mut PlumeRocket, fqn: &str) -> Result { let from_db = users::table .filter(users::fqn.eq(fqn)) .first(&*c.conn) @@ -201,7 +201,7 @@ impl User { } } - async fn fetch_from_webfinger(c: &PlumeRocket, acct: &str) -> Result { + async fn fetch_from_webfinger(c: &mut PlumeRocket, acct: &str) -> Result { let link = resolve(acct.to_owned(), true) .await? .links @@ -245,7 +245,7 @@ impl User { Ok(json) } - pub async fn fetch_from_url(c: &PlumeRocket, url: &str) -> Result { + pub async fn fetch_from_url(c: &mut PlumeRocket, url: &str) -> Result { let json = User::fetch(url).await?; User::from_activity(c, json) } @@ -821,11 +821,11 @@ impl FromId for User { type Error = Error; type Object = CustomPerson; - fn from_db(c: &PlumeRocket, id: &str) -> Result { + fn from_db(c: &mut PlumeRocket, id: &str) -> Result { Self::find_by_ap_url(&c.conn, id) } - fn from_activity(c: &PlumeRocket, acct: CustomPerson) -> Result { + fn from_activity(c: &mut PlumeRocket, acct: CustomPerson) -> Result { let url = Url::parse(&acct.object.object_props.id_string()?)?; let inst = url.host_str()?; let instance = Instance::find_by_domain(&c.conn, inst).or_else(|_| { @@ -917,7 +917,7 @@ impl FromId for User { } } -impl AsActor<&PlumeRocket> for User { +impl AsActor<&mut PlumeRocket> for User { fn get_inbox_url(&self) -> String { self.inbox_url.clone() } @@ -933,11 +933,11 @@ impl AsActor<&PlumeRocket> for User { } } -impl AsObject for User { +impl AsObject for User { type Error = Error; type Output = (); - fn activity(self, c: &PlumeRocket, actor: User, _id: &str) -> Result<()> { + fn activity(self, c: &mut PlumeRocket, actor: User, _id: &str) -> Result<()> { if self.id == actor.id { self.delete(&c.conn, &c.searcher).map(|_| ()) } else { diff --git a/src/api/mod.rs b/src/api/mod.rs index 6a3e8136..ffc6f2cf 100644 --- a/src/api/mod.rs +++ b/src/api/mod.rs @@ -68,13 +68,12 @@ pub async fn oauth( query: Form, rockets: PlumeRocket, ) -> Result, ApiError> { - let conn = &*rockets.conn; - let app = App::find_by_client_id(conn, &query.client_id)?; + let app = App::find_by_client_id(&rockets.conn, &query.client_id)?; if app.client_secret == query.client_secret { - if let Ok(user) = User::find_by_fqn(&rockets, &query.username).await { + if let Ok(user) = User::find_by_fqn(&mut rockets, &query.username).await { if user.auth(&query.password) { let token = ApiToken::insert( - conn, + &rockets.conn, NewApiToken { app_id: app.id, user_id: user.id, @@ -94,7 +93,7 @@ pub async fn oauth( // Making fake password verification to avoid different // response times that would make it possible to know // if a username is registered or not. - User::get(conn, 1)?.auth(&query.password); + User::get(&rockets.conn, 1)?.auth(&query.password); Ok(Json(json!({ "error": "Invalid credentials" })))