Automatically insert mentions in comments
Fix some bug with mentions too Fix #52
This commit is contained in:
		
							parent
							
								
									0fd181e7ea
								
							
						
					
					
						commit
						7ba6f77e0f
					
				| @ -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, | ||||
|  | ||||
| @ -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::<Vec<String>>(); | ||||
|         println!("{:?}", mentions); | ||||
|         json["mentions"] = serde_json::to_value(mentions).unwrap(); | ||||
|         json | ||||
|     } | ||||
| 
 | ||||
| @ -88,15 +93,6 @@ impl FromActivity<Note> 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::<link::Mention>(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<Note> 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::<link::Mention>(tag) | ||||
|                     .map(|m| Mention::from_activity(conn, m, comm.id, false)) | ||||
|                     .ok(); | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         comm.notify(conn); | ||||
|         comm | ||||
|     } | ||||
|  | ||||
| @ -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<i32>, | ||||
|     pub comment_id: Option<i32>, | ||||
|     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> { | ||||
|         User::get(conn, self.mentioned_id) | ||||
| @ -44,7 +45,7 @@ impl Mention { | ||||
|     } | ||||
| 
 | ||||
|     pub fn get_comment(&self, conn: &PgConnection) -> Option<Comment> { | ||||
|         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<Self> { | ||||
|     pub fn from_activity(conn: &PgConnection, ment: link::Mention, inside: i32, in_post: bool) -> Option<Self> { | ||||
|         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 { | ||||
|  | ||||
| @ -187,16 +187,7 @@ impl Post { | ||||
| 
 | ||||
| impl FromActivity<Article> 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::<link::Mention>(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<Article> 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::<link::Mention>(tag) | ||||
|                     .map(|m| Mention::from_activity(conn, m, post.id, true)) | ||||
|                     .ok(); | ||||
|             } | ||||
|         } | ||||
|         post | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -19,17 +19,25 @@ use utils; | ||||
| 
 | ||||
| #[get("/~/<blog>/<slug>/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("/~/<blog_name>/<slug>/comment?<query>")] | ||||
| fn new_response(blog_name: String, slug: String, query: Option<CommentQuery>, 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("/~/<blog>/<slug>/comment", rank=2)] | ||||
| #[get("/~/<blog>/<slug>/comment", rank = 2)] | ||||
| fn new_auth(blog: String, slug: String) -> Flash<Redirect>{ | ||||
|     utils::requires_login("You need to be logged in order to post a comment", uri!(new: blog = blog, slug = slug)) | ||||
| } | ||||
|  | ||||
| @ -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<NewPostForm>, 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); | ||||
|  | ||||
| @ -8,7 +8,8 @@ | ||||
| <h1>{{ 'Comment "{{ post }}"' | _(post=post.title) }}</h1> | ||||
| <form method="post"> | ||||
|     <label for="content">{{ "Content" | _ }}</label> | ||||
|     <textarea id="content" name="content"></textarea> | ||||
|     {# Ugly, but we don't have the choice if we don't want weird paddings #} | ||||
|     <textarea id="content" name="content">{% filter trim %}{% if previous %}{% if previous.author.fqn != user_fqn %}@{{ previous.author.fqn }} {% endif %}{% for mention in previous.mentions %}{% if mention != user_fqn %}@{{ mention }} {% endif %}{% endfor %}{% endif %}{% endfilter %}</textarea> | ||||
|     <input type="submit" value="{{ "Submit comment" | _ }}" /> | ||||
| </form> | ||||
| {% endblock content %} | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user