From 7ba6f77e0f9b2bee87bc6ebad7cd28c6041e5d24 Mon Sep 17 00:00:00 2001 From: Bat Date: Thu, 21 Jun 2018 14:05:35 +0100 Subject: [PATCH] Automatically insert mentions in comments Fix some bug with mentions too Fix #52 --- src/main.rs | 1 + src/models/comments.rs | 24 ++++++++++++------- src/models/mentions.rs | 41 ++++++++++++++++---------------- src/models/posts.rs | 23 +++++++++--------- src/routes/comments.rs | 14 ++++++++--- src/routes/posts.rs | 4 ++-- templates/comments/new.html.tera | 3 ++- 7 files changed, 64 insertions(+), 46 deletions(-) diff --git a/src/main.rs b/src/main.rs index 51390e26..786d2a8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -69,6 +69,7 @@ fn main() { routes::blogs::create, routes::comments::new, + routes::comments::new_response, routes::comments::new_auth, routes::comments::create, routes::comments::create_response, diff --git a/src/models/comments.rs b/src/models/comments.rs index 8e30e35e..326567db 100644 --- a/src/models/comments.rs +++ b/src/models/comments.rs @@ -75,6 +75,11 @@ impl Comment { pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value { let mut json = serde_json::to_value(self).unwrap(); json["author"] = self.get_author(conn).to_json(conn); + let mentions = Mention::list_for_comment(conn, self.id).into_iter() + .map(|m| m.get_mentioned(conn).map(|u| u.get_fqn(conn)).unwrap_or(String::new())) + .collect::>(); + println!("{:?}", mentions); + json["mentions"] = serde_json::to_value(mentions).unwrap(); json } @@ -88,15 +93,6 @@ impl FromActivity for 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()); - // save mentions - if let Some(serde_json::Value::Array(tags)) = note.object_props.tag.clone() { - for tag in tags.into_iter() { - serde_json::from_value::(tag) - .map(|m| Mention::from_activity(conn, m, Id::new(note.clone().object_props.clone().url_string().unwrap_or(String::from(""))))) - .ok(); - } - } - 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("")), @@ -108,6 +104,16 @@ impl FromActivity for Comment { 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 }); + + // save mentions + if let Some(serde_json::Value::Array(tags)) = note.object_props.tag.clone() { + for tag in tags.into_iter() { + serde_json::from_value::(tag) + .map(|m| Mention::from_activity(conn, m, comm.id, false)) + .ok(); + } + } + comm.notify(conn); comm } diff --git a/src/models/mentions.rs b/src/models/mentions.rs index 7d0fe57a..45b8abbf 100644 --- a/src/models/mentions.rs +++ b/src/models/mentions.rs @@ -1,7 +1,7 @@ use activitypub::link; use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods}; -use activity_pub::{Id, inbox::Notify}; +use activity_pub::inbox::Notify; use models::{ comments::Comment, notifications::*, @@ -10,13 +10,13 @@ use models::{ }; use schema::mentions; -#[derive(Queryable, Identifiable)] +#[derive(Queryable, Identifiable, Serialize, Deserialize)] pub struct Mention { pub id: i32, pub mentioned_id: i32, pub post_id: Option, pub comment_id: Option, - pub ap_url: String + pub ap_url: String // TODO: remove, since mentions don't have an AP URL actually, this field was added by mistake } #[derive(Insertable)] @@ -34,6 +34,7 @@ impl Mention { find_by!(mentions, find_by_ap_url, ap_url as String); list_by!(mentions, list_for_user, mentioned_id as i32); list_by!(mentions, list_for_post, post_id as i32); + list_by!(mentions, list_for_comment, comment_id as i32); pub fn get_mentioned(&self, conn: &PgConnection) -> Option { User::get(conn, self.mentioned_id) @@ -44,7 +45,7 @@ impl Mention { } pub fn get_comment(&self, conn: &PgConnection) -> Option { - self.post_id.and_then(|id| Comment::get(conn, id)) + self.comment_id.and_then(|id| Comment::get(conn, id)) } pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention { @@ -63,21 +64,23 @@ impl Mention { mention } - pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: Id) -> Option { + pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: i32, in_post: bool) -> Option { let ap_url = ment.link_props.href_string().unwrap(); let mentioned = User::find_by_ap_url(conn, ap_url).unwrap(); - if let Some(post) = Post::find_by_ap_url(conn, inside.clone().into()) { - let res = Mention::insert(conn, NewMention { - mentioned_id: mentioned.id, - post_id: Some(post.id), - comment_id: None, - ap_url: ment.link_props.href_string().unwrap_or(String::new()) - }); - res.notify(conn); - Some(res) + if in_post { + Post::get(conn, inside.clone().into()).map(|post| { + let res = Mention::insert(conn, NewMention { + mentioned_id: mentioned.id, + post_id: Some(post.id), + comment_id: None, + ap_url: ment.link_props.href_string().unwrap_or(String::new()) + }); + res.notify(conn); + res + }) } else { - if let Some(comment) = Comment::find_by_ap_url(conn, inside.into()) { + Comment::get(conn, inside.into()).map(|comment| { let res = Mention::insert(conn, NewMention { mentioned_id: mentioned.id, post_id: None, @@ -85,10 +88,8 @@ impl Mention { ap_url: ment.link_props.href_string().unwrap_or(String::new()) }); res.notify(conn); - Some(res) - } else { - None - } + res + }) } } } @@ -97,7 +98,7 @@ impl Notify for Mention { fn notify(&self, conn: &PgConnection) { let author = self.get_comment(conn) .map(|c| c.get_author(conn).display_name.clone()) - .unwrap_or(self.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone()); + .unwrap_or_else(|| self.get_post(conn).unwrap().get_authors(conn)[0].display_name.clone()); self.get_mentioned(conn).map(|m| { Notification::insert(conn, NewNotification { diff --git a/src/models/posts.rs b/src/models/posts.rs index 368d2834..bf0e7fee 100644 --- a/src/models/posts.rs +++ b/src/models/posts.rs @@ -187,16 +187,7 @@ impl Post { impl FromActivity
for Post { fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post { - // save mentions - if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() { - for tag in tags.into_iter() { - serde_json::from_value::(tag) - .map(|m| Mention::from_activity(conn, m, Id::new(article.clone().object_props.clone().url_string().unwrap_or(String::from(""))))) - .ok(); - } - } - - Post::insert(conn, NewPost { + let post = Post::insert(conn, NewPost { blog_id: 0, // TODO slug: String::from(""), // TODO title: article.object_props.name_string().unwrap(), @@ -204,7 +195,17 @@ impl FromActivity
for Post { published: true, license: String::from("CC-0"), ap_url: article.object_props.url_string().unwrap_or(String::from("")) - }) + }); + + // save mentions + if let Some(serde_json::Value::Array(tags)) = article.object_props.tag.clone() { + for tag in tags.into_iter() { + serde_json::from_value::(tag) + .map(|m| Mention::from_activity(conn, m, post.id, true)) + .ok(); + } + } + post } } diff --git a/src/routes/comments.rs b/src/routes/comments.rs index a2eddaf9..ca40a3a7 100644 --- a/src/routes/comments.rs +++ b/src/routes/comments.rs @@ -19,17 +19,25 @@ use utils; #[get("/~///comment")] fn new(blog: String, slug: String, user: User, conn: DbConn) -> Template { - may_fail!(Blog::find_by_fqn(&*conn, blog), "Couldn't find this blog", |blog| { + new_response(blog, slug, None, user, conn) +} + +// See: https://github.com/SergioBenitez/Rocket/pull/454 +#[get("/~///comment?")] +fn new_response(blog_name: String, slug: String, query: Option, user: User, conn: DbConn) -> Template { + may_fail!(Blog::find_by_fqn(&*conn, blog_name), "Couldn't find this blog", |blog| { may_fail!(Post::find_by_slug(&*conn, slug, blog.id), "Couldn't find this post", |post| { Template::render("comments/new", json!({ "post": post, - "account": user + "account": user, + "previous": query.and_then(|q| q.responding_to.map(|r| Comment::get(&*conn, r).expect("Error retrieving previous comment").to_json(&*conn))), + "user_fqn": user.get_fqn(&*conn) })) }) }) } -#[get("/~///comment", rank=2)] +#[get("/~///comment", rank = 2)] fn new_auth(blog: String, slug: String) -> Flash{ utils::requires_login("You need to be logged in order to post a comment", uri!(new: blog = blog, slug = slug)) } diff --git a/src/routes/posts.rs b/src/routes/posts.rs index d06f6090..fb8c9907 100644 --- a/src/routes/posts.rs +++ b/src/routes/posts.rs @@ -4,7 +4,7 @@ use rocket::response::{Redirect, Flash}; use rocket_contrib::Template; use serde_json; -use activity_pub::{broadcast, context, activity_pub, ActivityPub, Id}; +use activity_pub::{broadcast, context, activity_pub, ActivityPub}; use db_conn::DbConn; use models::{ blogs::*, @@ -106,7 +106,7 @@ fn create(blog_name: String, data: Form, user: User, conn: DbConn) }); for m in mentions.into_iter() { - Mention::from_activity(&*conn, Mention::build_activity(&*conn, m), Id::new(post.compute_id(&*conn))); + Mention::from_activity(&*conn, Mention::build_activity(&*conn, m), post.id, true); } let act = post.create_activity(&*conn); diff --git a/templates/comments/new.html.tera b/templates/comments/new.html.tera index a02de4ab..4c1bb836 100644 --- a/templates/comments/new.html.tera +++ b/templates/comments/new.html.tera @@ -8,7 +8,8 @@

{{ 'Comment "{{ post }}"' | _(post=post.title) }}

- + {# Ugly, but we don't have the choice if we don't want weird paddings #} +
{% endblock content %}