mirror of
https://git.joinplu.me/Plume/Plume.git
synced 2024-12-20 09:06:33 +00:00
Automatically insert mentions in comments
Fix some bug with mentions too Fix #52
This commit is contained in:
parent
0fd181e7ea
commit
7ba6f77e0f
7 changed files with 64 additions and 46 deletions
|
@ -69,6 +69,7 @@ fn main() {
|
||||||
routes::blogs::create,
|
routes::blogs::create,
|
||||||
|
|
||||||
routes::comments::new,
|
routes::comments::new,
|
||||||
|
routes::comments::new_response,
|
||||||
routes::comments::new_auth,
|
routes::comments::new_auth,
|
||||||
routes::comments::create,
|
routes::comments::create,
|
||||||
routes::comments::create_response,
|
routes::comments::create_response,
|
||||||
|
|
|
@ -75,6 +75,11 @@ impl Comment {
|
||||||
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
pub fn to_json(&self, conn: &PgConnection) -> serde_json::Value {
|
||||||
let mut json = serde_json::to_value(self).unwrap();
|
let mut json = serde_json::to_value(self).unwrap();
|
||||||
json["author"] = self.get_author(conn).to_json(conn);
|
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
|
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_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());
|
||||||
|
|
||||||
// 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 {
|
let comm = Comment::insert(conn, NewComment {
|
||||||
content: SafeString::new(¬e.object_props.content_string().unwrap()),
|
content: SafeString::new(¬e.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("")),
|
||||||
|
@ -108,6 +104,16 @@ impl FromActivity<Note> for Comment {
|
||||||
author_id: User::from_url(conn, actor.clone().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
|
||||||
});
|
});
|
||||||
|
|
||||||
|
// 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.notify(conn);
|
||||||
comm
|
comm
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use activitypub::link;
|
use activitypub::link;
|
||||||
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
use diesel::{self, PgConnection, QueryDsl, RunQueryDsl, ExpressionMethods};
|
||||||
|
|
||||||
use activity_pub::{Id, inbox::Notify};
|
use activity_pub::inbox::Notify;
|
||||||
use models::{
|
use models::{
|
||||||
comments::Comment,
|
comments::Comment,
|
||||||
notifications::*,
|
notifications::*,
|
||||||
|
@ -10,13 +10,13 @@ use models::{
|
||||||
};
|
};
|
||||||
use schema::mentions;
|
use schema::mentions;
|
||||||
|
|
||||||
#[derive(Queryable, Identifiable)]
|
#[derive(Queryable, Identifiable, Serialize, Deserialize)]
|
||||||
pub struct Mention {
|
pub struct Mention {
|
||||||
pub id: i32,
|
pub id: i32,
|
||||||
pub mentioned_id: i32,
|
pub mentioned_id: i32,
|
||||||
pub post_id: Option<i32>,
|
pub post_id: Option<i32>,
|
||||||
pub comment_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)]
|
#[derive(Insertable)]
|
||||||
|
@ -34,6 +34,7 @@ impl Mention {
|
||||||
find_by!(mentions, find_by_ap_url, ap_url as String);
|
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_user, mentioned_id as i32);
|
||||||
list_by!(mentions, list_for_post, post_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> {
|
pub fn get_mentioned(&self, conn: &PgConnection) -> Option<User> {
|
||||||
User::get(conn, self.mentioned_id)
|
User::get(conn, self.mentioned_id)
|
||||||
|
@ -44,7 +45,7 @@ impl Mention {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_comment(&self, conn: &PgConnection) -> Option<Comment> {
|
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 {
|
pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention {
|
||||||
|
@ -63,11 +64,12 @@ impl Mention {
|
||||||
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 ap_url = ment.link_props.href_string().unwrap();
|
||||||
let mentioned = User::find_by_ap_url(conn, ap_url).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()) {
|
if in_post {
|
||||||
|
Post::get(conn, inside.clone().into()).map(|post| {
|
||||||
let res = Mention::insert(conn, NewMention {
|
let res = Mention::insert(conn, NewMention {
|
||||||
mentioned_id: mentioned.id,
|
mentioned_id: mentioned.id,
|
||||||
post_id: Some(post.id),
|
post_id: Some(post.id),
|
||||||
|
@ -75,9 +77,10 @@ impl Mention {
|
||||||
ap_url: ment.link_props.href_string().unwrap_or(String::new())
|
ap_url: ment.link_props.href_string().unwrap_or(String::new())
|
||||||
});
|
});
|
||||||
res.notify(conn);
|
res.notify(conn);
|
||||||
Some(res)
|
res
|
||||||
|
})
|
||||||
} else {
|
} 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 {
|
let res = Mention::insert(conn, NewMention {
|
||||||
mentioned_id: mentioned.id,
|
mentioned_id: mentioned.id,
|
||||||
post_id: None,
|
post_id: None,
|
||||||
|
@ -85,10 +88,8 @@ impl Mention {
|
||||||
ap_url: ment.link_props.href_string().unwrap_or(String::new())
|
ap_url: ment.link_props.href_string().unwrap_or(String::new())
|
||||||
});
|
});
|
||||||
res.notify(conn);
|
res.notify(conn);
|
||||||
Some(res)
|
res
|
||||||
} else {
|
})
|
||||||
None
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -97,7 +98,7 @@ impl Notify for Mention {
|
||||||
fn notify(&self, conn: &PgConnection) {
|
fn notify(&self, conn: &PgConnection) {
|
||||||
let author = self.get_comment(conn)
|
let author = self.get_comment(conn)
|
||||||
.map(|c| c.get_author(conn).display_name.clone())
|
.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| {
|
self.get_mentioned(conn).map(|m| {
|
||||||
Notification::insert(conn, NewNotification {
|
Notification::insert(conn, NewNotification {
|
||||||
|
|
|
@ -187,16 +187,7 @@ impl Post {
|
||||||
|
|
||||||
impl FromActivity<Article> for Post {
|
impl FromActivity<Article> for Post {
|
||||||
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
|
fn from_activity(conn: &PgConnection, article: Article, _actor: Id) -> Post {
|
||||||
// save mentions
|
let post = Post::insert(conn, NewPost {
|
||||||
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 {
|
|
||||||
blog_id: 0, // TODO
|
blog_id: 0, // TODO
|
||||||
slug: String::from(""), // TODO
|
slug: String::from(""), // TODO
|
||||||
title: article.object_props.name_string().unwrap(),
|
title: article.object_props.name_string().unwrap(),
|
||||||
|
@ -204,7 +195,17 @@ impl FromActivity<Article> for Post {
|
||||||
published: true,
|
published: true,
|
||||||
license: String::from("CC-0"),
|
license: String::from("CC-0"),
|
||||||
ap_url: article.object_props.url_string().unwrap_or(String::from(""))
|
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,11 +19,19 @@ use utils;
|
||||||
|
|
||||||
#[get("/~/<blog>/<slug>/comment")]
|
#[get("/~/<blog>/<slug>/comment")]
|
||||||
fn new(blog: String, slug: String, user: User, conn: DbConn) -> Template {
|
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| {
|
may_fail!(Post::find_by_slug(&*conn, slug, blog.id), "Couldn't find this post", |post| {
|
||||||
Template::render("comments/new", json!({
|
Template::render("comments/new", json!({
|
||||||
"post": post,
|
"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)
|
||||||
}))
|
}))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
|
@ -4,7 +4,7 @@ use rocket::response::{Redirect, Flash};
|
||||||
use rocket_contrib::Template;
|
use rocket_contrib::Template;
|
||||||
use serde_json;
|
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 db_conn::DbConn;
|
||||||
use models::{
|
use models::{
|
||||||
blogs::*,
|
blogs::*,
|
||||||
|
@ -106,7 +106,7 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
|
||||||
});
|
});
|
||||||
|
|
||||||
for m in mentions.into_iter() {
|
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);
|
let act = post.create_activity(&*conn);
|
||||||
|
|
|
@ -8,7 +8,8 @@
|
||||||
<h1>{{ 'Comment "{{ post }}"' | _(post=post.title) }}</h1>
|
<h1>{{ 'Comment "{{ post }}"' | _(post=post.title) }}</h1>
|
||||||
<form method="post">
|
<form method="post">
|
||||||
<label for="content">{{ "Content" | _ }}</label>
|
<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" | _ }}" />
|
<input type="submit" value="{{ "Submit comment" | _ }}" />
|
||||||
</form>
|
</form>
|
||||||
{% endblock content %}
|
{% endblock content %}
|
||||||
|
|
Loading…
Reference in a new issue