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)]
|
||||
|
||||
extern crate activitypub;
|
||||
|
@ -33,6 +33,7 @@ impl Mention {
|
||||
get!(mentions);
|
||||
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);
|
||||
|
||||
pub fn get_mentioned(&self, conn: &PgConnection) -> Option<User> {
|
||||
User::get(conn, self.mentioned_id)
|
||||
@ -46,6 +47,14 @@ impl Mention {
|
||||
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 {
|
||||
let user = self.get_mentioned(conn);
|
||||
let mut mention = link::Mention::default();
|
||||
|
@ -145,6 +145,8 @@ impl Post {
|
||||
let mut to = self.get_receivers_urls(conn);
|
||||
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();
|
||||
article.object_props = ObjectProperties {
|
||||
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()),
|
||||
content: Some(serde_json::to_value(self.content.clone()).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()),
|
||||
to: Some(serde_json::to_value(to).unwrap()),
|
||||
cc: Some(serde_json::to_value(Vec::<serde_json::Value>::new()).unwrap()),
|
||||
..ObjectProperties::default()
|
||||
..ObjectProperties::default()
|
||||
};
|
||||
article
|
||||
}
|
||||
|
@ -4,11 +4,12 @@ use rocket::response::{Redirect, Flash};
|
||||
use rocket_contrib::Template;
|
||||
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 models::{
|
||||
blogs::*,
|
||||
comments::Comment,
|
||||
mentions::Mention,
|
||||
post_authors::*,
|
||||
posts::*,
|
||||
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() {
|
||||
Redirect::to(uri!(new: blog = blog_name))
|
||||
} 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 {
|
||||
blog_id: blog.id,
|
||||
@ -104,6 +105,10 @@ fn create(blog_name: String, data: Form<NewPostForm>, user: User, conn: DbConn)
|
||||
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);
|
||||
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())
|
||||
}
|
||||
|
||||
|
||||
pub fn md_to_html(md: &str) -> String {
|
||||
/// Returns (HTML, mentions)
|
||||
pub fn md_to_html(md: &str) -> (String, Vec<String>) {
|
||||
let parser = Parser::new_ext(md, Options::all());
|
||||
|
||||
let parser = parser.flat_map(|evt| match evt {
|
||||
Event::Text(txt) => txt.chars().fold((vec![], false, String::new(), 0), |(mut events, in_mention, text_acc, n), c| {
|
||||
if in_mention {
|
||||
if (c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_') && (n < (txt.chars().count() - 1)) {
|
||||
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1)
|
||||
} else {
|
||||
let mention = text_acc + c.to_string().as_ref();
|
||||
let short_mention = mention.clone();
|
||||
let short_mention = short_mention.splitn(1, '@').nth(0).unwrap_or("");
|
||||
let link = Tag::Link(format!("/@/{}/", mention).into(), short_mention.to_string().into());
|
||||
let (parser, mentions): (Vec<Vec<Event>>, Vec<Vec<String>>) = parser.map(|evt| match evt {
|
||||
Event::Text(txt) => {
|
||||
let (evts, _, _, _, new_mentions) = txt.chars().fold((vec![], false, String::new(), 0, vec![]), |(mut events, in_mention, text_acc, n, mut mentions), c| {
|
||||
if in_mention {
|
||||
if (c.is_alphanumeric() || c == '@' || c == '.' || c == '-' || c == '_') && (n < (txt.chars().count() - 1)) {
|
||||
(events, in_mention, text_acc + c.to_string().as_ref(), n + 1, mentions)
|
||||
} else {
|
||||
let mention = text_acc + c.to_string().as_ref();
|
||||
let short_mention = mention.clone();
|
||||
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()));
|
||||
events.push(Event::Text(format!("@{}", short_mention).into()));
|
||||
events.push(Event::End(link));
|
||||
mentions.push(mention);
|
||||
events.push(Event::Start(link.clone()));
|
||||
events.push(Event::Text(format!("@{}", short_mention).into()));
|
||||
events.push(Event::End(link));
|
||||
|
||||
(events, false, c.to_string(), n + 1)
|
||||
}
|
||||
} else {
|
||||
if c == '@' {
|
||||
events.push(Event::Text(text_acc.into()));
|
||||
(events, true, String::new(), n + 1)
|
||||
} else {
|
||||
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, false, c.to_string(), n + 1, mentions)
|
||||
}
|
||||
} else {
|
||||
if c == '@' {
|
||||
events.push(Event::Text(text_acc.into()));
|
||||
(events, true, String::new(), n + 1, mentions)
|
||||
} else {
|
||||
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, 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,
|
||||
_ => vec![evt]
|
||||
});
|
||||
});
|
||||
(evts, new_mentions)
|
||||
},
|
||||
_ => (vec![evt], vec![])
|
||||
}).unzip();
|
||||
let parser = parser.into_iter().flatten();
|
||||
let mentions = mentions.into_iter().flatten();
|
||||
|
||||
// TODO: fetch mentionned profiles in background, if needed
|
||||
|
||||
let mut buf = String::new();
|
||||
html::push_html(&mut buf, parser);
|
||||
buf
|
||||
(buf, mentions.collect())
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user