mirror of
				https://gitlab.com/comunic/comunicapiv3
				synced 2025-11-04 01:24:04 +00:00 
			
		
		
		
	Start to push notifications
This commit is contained in:
		@@ -8,8 +8,9 @@ use crate::constants::PATH_COMMENTS_IMAGES;
 | 
			
		||||
use crate::controllers::routes::RequestResult;
 | 
			
		||||
use crate::data::comment::Comment;
 | 
			
		||||
use crate::data::http_request_handler::HttpRequestHandler;
 | 
			
		||||
use crate::data::notification::NotifEventType;
 | 
			
		||||
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::string_utils::remove_html_nodes;
 | 
			
		||||
 | 
			
		||||
@@ -45,7 +46,9 @@ pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
 | 
			
		||||
 | 
			
		||||
    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
 | 
			
		||||
 | 
			
		||||
    r.set_response(ResCreateComment::new(comment_id))
 | 
			
		||||
 
 | 
			
		||||
@@ -211,6 +211,11 @@ impl PartialNotification {
 | 
			
		||||
        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 {
 | 
			
		||||
        self.dest_user_id = Some(id.clone());
 | 
			
		||||
        self
 | 
			
		||||
@@ -230,4 +235,9 @@ impl PartialNotification {
 | 
			
		||||
        self.on_elem_type = Some(t);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn set_type(mut self, t: NotifEventType) -> PartialNotification {
 | 
			
		||||
        self.kind = Some(t);
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@@ -153,6 +153,11 @@ impl Post {
 | 
			
		||||
            _ => 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)]
 | 
			
		||||
 
 | 
			
		||||
@@ -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
 | 
			
		||||
    pub fn add_str(mut self, key: &str, value: &str) -> InsertQuery {
 | 
			
		||||
        self.values.insert(key.to_string(), Value::from(value));
 | 
			
		||||
 
 | 
			
		||||
@@ -16,8 +16,10 @@ use crate::helpers::database::QueryInfo;
 | 
			
		||||
pub struct GetFriendsQuery {
 | 
			
		||||
    only_accepted: bool,
 | 
			
		||||
    only_following: bool,
 | 
			
		||||
    only_followers: bool,
 | 
			
		||||
    target_user: UserID,
 | 
			
		||||
    friend_id: Option<UserID>,
 | 
			
		||||
    common_with_user: Option<UserID>,
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl GetFriendsQuery {
 | 
			
		||||
@@ -26,8 +28,10 @@ impl GetFriendsQuery {
 | 
			
		||||
        GetFriendsQuery {
 | 
			
		||||
            only_accepted: false,
 | 
			
		||||
            only_following: false,
 | 
			
		||||
            only_followers: false,
 | 
			
		||||
            target_user: target_user.clone(),
 | 
			
		||||
            friend_id: None,
 | 
			
		||||
            common_with_user: None,
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -36,11 +40,24 @@ impl GetFriendsQuery {
 | 
			
		||||
        self
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Specify whether only the friends followed by friend_id should be selected
 | 
			
		||||
    pub fn set_only_following(mut self, following: bool) -> GetFriendsQuery {
 | 
			
		||||
        self.only_following = following;
 | 
			
		||||
        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
 | 
			
		||||
    pub fn exec(self) -> ResultBoxError<Vec<Friend>> {
 | 
			
		||||
        get_list(&self)
 | 
			
		||||
@@ -80,6 +97,26 @@ fn get_list(friend_query: &GetFriendsQuery) -> ResultBoxError<Vec<Friend>> {
 | 
			
		||||
        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)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -313,6 +313,15 @@ pub fn get_access_level(group_id: &GroupID, user_id: Option<UserID>) -> ResultBo
 | 
			
		||||
    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
 | 
			
		||||
pub fn count_members(group_id: &GroupID) -> ResultBoxError<usize> {
 | 
			
		||||
    database::QueryInfo::new(GROUPS_MEMBERS_TABLE)
 | 
			
		||||
 
 | 
			
		||||
@@ -8,8 +8,147 @@ use crate::constants::database_tables_names::NOTIFICATIONS_TABLE;
 | 
			
		||||
use crate::data::error::ResultBoxError;
 | 
			
		||||
use crate::data::group_id::GroupID;
 | 
			
		||||
use crate::data::notification::{NotifElemType, NotifEventType, NotifEventVisibility, Notification, PartialNotification};
 | 
			
		||||
use crate::data::post::{PostPageKind, PostVisibilityLevel};
 | 
			
		||||
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
 | 
			
		||||
pub fn delete(notification: &PartialNotification) -> ResultBoxError {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user