1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-29 16:56:28 +00:00

Start to push notifications

This commit is contained in:
Pierre HUBERT 2021-01-23 14:52:05 +01:00
parent 0e80564f85
commit 4d6ff8fef3
7 changed files with 213 additions and 3 deletions

View File

@ -8,8 +8,9 @@ use crate::constants::PATH_COMMENTS_IMAGES;
use crate::controllers::routes::RequestResult; use crate::controllers::routes::RequestResult;
use crate::data::comment::Comment; use crate::data::comment::Comment;
use crate::data::http_request_handler::HttpRequestHandler; use crate::data::http_request_handler::HttpRequestHandler;
use crate::data::notification::NotifEventType;
use crate::data::post::PostAccessLevel; use crate::data::post::PostAccessLevel;
use crate::helpers::{comments_helper, posts_helper}; use crate::helpers::{comments_helper, notifications_helper, posts_helper};
use crate::utils::date_utils::time; use crate::utils::date_utils::time;
use crate::utils::string_utils::remove_html_nodes; use crate::utils::string_utils::remove_html_nodes;
@ -45,7 +46,9 @@ pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
let comment_id = comments_helper::create(&comment)?; let comment_id = comments_helper::create(&comment)?;
// TODO : Create notifications // Create notifications
notifications_helper::create_post_notification(&r.user_id()?, post.id, NotifEventType::COMMENT_CREATED)?;
// TODO : Remove notifications targeting current user about the post // TODO : Remove notifications targeting current user about the post
r.set_response(ResCreateComment::new(comment_id)) r.set_response(ResCreateComment::new(comment_id))

View File

@ -211,6 +211,11 @@ impl PartialNotification {
self.id.is_some() self.id.is_some()
} }
pub fn set_time_create(mut self, time: u64) -> PartialNotification {
self.time_create = Some(time);
self
}
pub fn set_dest_user_id(mut self, id: &UserID) -> PartialNotification { pub fn set_dest_user_id(mut self, id: &UserID) -> PartialNotification {
self.dest_user_id = Some(id.clone()); self.dest_user_id = Some(id.clone());
self self
@ -230,4 +235,9 @@ impl PartialNotification {
self.on_elem_type = Some(t); self.on_elem_type = Some(t);
self self
} }
pub fn set_type(mut self, t: NotifEventType) -> PartialNotification {
self.kind = Some(t);
self
}
} }

View File

@ -153,6 +153,11 @@ impl Post {
_ => false, _ => false,
} }
} }
/// Check out whether a post is targeting a group page or not
pub fn is_on_group_page(&self) -> bool {
matches!(self.target_page, PostPageKind::PAGE_KIND_GROUP(_))
}
} }
#[cfg(test)] #[cfg(test)]

View File

@ -552,6 +552,13 @@ impl InsertQuery {
} }
} }
/// Add batch values
pub fn add_values(mut self, values: HashMap<String, mysql::Value>) -> Self {
self.values.extend(values.into_iter());
self
}
/// Add a string /// Add a string
pub fn add_str(mut self, key: &str, value: &str) -> InsertQuery { pub fn add_str(mut self, key: &str, value: &str) -> InsertQuery {
self.values.insert(key.to_string(), Value::from(value)); self.values.insert(key.to_string(), Value::from(value));

View File

@ -16,8 +16,10 @@ use crate::helpers::database::QueryInfo;
pub struct GetFriendsQuery { pub struct GetFriendsQuery {
only_accepted: bool, only_accepted: bool,
only_following: bool, only_following: bool,
only_followers: bool,
target_user: UserID, target_user: UserID,
friend_id: Option<UserID>, friend_id: Option<UserID>,
common_with_user: Option<UserID>,
} }
impl GetFriendsQuery { impl GetFriendsQuery {
@ -26,8 +28,10 @@ impl GetFriendsQuery {
GetFriendsQuery { GetFriendsQuery {
only_accepted: false, only_accepted: false,
only_following: false, only_following: false,
only_followers: false,
target_user: target_user.clone(), target_user: target_user.clone(),
friend_id: None, friend_id: None,
common_with_user: None,
} }
} }
@ -36,11 +40,24 @@ impl GetFriendsQuery {
self self
} }
/// Specify whether only the friends followed by friend_id should be selected
pub fn set_only_following(mut self, following: bool) -> GetFriendsQuery { pub fn set_only_following(mut self, following: bool) -> GetFriendsQuery {
self.only_following = following; self.only_following = following;
self self
} }
/// Specify whether only the friends following friend_id should be selected
pub fn set_only_followers(mut self, following: bool) -> GetFriendsQuery {
self.only_followers = following;
self
}
/// Specify whether all the returned friends should be common with a specified user
pub fn set_only_common_with(mut self, user: &UserID) -> GetFriendsQuery {
self.common_with_user = Some(user.clone());
self
}
/// Get the list of friends /// Get the list of friends
pub fn exec(self) -> ResultBoxError<Vec<Friend>> { pub fn exec(self) -> ResultBoxError<Vec<Friend>> {
get_list(&self) get_list(&self)
@ -80,6 +97,26 @@ fn get_list(friend_query: &GetFriendsQuery) -> ResultBoxError<Vec<Friend>> {
query = query.cond_legacy_bool("f.abonnement", true); query = query.cond_legacy_bool("f.abonnement", true);
} }
let mut custom_where = String::new();
if friend_query.only_followers {
custom_where = " EXISTS (SELECT * FROM amis d WHERE d.ID_personne = f.ID_amis AND d.ID_amis = f.ID_personne AND abonnement = 1) ".to_string();
}
if let Some(user_id) = &friend_query.common_with_user {
if !custom_where.is_empty() {
custom_where.push_str(" AND ");
}
custom_where.push_str(" (f.ID_amis = ? OR EXISTS (SELECT * FROM amis d WHERE d.ID_personne = ? AND d.ID_amis = f.ID_amis AND actif = 1) ) ");
query = query.add_custom_where_argument_user_id(user_id);
query = query.add_custom_where_argument_user_id(user_id);
}
if !custom_where.is_empty() {
query = query.set_custom_where(&custom_where);
}
query.exec(db_to_friend) query.exec(db_to_friend)
} }

View File

@ -313,6 +313,15 @@ pub fn get_access_level(group_id: &GroupID, user_id: Option<UserID>) -> ResultBo
Ok(GroupAccessLevel::NO_ACCESS) Ok(GroupAccessLevel::NO_ACCESS)
} }
/// Get the list of follower of a given group
pub fn get_list_followers(group_id: &GroupID) -> ResultBoxError<Vec<UserID>> {
database::QueryInfo::new(GROUPS_MEMBERS_TABLE)
.cond_group_id("groups_id", group_id)
.cond_legacy_bool("following", true)
.add_field("user_id")
.exec(|r| r.get_user_id("user_id"))
}
/// Count the number of members of a group /// Count the number of members of a group
pub fn count_members(group_id: &GroupID) -> ResultBoxError<usize> { pub fn count_members(group_id: &GroupID) -> ResultBoxError<usize> {
database::QueryInfo::new(GROUPS_MEMBERS_TABLE) database::QueryInfo::new(GROUPS_MEMBERS_TABLE)

View File

@ -8,8 +8,147 @@ use crate::constants::database_tables_names::NOTIFICATIONS_TABLE;
use crate::data::error::ResultBoxError; use crate::data::error::ResultBoxError;
use crate::data::group_id::GroupID; use crate::data::group_id::GroupID;
use crate::data::notification::{NotifElemType, NotifEventType, NotifEventVisibility, Notification, PartialNotification}; use crate::data::notification::{NotifElemType, NotifEventType, NotifEventVisibility, Notification, PartialNotification};
use crate::data::post::{PostPageKind, PostVisibilityLevel};
use crate::data::user::UserID; use crate::data::user::UserID;
use crate::helpers::database; use crate::helpers::{database, groups_helper, posts_helper};
use crate::helpers::friends_helper::GetFriendsQuery;
use crate::utils::date_utils;
/// Create post notification
pub fn create_post_notification(from_user: &UserID, post_id: u64, action: NotifEventType) -> ResultBoxError {
let mut n = PartialNotification::new()
.set_time_create(date_utils::time())
.set_from_user_id(from_user)
.set_on_elem_id(post_id)
.set_on_elem_type(NotifElemType::POST)
.set_type(action);
push(&mut n)
}
/// Push a new notification
pub fn push(n: &mut PartialNotification) -> ResultBoxError
{
if n.time_create.is_none()
{
n.time_create = Some(date_utils::time());
}
// Determine the visibility level of the notification
if matches!(n.on_elem_type, Some(NotifElemType::POST)) {
let post = posts_helper::get_single(n.on_elem_id.unwrap())?;
// Determine post container
match &post.target_page {
PostPageKind::PAGE_KIND_USER(user_id) => {
n.container_type = Some(NotifElemType::USER_PAGE);
n.container_id = Some(user_id.id());
}
PostPageKind::PAGE_KIND_GROUP(group_id) => {
n.container_type = Some(NotifElemType::GROUP_PAGE);
n.container_id = Some(group_id.id());
}
};
// Check the scope of the notification
// Private post (on user page)
if matches!(post.visibility, PostVisibilityLevel::VISIBILITY_USER) {
// Check if the post belongs to current user => no notification needed
if &post.user_id == post.user_page_id().unwrap() {
return Ok(());
}
// If the person who posted that is not the owner of the page
if post.user_page_id().unwrap() != n.from_user_id.as_ref().unwrap() {
n.dest_user_id = Some(post.user_page_id().unwrap().clone());
}
// If the user is the owner of the page, but the post does not belongs to him
else {
n.dest_user_id = Some(post.user_id);
}
return push_private(n);
}
// Posts on user page
else if post.is_on_user_page() {
let mut friend_req = GetFriendsQuery::new(n.from_user_id.as_ref().unwrap())
.set_only_followers(true);
// If the person who created the notification is not on his page
if n.from_user_id.as_ref().unwrap() != post.user_page_id().unwrap() {
friend_req = friend_req.set_only_common_with(post.user_page_id().unwrap())
}
let friends: Vec<UserID> = friend_req
.exec()?
.into_iter()
.map(|f| f.friend_id)
.collect();
return push_public(n, friends);
}
// Posts on group pages
else if post.is_on_group_page() {
return push_group_members(n, post.group_id().unwrap());
}
// Unsupported scenario
else {
unimplemented!();
}
} else {
unimplemented!();
}
}
/// Push a notification to group members
pub fn push_group_members(n: &mut PartialNotification, group_id: &GroupID) -> ResultBoxError {
let mut list = groups_helper::get_list_followers(group_id)?;
list = list.into_iter().filter(|f| f != n.from_user_id.as_ref().unwrap()).collect();
push_public(n, list)
}
/// Push a public notification
fn push_public(n: &mut PartialNotification, users: Vec<UserID>) -> ResultBoxError {
n.visibility = Some(NotifEventVisibility::EVENT_PUBLIC);
for user_id in users {
n.dest_user_id = Some(user_id);
if !similar_exists(n)? {
create(n)?;
}
}
Ok(())
}
/// Push a private notification (to 1 user)
fn push_private(n: &mut PartialNotification) -> ResultBoxError {
n.visibility = Some(NotifEventVisibility::EVENT_PRIVATE);
if !similar_exists(n)? {
create(n)?;
}
Ok(())
}
/// Create a new notification
fn create(n: &PartialNotification) -> ResultBoxError {
database::InsertQuery::new(NOTIFICATIONS_TABLE)
.add_values(notif_to_db(n, true))
.insert_drop_result()?;
// TODO : WebSocket : trigger notify system
Ok(())
}
/// Delete notifications /// Delete notifications
pub fn delete(notification: &PartialNotification) -> ResultBoxError { pub fn delete(notification: &PartialNotification) -> ResultBoxError {