diff --git a/src/activity_pub/inbox.rs b/src/activity_pub/inbox.rs index cbd67f39..1d8fe0a6 100644 --- a/src/activity_pub/inbox.rs +++ b/src/activity_pub/inbox.rs @@ -1,5 +1,5 @@ use activitypub::{ - Activity, Object, + Object, activity::{Create, Like, Undo} }; use diesel::PgConnection; @@ -40,7 +40,7 @@ pub trait FromActivity: Sized { } } -pub trait Notify { +pub trait Notify { fn notify(conn: &PgConnection, act: T, actor: Id); } diff --git a/src/models/comments.rs b/src/models/comments.rs index be66f878..ed15465d 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -9,11 +9,12 @@ use serde_json; use activity_pub::{ ap_url, Id, IntoId, PUBLIC_VISIBILTY, actor::Actor, - inbox::FromActivity, + inbox::{FromActivity, Notify}, object::Object }; use models::{ instance::Instance, + notifications::*, posts::Post, users::User }; @@ -128,7 +129,7 @@ impl FromActivity for Comment { fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> Comment { let previous_url = note.object_props.in_reply_to.clone().unwrap().as_str().unwrap().to_string(); let previous_comment = Comment::find_by_ap_url(conn, previous_url.clone()); - Comment::insert(conn, NewComment { + let comm = Comment::insert(conn, NewComment { content: SafeString::new(¬e.object_props.content_string().unwrap()), spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), ap_url: note.object_props.id_string().ok(), @@ -136,9 +137,30 @@ impl FromActivity for Comment { post_id: previous_comment .map(|c| c.post_id) .unwrap_or_else(|| Post::find_by_ap_url(conn, previous_url).unwrap().id), - author_id: User::from_url(conn, actor.into()).unwrap().id, + author_id: User::from_url(conn, actor.clone().into()).unwrap().id, sensitive: false // "sensitive" is not a standard property, we need to think about how to support it with the activitypub crate - }) + }); + Comment::notify(conn, note, actor); + comm + } +} + +impl Notify for Comment { + fn notify(conn: &PgConnection, note: Note, _actor: Id) { + match Comment::find_by_ap_url(conn, note.object_props.id_string().unwrap()) { + Some(comment) => { + for author in comment.clone().get_post(conn).get_authors(conn) { + let comment = comment.clone(); + Notification::insert(conn, NewNotification { + title: format!("{} commented your article", comment.get_author(conn).display_name.clone()), + content: Some(comment.get_post(conn).title), + link: comment.ap_url, + user_id: author.id + }); + } + }, + None => println!("Couldn't find comment by AP id, to create a new notification") + }; } } diff --git a/src/models/follows.rs b/src/models/follows.rs index fa5f66fc..66005ed7 100644 --- a/src/models/follows.rs +++ b/src/models/follows.rs @@ -1,9 +1,12 @@ use activitypub::{Actor, activity::{Accept, Follow as FollowAct}}; use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl}; -use activity_pub::{broadcast, Id, IntoId, actor::Actor as ApActor, inbox::{FromActivity, WithInbox}, sign::Signer}; -use models::blogs::Blog; -use models::users::User; +use activity_pub::{broadcast, Id, IntoId, actor::Actor as ApActor, inbox::{FromActivity, Notify, WithInbox}, sign::Signer}; +use models::{ + blogs::Blog, + notifications::*, + users::User +}; use schema::follows; #[derive(Queryable, Identifiable, Associations)] @@ -70,3 +73,15 @@ impl FromActivity for Follow { } } } + +impl Notify for Follow { + fn notify(conn: &PgConnection, follow: FollowAct, actor: Id) { + let follower = User::from_url(conn, actor.into()).unwrap(); + Notification::insert(conn, NewNotification { + title: format!("{} started following you", follower.display_name.clone()), + content: None, + link: Some(follower.ap_url), + user_id: User::from_url(conn, follow.follow_props.object_link::().unwrap().into()).unwrap().id + }); + } +} diff --git a/src/models/likes.rs b/src/models/likes.rs index 59bd48bc..6c8bb929 100644 --- a/src/models/likes.rs +++ b/src/models/likes.rs @@ -7,10 +7,11 @@ use activity_pub::{ Id, IntoId, actor::Actor, - inbox::{FromActivity, Deletable}, + inbox::{FromActivity, Deletable, Notify}, object::Object }; use models::{ + notifications::*, posts::Post, users::User }; @@ -97,14 +98,32 @@ impl Like { } impl FromActivity for Like { - fn from_activity(conn: &PgConnection, like: activity::Like, _actor: Id) -> Like { + fn from_activity(conn: &PgConnection, like: activity::Like, actor: Id) -> Like { let liker = User::from_url(conn, like.like_props.actor.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, like.like_props.object.as_str().unwrap().to_string()); - Like::insert(conn, NewLike { + let res = Like::insert(conn, NewLike { post_id: post.unwrap().id, user_id: liker.unwrap().id, ap_url: like.object_props.id_string().unwrap_or(String::from("")) - }) + }); + Like::notify(conn, like, actor); + res + } +} + +impl Notify for Like { + fn notify(conn: &PgConnection, like: activity::Like, actor: Id) { + let liker = User::from_url(conn, actor.into()).unwrap(); + let post = Post::find_by_ap_url(conn, like.like_props.object_link::().unwrap().into()).unwrap(); + for author in post.get_authors(conn) { + let post = post.clone(); + Notification::insert(conn, NewNotification { + title: format!("{} liked your article", liker.display_name.clone()), + content: Some(post.title), + link: Some(post.ap_url), + user_id: author.id + }); + } } } diff --git a/src/models/posts.rs b/src/models/posts.rs index 6e3f4899..b17a2340 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -24,7 +24,7 @@ use models::{ use schema::posts; use safe_string::SafeString; -#[derive(Queryable, Identifiable, Serialize)] +#[derive(Queryable, Identifiable, Serialize, Clone)] pub struct Post { pub id: i32, pub blog_id: i32, diff --git a/src/models/reshares.rs b/src/models/reshares.rs index 2e2896d8..8477243d 100644 --- a/src/models/reshares.rs +++ b/src/models/reshares.rs @@ -2,8 +2,8 @@ use activitypub::activity::{Announce, Undo}; use chrono::NaiveDateTime; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; -use activity_pub::{Id, IntoId, actor::Actor, inbox::FromActivity, object::Object}; -use models::{posts::Post, users::User}; +use activity_pub::{Id, IntoId, actor::Actor, inbox::{FromActivity, Notify}, object::Object}; +use models::{notifications::*, posts::Post, users::User}; use schema::reshares; #[derive(Serialize, Deserialize, Queryable, Identifiable)] @@ -100,13 +100,31 @@ impl Reshare { } impl FromActivity for Reshare { - fn from_activity(conn: &PgConnection, announce: Announce, _actor: Id) -> Reshare { + fn from_activity(conn: &PgConnection, announce: Announce, actor: Id) -> Reshare { let user = User::from_url(conn, announce.announce_props.actor.as_str().unwrap().to_string()); let post = Post::find_by_ap_url(conn, announce.announce_props.object.as_str().unwrap().to_string()); - Reshare::insert(conn, NewReshare { + let reshare = Reshare::insert(conn, NewReshare { post_id: post.unwrap().id, user_id: user.unwrap().id, ap_url: announce.object_props.id_string().unwrap_or(String::from("")) - }) + }); + Reshare::notify(conn, announce, actor); + reshare + } +} + +impl Notify for Reshare { + fn notify(conn: &PgConnection, announce: Announce, actor: Id) { + let actor = User::from_url(conn, actor.into()).unwrap(); + let post = Post::find_by_ap_url(conn, announce.announce_props.object_link::().unwrap().into()).unwrap(); + for author in post.get_authors(conn) { + let post = post.clone(); + Notification::insert(conn, NewNotification { + title: format!("{} reshared your article", actor.display_name.clone()), + content: Some(post.title), + link: Some(post.ap_url), + user_id: author.id + }); + } } } diff --git a/src/models/users.rs b/src/models/users.rs index 0b10dfc4..78846ac8 100644 --- a/src/models/users.rs +++ b/src/models/users.rs @@ -37,10 +37,8 @@ use db_conn::DbConn; use models::{ blogs::Blog, blog_authors::BlogAuthor, - comments::Comment, follows::Follow, instance::Instance, - notifications::*, post_authors::PostAuthor, posts::Post }; @@ -458,58 +456,6 @@ impl Inbox for User { println!("Inbox error:\n{}\n{}\n\nActivity was: {}", err.cause(), err.backtrace(), act.to_string()); } - // Notifications - match act["type"].as_str().unwrap() { - "Announce" => { - let actor = User::from_url(conn, act["actor"].as_str().unwrap().to_string()).unwrap(); - let post = Post::find_by_ap_url(conn, act["object"].as_str().unwrap().to_string()).unwrap(); - Notification::insert(conn, NewNotification { - title: format!("{} reshared your article", actor.display_name.clone()), - content: Some(post.title), - link: Some(post.ap_url), - user_id: self.id - }); - }, - "Follow" => { - let follower = User::from_url(conn, act["actor"].as_str().unwrap().to_string()).unwrap(); - Notification::insert(conn, NewNotification { - title: format!("{} started following you", follower.display_name.clone()), - content: None, - link: Some(follower.ap_url), - user_id: self.id - }); - } - "Like" => { - let liker = User::from_url(conn, act["actor"].as_str().unwrap().to_string()).unwrap(); - let post = Post::find_by_ap_url(conn, act["object"].as_str().unwrap().to_string()).unwrap(); - Notification::insert(conn, NewNotification { - title: format!("{} liked your article", liker.display_name.clone()), - content: Some(post.title), - link: Some(post.ap_url), - user_id: self.id - }); - }, - "Create" => { - match act["object"]["type"].as_str().unwrap() { - "Note" => { - match Comment::find_by_ap_url(conn, act["object"]["id"].as_str().unwrap().to_string()) { - Some(comment) => { - Notification::insert(conn, NewNotification { - title: format!("{} commented your article", comment.get_author(conn).display_name.clone()), - content: Some(comment.get_post(conn).title), - link: comment.ap_url, - user_id: self.id - }); - }, - None => println!("Couldn't find comment by AP id, to create a new notification") - }; - } - _ => {} - } - } - _ => {} - } - // TODO: add to stream, or whatever needs to be done } }