Actually use the activity_pub::inbox::Notify trait for notifications

It won't work for local events until we use AP internally too
This commit is contained in:
Bat 2018-06-17 20:37:10 +01:00
parent 2a34b7909a
commit 0ea8c882ad
7 changed files with 93 additions and 73 deletions

View File

@ -1,5 +1,5 @@
use activitypub::{ use activitypub::{
Activity, Object, Object,
activity::{Create, Like, Undo} activity::{Create, Like, Undo}
}; };
use diesel::PgConnection; use diesel::PgConnection;
@ -40,7 +40,7 @@ pub trait FromActivity<T: Object>: Sized {
} }
} }
pub trait Notify<T: Activity> { pub trait Notify<T: Object> {
fn notify(conn: &PgConnection, act: T, actor: Id); fn notify(conn: &PgConnection, act: T, actor: Id);
} }

View File

@ -9,11 +9,12 @@ use serde_json;
use activity_pub::{ use activity_pub::{
ap_url, Id, IntoId, PUBLIC_VISIBILTY, ap_url, Id, IntoId, PUBLIC_VISIBILTY,
actor::Actor, actor::Actor,
inbox::FromActivity, inbox::{FromActivity, Notify},
object::Object object::Object
}; };
use models::{ use models::{
instance::Instance, instance::Instance,
notifications::*,
posts::Post, posts::Post,
users::User users::User
}; };
@ -128,7 +129,7 @@ impl FromActivity<Note> for Comment {
fn from_activity(conn: &PgConnection, note: Note, actor: Id) -> 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_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()); 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(&note.object_props.content_string().unwrap()), content: SafeString::new(&note.object_props.content_string().unwrap()),
spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")), spoiler_text: note.object_props.summary_string().unwrap_or(String::from("")),
ap_url: note.object_props.id_string().ok(), ap_url: note.object_props.id_string().ok(),
@ -136,9 +137,30 @@ impl FromActivity<Note> for Comment {
post_id: previous_comment post_id: previous_comment
.map(|c| c.post_id) .map(|c| c.post_id)
.unwrap_or_else(|| Post::find_by_ap_url(conn, previous_url).unwrap().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 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<Note> 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")
};
} }
} }

View File

@ -1,9 +1,12 @@
use activitypub::{Actor, activity::{Accept, Follow as FollowAct}}; use activitypub::{Actor, activity::{Accept, Follow as FollowAct}};
use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl}; use diesel::{self, PgConnection, ExpressionMethods, QueryDsl, RunQueryDsl};
use activity_pub::{broadcast, Id, IntoId, actor::Actor as ApActor, inbox::{FromActivity, WithInbox}, sign::Signer}; use activity_pub::{broadcast, Id, IntoId, actor::Actor as ApActor, inbox::{FromActivity, Notify, WithInbox}, sign::Signer};
use models::blogs::Blog; use models::{
use models::users::User; blogs::Blog,
notifications::*,
users::User
};
use schema::follows; use schema::follows;
#[derive(Queryable, Identifiable, Associations)] #[derive(Queryable, Identifiable, Associations)]
@ -70,3 +73,15 @@ impl FromActivity<FollowAct> for Follow {
} }
} }
} }
impl Notify<FollowAct> 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::<Id>().unwrap().into()).unwrap().id
});
}
}

View File

@ -7,10 +7,11 @@ use activity_pub::{
Id, Id,
IntoId, IntoId,
actor::Actor, actor::Actor,
inbox::{FromActivity, Deletable}, inbox::{FromActivity, Deletable, Notify},
object::Object object::Object
}; };
use models::{ use models::{
notifications::*,
posts::Post, posts::Post,
users::User users::User
}; };
@ -97,14 +98,32 @@ impl Like {
} }
impl FromActivity<activity::Like> for Like { impl FromActivity<activity::Like> 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 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()); 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, post_id: post.unwrap().id,
user_id: liker.unwrap().id, user_id: liker.unwrap().id,
ap_url: like.object_props.id_string().unwrap_or(String::from("")) ap_url: like.object_props.id_string().unwrap_or(String::from(""))
}) });
Like::notify(conn, like, actor);
res
}
}
impl Notify<activity::Like> 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::<Id>().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
});
}
} }
} }

View File

@ -24,7 +24,7 @@ use models::{
use schema::posts; use schema::posts;
use safe_string::SafeString; use safe_string::SafeString;
#[derive(Queryable, Identifiable, Serialize)] #[derive(Queryable, Identifiable, Serialize, Clone)]
pub struct Post { pub struct Post {
pub id: i32, pub id: i32,
pub blog_id: i32, pub blog_id: i32,

View File

@ -2,8 +2,8 @@ use activitypub::activity::{Announce, Undo};
use chrono::NaiveDateTime; use chrono::NaiveDateTime;
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
use activity_pub::{Id, IntoId, actor::Actor, inbox::FromActivity, object::Object}; use activity_pub::{Id, IntoId, actor::Actor, inbox::{FromActivity, Notify}, object::Object};
use models::{posts::Post, users::User}; use models::{notifications::*, posts::Post, users::User};
use schema::reshares; use schema::reshares;
#[derive(Serialize, Deserialize, Queryable, Identifiable)] #[derive(Serialize, Deserialize, Queryable, Identifiable)]
@ -100,13 +100,31 @@ impl Reshare {
} }
impl FromActivity<Announce> for Reshare { impl FromActivity<Announce> 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 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()); 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, post_id: post.unwrap().id,
user_id: user.unwrap().id, user_id: user.unwrap().id,
ap_url: announce.object_props.id_string().unwrap_or(String::from("")) ap_url: announce.object_props.id_string().unwrap_or(String::from(""))
}) });
Reshare::notify(conn, announce, actor);
reshare
}
}
impl Notify<Announce> 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::<Id>().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
});
}
} }
} }

View File

@ -37,10 +37,8 @@ use db_conn::DbConn;
use models::{ use models::{
blogs::Blog, blogs::Blog,
blog_authors::BlogAuthor, blog_authors::BlogAuthor,
comments::Comment,
follows::Follow, follows::Follow,
instance::Instance, instance::Instance,
notifications::*,
post_authors::PostAuthor, post_authors::PostAuthor,
posts::Post 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()); 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 // TODO: add to stream, or whatever needs to be done
} }
} }