Plume/plume-models/src/mentions.rs
2022-02-05 17:58:00 +09:00

207 lines
6.0 KiB
Rust

use crate::{
comments::Comment, db_conn::DbConn, notifications::*, posts::Post, schema::mentions,
users::User, Connection, Error, Result,
};
use activitypub::link;
use diesel::{self, ExpressionMethods, QueryDsl, RunQueryDsl};
use plume_common::activity_pub::inbox::AsActor;
#[derive(Clone, Queryable, Identifiable)]
pub struct Mention {
pub id: i32,
pub mentioned_id: i32,
pub post_id: Option<i32>,
pub comment_id: Option<i32>,
}
#[derive(Insertable)]
#[table_name = "mentions"]
pub struct NewMention {
pub mentioned_id: i32,
pub post_id: Option<i32>,
pub comment_id: Option<i32>,
}
impl Mention {
insert!(mentions, NewMention);
get!(mentions);
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: &Connection) -> Result<User> {
User::get(conn, self.mentioned_id)
}
pub fn get_post(&self, conn: &Connection) -> Result<Post> {
self.post_id
.ok_or(Error::NotFound)
.and_then(|id| Post::get(conn, id))
}
pub fn get_comment(&self, conn: &Connection) -> Result<Comment> {
self.comment_id
.ok_or(Error::NotFound)
.and_then(|id| Comment::get(conn, id))
}
pub fn get_user(&self, conn: &Connection) -> Result<User> {
match self.get_post(conn) {
Ok(p) => Ok(p
.get_authors(conn)?
.into_iter()
.next()
.ok_or(Error::NotFound)?),
Err(_) => self.get_comment(conn).and_then(|c| c.get_author(conn)),
}
}
pub fn build_activity(conn: &DbConn, ment: &str) -> Result<link::Mention> {
let user = User::find_by_fqn(conn, ment)?;
let mut mention = link::Mention::default();
mention.link_props.set_href_string(user.ap_url)?;
mention.link_props.set_name_string(format!("@{}", ment))?;
Ok(mention)
}
pub fn to_activity(&self, conn: &Connection) -> Result<link::Mention> {
let user = self.get_mentioned(conn)?;
let mut mention = link::Mention::default();
mention.link_props.set_href_string(user.ap_url.clone())?;
mention
.link_props
.set_name_string(format!("@{}", user.fqn))?;
Ok(mention)
}
pub fn from_activity(
conn: &Connection,
ment: &link::Mention,
inside: i32,
in_post: bool,
notify: bool,
) -> Result<Self> {
let ap_url = ment.link_props.href_string().or(Err(Error::NotFound))?;
let mentioned = User::find_by_ap_url(conn, &ap_url)?;
if in_post {
Post::get(conn, inside).and_then(|post| {
let res = Mention::insert(
conn,
NewMention {
mentioned_id: mentioned.id,
post_id: Some(post.id),
comment_id: None,
},
)?;
if notify {
res.notify(conn)?;
}
Ok(res)
})
} else {
Comment::get(conn, inside).and_then(|comment| {
let res = Mention::insert(
conn,
NewMention {
mentioned_id: mentioned.id,
post_id: None,
comment_id: Some(comment.id),
},
)?;
if notify {
res.notify(conn)?;
}
Ok(res)
})
}
}
pub fn delete(&self, conn: &Connection) -> Result<()> {
//find related notifications and delete them
if let Ok(n) = Notification::find(conn, notification_kind::MENTION, self.id) {
n.delete(conn)?;
}
diesel::delete(self)
.execute(conn)
.map(|_| ())
.map_err(Error::from)
}
fn notify(&self, conn: &Connection) -> Result<()> {
let m = self.get_mentioned(conn)?;
if m.is_local() {
Notification::insert(
conn,
NewNotification {
kind: notification_kind::MENTION.to_string(),
object_id: self.id,
user_id: m.id,
},
)
.map(|_| ())
} else {
Ok(())
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::{inbox::tests::fill_database, tests::db, Error};
use assert_json_diff::assert_json_eq;
use diesel::Connection;
use serde_json::{json, to_value};
#[test]
fn build_activity() {
let conn = db();
conn.test_transaction::<_, Error, _>(|| {
let (_posts, users, _blogs) = fill_database(&conn);
let user = &users[0];
let name = &user.username;
let act = Mention::build_activity(&conn, name)?;
let expected = json!({
"href": "https://plu.me/@/admin/",
"name": "@admin",
"type": "Mention",
});
assert_json_eq!(to_value(act)?, expected);
Ok(())
});
}
#[test]
fn to_activity() {
let conn = db();
conn.test_transaction::<_, Error, _>(|| {
let (posts, users, _blogs) = fill_database(&conn);
let post = &posts[0];
let user = &users[0];
let mention = Mention::insert(
&conn,
NewMention {
mentioned_id: user.id,
post_id: Some(post.id),
comment_id: None,
},
)?;
let act = mention.to_activity(&conn)?;
let expected = json!({
"href": "https://plu.me/@/admin/",
"name": "@admin",
"type": "Mention",
});
assert_json_eq!(to_value(act)?, expected);
Ok(())
});
}
}