179 lines
6.3 KiB
Rust
179 lines
6.3 KiB
Rust
use crate::{
|
|
comments::Comment,
|
|
follows::Follow,
|
|
likes::Like,
|
|
mentions::Mention,
|
|
posts::Post,
|
|
reshares::Reshare,
|
|
schema::{follows, notifications},
|
|
users::User,
|
|
Connection, Error, Result,
|
|
};
|
|
use chrono::NaiveDateTime;
|
|
use diesel::{self, ExpressionMethods, JoinOnDsl, QueryDsl, RunQueryDsl};
|
|
|
|
pub mod notification_kind {
|
|
pub const COMMENT: &str = "COMMENT";
|
|
pub const FOLLOW: &str = "FOLLOW";
|
|
pub const LIKE: &str = "LIKE";
|
|
pub const MENTION: &str = "MENTION";
|
|
pub const RESHARE: &str = "RESHARE";
|
|
}
|
|
|
|
#[derive(Clone, Queryable, Identifiable)]
|
|
pub struct Notification {
|
|
pub id: i32,
|
|
pub user_id: i32,
|
|
pub creation_date: NaiveDateTime,
|
|
pub kind: String,
|
|
pub object_id: i32,
|
|
}
|
|
|
|
#[derive(Insertable)]
|
|
#[table_name = "notifications"]
|
|
pub struct NewNotification {
|
|
pub user_id: i32,
|
|
pub kind: String,
|
|
pub object_id: i32,
|
|
}
|
|
|
|
impl Notification {
|
|
insert!(notifications, NewNotification);
|
|
get!(notifications);
|
|
|
|
pub fn find_for_user(conn: &Connection, user: &User) -> Result<Vec<Notification>> {
|
|
notifications::table
|
|
.filter(notifications::user_id.eq(user.id))
|
|
.order_by(notifications::creation_date.desc())
|
|
.load::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn find_for_mention(conn: &Connection, mention: &Mention) -> Result<Vec<Notification>> {
|
|
notifications::table
|
|
.filter(notifications::kind.eq(notification_kind::MENTION))
|
|
.filter(notifications::object_id.eq(mention.id))
|
|
.load::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn find_for_comment(conn: &Connection, comment: &Comment) -> Result<Vec<Notification>> {
|
|
notifications::table
|
|
.filter(notifications::kind.eq(notification_kind::COMMENT))
|
|
.filter(notifications::object_id.eq(comment.id))
|
|
.load::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn find_followed_by(conn: &Connection, user: &User) -> Result<Vec<Notification>> {
|
|
notifications::table
|
|
.inner_join(follows::table.on(notifications::object_id.eq(follows::id)))
|
|
.filter(notifications::kind.eq(notification_kind::FOLLOW))
|
|
.filter(follows::follower_id.eq(user.id))
|
|
.select(notifications::all_columns)
|
|
.load::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn count_for_user(conn: &Connection, user: &User) -> Result<i64> {
|
|
notifications::table
|
|
.filter(notifications::user_id.eq(user.id))
|
|
.count()
|
|
.get_result(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn page_for_user(
|
|
conn: &Connection,
|
|
user: &User,
|
|
(min, max): (i32, i32),
|
|
) -> Result<Vec<Notification>> {
|
|
notifications::table
|
|
.filter(notifications::user_id.eq(user.id))
|
|
.order_by(notifications::creation_date.desc())
|
|
.offset(min.into())
|
|
.limit((max - min).into())
|
|
.load::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn find<S: Into<String>>(conn: &Connection, kind: S, obj: i32) -> Result<Notification> {
|
|
notifications::table
|
|
.filter(notifications::kind.eq(kind.into()))
|
|
.filter(notifications::object_id.eq(obj))
|
|
.get_result::<Notification>(conn)
|
|
.map_err(Error::from)
|
|
}
|
|
|
|
pub fn get_url(&self, conn: &Connection) -> Option<String> {
|
|
match self.kind.as_ref() {
|
|
notification_kind::COMMENT => self
|
|
.get_post(conn)
|
|
.and_then(|p| Some(format!("{}#comment-{}", p.url(conn).ok()?, self.object_id))),
|
|
notification_kind::FOLLOW => Some(format!("/@/{}/", self.get_actor(conn).ok()?.fqn)),
|
|
notification_kind::MENTION => Mention::get(conn, self.object_id)
|
|
.and_then(|mention| {
|
|
mention
|
|
.get_post(conn)
|
|
.and_then(|p| p.url(conn))
|
|
.or_else(|_| {
|
|
let comment = mention.get_comment(conn)?;
|
|
Ok(format!(
|
|
"{}#comment-{}",
|
|
comment.get_post(conn)?.url(conn)?,
|
|
comment.id
|
|
))
|
|
})
|
|
})
|
|
.ok(),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn get_post(&self, conn: &Connection) -> Option<Post> {
|
|
match self.kind.as_ref() {
|
|
notification_kind::COMMENT => Comment::get(conn, self.object_id)
|
|
.and_then(|comment| comment.get_post(conn))
|
|
.ok(),
|
|
notification_kind::LIKE => Like::get(conn, self.object_id)
|
|
.and_then(|like| Post::get(conn, like.post_id))
|
|
.ok(),
|
|
notification_kind::RESHARE => Reshare::get(conn, self.object_id)
|
|
.and_then(|reshare| reshare.get_post(conn))
|
|
.ok(),
|
|
_ => None,
|
|
}
|
|
}
|
|
|
|
pub fn get_actor(&self, conn: &Connection) -> Result<User> {
|
|
Ok(match self.kind.as_ref() {
|
|
notification_kind::COMMENT => Comment::get(conn, self.object_id)?.get_author(conn)?,
|
|
notification_kind::FOLLOW => {
|
|
User::get(conn, Follow::get(conn, self.object_id)?.follower_id)?
|
|
}
|
|
notification_kind::LIKE => User::get(conn, Like::get(conn, self.object_id)?.user_id)?,
|
|
notification_kind::MENTION => Mention::get(conn, self.object_id)?.get_user(conn)?,
|
|
notification_kind::RESHARE => Reshare::get(conn, self.object_id)?.get_user(conn)?,
|
|
_ => unreachable!("Notification::get_actor: Unknow type"),
|
|
})
|
|
}
|
|
|
|
pub fn icon_class(&self) -> &'static str {
|
|
match self.kind.as_ref() {
|
|
notification_kind::COMMENT => "icon-message-circle",
|
|
notification_kind::FOLLOW => "icon-user-plus",
|
|
notification_kind::LIKE => "icon-heart",
|
|
notification_kind::MENTION => "icon-at-sign",
|
|
notification_kind::RESHARE => "icon-repeat",
|
|
_ => unreachable!("Notification::get_actor: Unknow type"),
|
|
}
|
|
}
|
|
|
|
pub fn delete(&self, conn: &Connection) -> Result<()> {
|
|
diesel::delete(self)
|
|
.execute(conn)
|
|
.map(|_| ())
|
|
.map_err(Error::from)
|
|
}
|
|
}
|