//! # Friends helper //! //! @author Pierre Hubert use crate::constants::database_tables_names::{FRIENDS_TABLE, USERS_TABLE}; use crate::data::error::{ExecError, ResultBoxError}; use crate::data::friend::Friend; use crate::data::friendship_status::FriendshipStatus; use crate::data::user::UserID; use crate::helpers::database; use crate::helpers::database::QueryInfo; /// Structure used to get a friend information pub struct GetFriendsQuery { only_accepted: bool, only_following: bool, only_followers: bool, target_user: UserID, friend_id: Option, common_with_user: Option, } impl GetFriendsQuery { /// Construct a new request pub fn new(target_user: &UserID) -> GetFriendsQuery { GetFriendsQuery { only_accepted: false, only_following: false, only_followers: false, target_user: target_user.clone(), friend_id: None, common_with_user: None, } } pub fn set_only_accepted(mut self, accepted: bool) -> GetFriendsQuery { self.only_accepted = accepted; 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> { get_list(&self) } /// Get information about a single friendship pub fn get_single_friend(mut self, friend_id: &UserID) -> ResultBoxError { self.friend_id = Some(friend_id.clone()); get_list(&self)? .pop() .ok_or(ExecError::boxed_new("Single friend not found!")) } } /// Get the list of friends of a user fn get_list(friend_query: &GetFriendsQuery) -> ResultBoxError> { let mut query = database::QueryInfo::new(FRIENDS_TABLE) .alias("f") .cond_user_id("ID_personne", &friend_query.target_user) .join(USERS_TABLE, "u", "f.ID_amis = u.ID") .add_field("u.last_activity") .add_field("f.ID_amis") .add_field("f.actif") .add_field("f.abonnement") .add_field("f.autoriser_post_page") .set_order("u.last_activity DESC"); if let Some(friend_id) = friend_query.friend_id.as_ref() { query = query.cond_user_id("ID_amis", friend_id); } if friend_query.only_accepted { query = query.cond_legacy_bool("f.actif", true); } if friend_query.only_following { 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) } /// get the list of friends that allows a given user to create posts on their page pub fn get_list_that_allow_posts_from_user(user_id: &UserID) -> ResultBoxError> { database::QueryInfo::new(FRIENDS_TABLE) .cond_legacy_bool("autoriser_post_page", true) .cond_legacy_bool("actif", true) .cond_user_id("ID_amis", user_id) .add_field("ID_personne as user_id") .exec(|r| r.get_user_id("user_id")) } /// Send a new friendship request pub fn send_request(user_id: &UserID, target_user: &UserID) -> ResultBoxError { database::InsertQuery::new(FRIENDS_TABLE) .add_user_id("ID_personne", target_user) .add_user_id("ID_amis", user_id) .add_legacy_bool("actif", false) .insert_drop_result() } /// Remove a friendship request pub fn remove_request(user_id: &UserID, target_user: &UserID) -> ResultBoxError { database::DeleteQuery::new(FRIENDS_TABLE) .cond_user_id("ID_personne", target_user) .cond_user_id("ID_amis", user_id) .cond_legacy_bool("actif", false) .exec() } /// Check out whether a user has sent a request to another user pub fn sent_request(user_id: &UserID, target_user: &UserID) -> ResultBoxError { database::QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", target_user) .cond_user_id("ID_amis", user_id) .cond_legacy_bool("actif", false) .exec_count() .map(|f| f > 0) } /// Respond to a friendship request pub fn respond_request(user_id: &UserID, friend_id: &UserID, accept: bool) -> ResultBoxError { // Delete the request remove_request(friend_id, user_id)?; if accept { database::InsertQuery::new(FRIENDS_TABLE) .add_user_id("ID_personne", user_id) .add_user_id("ID_amis", friend_id) .add_legacy_bool("actif", true) .insert_drop_result()?; database::InsertQuery::new(FRIENDS_TABLE) .add_user_id("ID_personne", friend_id) .add_user_id("ID_amis", user_id) .add_legacy_bool("actif", true) .insert_drop_result()?; } Ok(()) } /// Check out whether two users are friend or not pub fn are_friend(user_one: &UserID, user_two: &UserID) -> ResultBoxError { Ok(database::count(QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_one) .cond_user_id("ID_amis", user_two) .cond_i64("actif", 1))? > 0) } /// Delete a friendship pub fn remove_friendship(user_one: &UserID, user_two: &UserID) -> ResultBoxError { database::DeleteQuery::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_one) .cond_user_id("ID_amis", user_two) .exec()?; database::DeleteQuery::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_two) .cond_user_id("ID_amis", user_one) .exec()?; Ok(()) } /// Count the number of friends of a user pub fn count_friends(user_id: &UserID) -> ResultBoxError { QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_amis", user_id) .cond_u32("actif", 1) .exec_count() } /// Check if a user can create posts on another friend's page pub fn can_post_texts(user_id: &UserID, target_user: &UserID) -> ResultBoxError { QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", target_user) .cond_user_id("ID_amis", user_id) .add_field("autoriser_post_page") .query_row(|res| res.get_legacy_bool("autoriser_post_page")) .or(Ok(false)) } /// Check out whether a user is following another user or not pub fn is_following(user_id: &UserID, friend_id: &UserID) -> ResultBoxError { database::QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_id) .cond_user_id("ID_amis", friend_id) .cond_legacy_bool("actif", true) .cond_legacy_bool("abonnement", true) .exec_count() .map(|f| f > 0) } /// Update following status of a friendship pub fn set_following(user_id: &UserID, friend_id: &UserID, follow: bool) -> ResultBoxError { database::UpdateInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_id) .cond_user_id("ID_amis", friend_id) .set_legacy_bool("abonnement", follow) .exec() } /// Specify whether a friend is allowed to create posts on current user's page or not pub fn set_can_post_texts(user_id: &UserID, friend_id: &UserID, allow: bool) -> ResultBoxError { database::UpdateInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_id) .cond_user_id("ID_amis", friend_id) .set_legacy_bool("autoriser_post_page", allow) .exec() } /// Get the status of a friendship pub fn get_status(user_id: &UserID, friend_id: &UserID) -> ResultBoxError { let mut status = FriendshipStatus { are_friend: false, sent_request: false, received_request: false, following: false, }; status.are_friend = are_friend(user_id, friend_id)?; match status.are_friend { false => { status.sent_request = sent_request(user_id, friend_id)?; status.received_request = sent_request(friend_id, user_id)?; } true => { status.following = is_following(user_id, friend_id)?; } } Ok(status) } /// Count the number of friendship requests of a user pub fn count_requests(user_id: &UserID) -> ResultBoxError { database::QueryInfo::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_id) .cond_legacy_bool("actif", false) .exec_count() .map(|r| r as u64) } /// Delete all the friends of a given user pub fn delete_all_user(user_id: &UserID) -> ResultBoxError { database::DeleteQuery::new(FRIENDS_TABLE) .cond_user_id("ID_personne", user_id) .exec()?; database::DeleteQuery::new(FRIENDS_TABLE) .cond_user_id("ID_amis", user_id) .exec() } /// Turn a database entry into a Friend structure fn db_to_friend(row: &database::RowResult) -> ResultBoxError { Ok(Friend { friend_id: row.get_user_id("ID_amis")?, accepted: row.get_legacy_bool("actif")?, following: row.get_legacy_bool("abonnement")?, last_activity_time: row.get_u64("last_activity")?, can_post_texts: row.get_legacy_bool("autoriser_post_page")?, }) }