Save mentions
This commit is contained in:
parent
c4cc4a4e13
commit
d7b71848fc
@ -1,4 +1,4 @@
|
|||||||
#![feature(plugin, custom_derive, decl_macro, iterator_find_map)]
|
#![feature(plugin, custom_derive, decl_macro, iterator_find_map, iterator_flatten)]
|
||||||
#![plugin(rocket_codegen)]
|
#![plugin(rocket_codegen)]
|
||||||
|
|
||||||
extern crate activitypub;
|
extern crate activitypub;
|
||||||
|
@ -33,6 +33,7 @@ impl Mention {
|
|||||||
get!(mentions);
|
get!(mentions);
|
||||||
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);
|
||||||
|
|
||||||
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)
|
||||||
@ -46,6 +47,14 @@ impl Mention {
|
|||||||
self.post_id.and_then(|id| Comment::get(conn, id))
|
self.post_id.and_then(|id| Comment::get(conn, id))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn build_activity(conn: &PgConnection, ment: String) -> link::Mention {
|
||||||
|
let user = User::find_by_fqn(conn, ment.clone());
|
||||||
|
let mut mention = link::Mention::default();
|
||||||
|
mention.link_props.set_href_string(user.clone().map(|u| u.ap_url).unwrap_or(String::new())).expect("Error setting mention's href");
|
||||||
|
mention.link_props.set_name_string(format!("@{}", ment)).expect("Error setting mention's name");
|
||||||
|
mention
|
||||||
|
}
|
||||||
|
|
||||||
pub fn to_activity(&self, conn: &PgConnection) -> link::Mention {
|
pub fn to_activity(&self, conn: &PgConnection) -> link::Mention {
|
||||||
let user = self.get_mentioned(conn);
|
let user = self.get_mentioned(conn);
|
||||||
let mut mention = link::Mention::default();
|
let mut mention = link::Mention::default();
|
||||||
|
@ -145,6 +145,8 @@ impl Post {
|
|||||||
let mut to = self.get_receivers_urls(conn);
|
let mut to = self.get_receivers_urls(conn);
|
||||||
to.push(PUBLIC_VISIBILTY.to_string());
|
to.push(PUBLIC_VISIBILTY.to_string());
|
||||||
|
|
||||||
|
let mentions = Mention::list_for_post(conn, self.id).into_iter().map(|m| m.to_activity(conn)).collect::<Vec<link::Mention>>();
|
||||||
|
|
||||||
let mut article = Article::default();
|
let mut article = Article::default();
|
||||||
article.object_props = ObjectProperties {
|
article.object_props = ObjectProperties {
|
||||||
name: Some(serde_json::to_value(self.title.clone()).unwrap()),
|
name: Some(serde_json::to_value(self.title.clone()).unwrap()),
|
||||||
@ -152,11 +154,11 @@ impl Post {
|
|||||||
attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::<Vec<String>>()).unwrap()),
|
attributed_to: Some(serde_json::to_value(self.get_authors(conn).into_iter().map(|x| x.ap_url).collect::<Vec<String>>()).unwrap()),
|
||||||
content: Some(serde_json::to_value(self.content.clone()).unwrap()),
|
content: Some(serde_json::to_value(self.content.clone()).unwrap()),
|
||||||
published: Some(serde_json::to_value(self.creation_date).unwrap()),
|
published: Some(serde_json::to_value(self.creation_date).unwrap()),
|
||||||
tag: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
|
tag: Some(serde_json::to_value(mentions).unwrap()),
|
||||||
url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()),
|
url: Some(serde_json::to_value(self.compute_id(conn)).unwrap()),
|
||||||
to: Some(serde_json::to_value(to).unwrap()),
|
to: Some(serde_json::to_value(to).unwrap()),
|
||||||
cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
|
cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
|
||||||
..ObjectProperties::default()
|
..ObjectProperties::default()
|
||||||
};
|
};
|
||||||
article
|
article
|
||||||
}
|
}
|
||||||
|
@ -4,11 +4,12 @@ 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};
|
use activity_pub::{broadcast, context, activity_pub, ActivityPub, Id};
|
||||||
use db_conn::DbConn;
|
use db_conn::DbConn;
|
||||||
use models::{
|
use models::{
|
||||||
blogs::*,
|
blogs::*,
|
||||||
comments::Comment,
|
comments::Comment,
|
||||||
|
mentions::Mention,
|
||||||
post_authors::*,
|
post_authors::*,
|
||||||
posts::*,
|
posts::*,
|
||||||
users::User
|
users::User
|
||||||
@ -87,7 +88,7 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
|
|||||||
if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() {
|
if slug == "new" || Post::find_by_slug(&*conn, slug.clone(), blog.id).is_some() {
|
||||||
Redirect::to(uri!(new: blog = blog_name))
|
Redirect::to(uri!(new: blog = blog_name))
|
||||||
} else {
|
} else {
|
||||||
let content = utils::md_to_html(form.content.to_string().as_ref());
|
let (content, mentions) = utils::md_to_html(form.content.to_string().as_ref());
|
||||||
|
|
||||||
let post = Post::insert(&*conn, NewPost {
|
let post = Post::insert(&*conn, NewPost {
|
||||||
blog_id: blog.id,
|
blog_id: blog.id,
|
||||||
@ -104,6 +105,10 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
|
|||||||
author_id: user.id
|
author_id: user.id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
for m in mentions.into_iter() {
|
||||||
|
Mention::from_activity(&*conn, Mention::build_activity(&*conn, m), Id::new(post.compute_id(&*conn)));
|
||||||
|
}
|
||||||
|
|
||||||
let act = post.create_activity(&*conn);
|
let act = post.create_activity(&*conn);
|
||||||
broadcast(&*conn, &user, act, user.get_followers(&*conn));
|
broadcast(&*conn, &user, act, user.get_followers(&*conn));
|
||||||
|
|
||||||
|
66
src/utils.rs
66
src/utils.rs
@ -20,45 +20,51 @@ pub fn requires_login(message: &str, url: Uri) -> Flash<Redirect> {
|
|||||||
Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str())
|
Flash::new(Redirect::to(Uri::new(format!("/login?m={}", gettext(message.to_string())))), "callback", url.as_str())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns (HTML, mentions)
|
||||||
pub fn md_to_html(md: &str) -> String {
|
pub fn md_to_html(md: &str) -> (String, Vec<String>) {
|
||||||
let parser = Parser::new_ext(md, Options::all());
|
let parser = Parser::new_ext(md, Options::all());
|
||||||
|
|
||||||
let parser = parser.flat_map(|evt| match evt {
|
let (parser, mentions): (Vec<Vec<Event>>, Vec<Vec<String>>) = parser.map(|evt| match evt {
|
||||||
Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), c| {
|
Event::Text(txt) => {
|
||||||
if in_mention {
|
let (evts, _, _, _, new_mentions) = txt.chars().fold((vec![], false, String::new(), 0, vec![]), |(mut events, in_mention, text_acc, n, mut mentions), c| {
|
||||||
if (c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_') && (n < (txt.chars().count() - 1)) {
|
if in_mention {
|
||||||
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1)
|
if (c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_') && (n < (txt.chars().count() - 1)) {
|
||||||
} else {
|
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1, mentions)
|
||||||
let mention = text_acc + c.to_string().as_ref();
|
} else {
|
||||||
let short_mention = mention.clone();
|
let mention = text_acc + c.to_string().as_ref();
|
||||||
let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or("");
|
let short_mention = mention.clone();
|
||||||
let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into());
|
let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or("");
|
||||||
|
let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into());
|
||||||
|
|
||||||
events.push(Event::Start(link.clone()));
|
mentions.push(mention);
|
||||||
events.push(Event::Text(format!("@{}", short_mention).into()));
|
events.push(Event::Start(link.clone()));
|
||||||
events.push(Event::End(link));
|
events.push(Event::Text(format!("@{}", short_mention).into()));
|
||||||
|
events.push(Event::End(link));
|
||||||
|
|
||||||
(events, false, c.to_string(), n + 1)
|
(events, false, c.to_string(), n + 1, mentions)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if c == '@' {
|
if c == '@' {
|
||||||
events.push(Event::Text(text_acc.into()));
|
events.push(Event::Text(text_acc.into()));
|
||||||
(events, true, String::new(), n + 1)
|
(events, true, String::new(), n + 1, mentions)
|
||||||
} else {
|
} else {
|
||||||
if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention.
|
if n >= (txt.chars().count() - 1) { // Add the text after at the end, even if it is not followed by a mention.
|
||||||
events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into()))
|
events.push(Event::Text((text_acc.clone() + c.to_string().as_ref()).into()))
|
||||||
|
}
|
||||||
|
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1, mentions)
|
||||||
}
|
}
|
||||||
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1)
|
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
}).0,
|
(evts, new_mentions)
|
||||||
_ => vec![evt]
|
},
|
||||||
});
|
_ => (vec![evt], vec![])
|
||||||
|
}).unzip();
|
||||||
|
let parser = parser.into_iter().flatten();
|
||||||
|
let mentions = mentions.into_iter().flatten();
|
||||||
|
|
||||||
// TODO: fetch mentionned profiles in background, if needed
|
// TODO: fetch mentionned profiles in background, if needed
|
||||||
|
|
||||||
let mut buf = String::new();
|
let mut buf = String::new();
|
||||||
html::push_html(&mut buf, parser);
|
html::push_html(&mut buf, parser);
|
||||||
buf
|
(buf, mentions.collect())
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user