//! # Conversations helper //! //! @author Pierre Hubert use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_MESSAGES_TABLE, CONV_USERS_TABLE}; use crate::data::conversation::Conversation; use crate::data::conversation_message::ConversationMessage; use crate::data::error::{ExecError, ResultBoxError}; use crate::data::new_conversation::NewConversation; use crate::data::user::UserID; use crate::helpers::database; use crate::helpers::database::InsertQuery; use crate::utils::date_utils::time; /// Create a new conversation. This method returns the ID of the created conversation pub fn create(conv: &NewConversation) -> ResultBoxError { // Create the conversation in the main table let conv_id = InsertQuery::new(CONV_LIST_TABLE) .add_user_id("user_id", conv.owner_id) .add_str("name", conv.name.clone().unwrap_or(String::new()).as_str()) .add_u64("last_active", time()) .add_u64("creation_time", time()) .add_legacy_bool("can_everyone_add_members", conv.can_everyone_add_members) .insert()?.ok_or(ExecError::new("missing result conv id!"))?; // Add the members to the conversation for member in &conv.members { // Check following status of the member let mut follow = true; if member.eq(&conv.owner_id) { follow = conv.owner_following; } add_member(conv_id, member.clone(), follow)?; } Ok(conv_id) } /// Add a member to a conversation pub fn add_member(conv_id: u64, user_id: UserID, following: bool) -> ResultBoxError<()> { InsertQuery::new(CONV_USERS_TABLE) .add_u64("conv_id", conv_id) .add_user_id("user_id", user_id) .add_u64("time_add", time()) .add_legacy_bool("following", following) .add_legacy_bool("saw_last_message", true) .insert()?; Ok(()) } /// Remove a member from a conversation pub fn remove_member(conv_id: u64, user_id: UserID) -> ResultBoxError<()> { database::DeleteQuery::new(CONV_USERS_TABLE) .cond_u64("conv_id", conv_id) .cond_user_id("user_id", user_id) .exec() } /// Get the list of conversations of a specific user pub fn get_list_user(user_id: UserID) -> ResultBoxError> { database::QueryInfo::new(CONV_LIST_TABLE) .alias("l") // Join with conversation members table .join(CONV_USERS_TABLE, "u", "l.id = u.conv_id") // Specify selected fields .add_field("*") .add_field("l.id as id") .add_field("l.user_id as owner_id") // Filter query .cond_user_id("u.user_id", user_id) // Sort results .set_order("l.last_active DESC") // Execute query .exec(db_to_conversation_info) } /// Get information about a single conversation pub fn get_single(conv_id: u64, user_id: UserID) -> ResultBoxError { // Tables database::QueryInfo::new(CONV_LIST_TABLE) .alias("l") .join(CONV_USERS_TABLE, "u", "l.id = u.conv_id") // Fields .add_field("*") .add_field("l.id as id") .add_field("l.user_id as owner_id") // Conditions .cond_u64("l.id", conv_id) .cond_user_id("u.user_id", user_id) .query_row(db_to_conversation_info) } /// Get the list of members of a conversation pub fn get_list_members(conv_id: u64) -> ResultBoxError> { database::QueryInfo::new(CONV_USERS_TABLE) .cond_u64("conv_id", conv_id) .add_field("user_id") .exec(|res| res.get_user_id("user_id")) } /// Check if a user belongs to a conversation or not pub fn does_user_belongs_to(user_id: UserID, conv_id: u64) -> ResultBoxError { Ok(database::QueryInfo::new(CONV_USERS_TABLE) .cond_u64("conv_id", conv_id) .cond_user_id("user_id", user_id) .exec_count()? > 0) } /// Check out wheter a user is the moderator of a conversation or not pub fn is_user_moderator(user_id: UserID, conv_id: u64) -> ResultBoxError { Ok(database::QueryInfo::new(CONV_LIST_TABLE) .cond_u64("id", conv_id) .cond_user_id("user_id", user_id) .exec_count()? > 0) } /// Check out whether all the members of a conversation can add members to it or not pub fn can_everyone_add_members(conv_id: u64) -> ResultBoxError { database::QueryInfo::new(CONV_LIST_TABLE) .cond_u64("id", conv_id) .add_field("can_everyone_add_members") .query_row(|f| f.get_legacy_bool("can_everyone_add_members")) } /// Set whether a user is following a conversation or not pub fn set_following(user_id: UserID, conv_id: u64, following: bool) -> ResultBoxError<()> { database::UpdateInfo::new(CONV_USERS_TABLE) .cond_u64("conv_id", conv_id) .cond_user_id("user_id", user_id) .set_legacy_bool("following", following) .exec() } /// Set a new list of members for a given conversation pub fn set_members(conv_id: u64, new_list: &Vec, can_delete: bool) -> ResultBoxError<()> { let curr_list = get_list_members(conv_id)?; // Add new members for member in new_list { if curr_list.contains(member) { continue; } add_member(conv_id, member.clone(), true)?; } // Remove a member if can_delete { for member in curr_list { if new_list.contains(&member) { continue; } remove_member(conv_id, member)?; } } Ok(()) } /// Set a new name to the conversation pub fn set_name(conv_id: u64, name: Option) -> ResultBoxError<()> { database::UpdateInfo::new(CONV_LIST_TABLE) .cond_u64("id", conv_id) .set_opt_str("name", name) .exec() } /// Specify whether any member of this conversation can invite other users to join it pub fn set_can_everyone_add_members(conv_id: u64, allow: bool) -> ResultBoxError<()> { database::UpdateInfo::new(CONV_LIST_TABLE) .cond_u64("id", conv_id) .set_legacy_bool("can_everyone_add_members", allow) .exec() } /// Search for private conversation between two users pub fn find_private(user_1: UserID, user_2: UserID) -> ResultBoxError> { database::QueryInfo::new(CONV_USERS_TABLE) .alias("t1") // Join .join(CONV_USERS_TABLE, "t2", "t1.conv_id = t2.conv_id") // Conditions .cond_user_id("t1.user_id", user_1) .cond_user_id("t2.user_id", user_2) .set_custom_where(format!("(SELECT COUNT(*) FROM {} WHERE conv_id = t1.conv_id) = 2", CONV_USERS_TABLE).as_ref()) .add_field("t1.conv_id AS conv_id") .exec(|f| f.get_u64("conv_id")) } /// Get the last messages posted in a conversation pub fn get_last_messages(conv_id: u64, number_of_messages: u64) -> ResultBoxError> { database::QueryInfo::new(CONV_MESSAGES_TABLE) .cond_u64("conv_id", conv_id) .set_limit(number_of_messages) .set_order("id DESC") .exec(db_to_conversation_message) .map(|mut l| { l.sort_by(|a, b| a.id.partial_cmp(&b.id).unwrap()); l }) } /// Get the new messages of a conversation pub fn get_new_messages(conv_id: u64, last_message_id: u64) -> ResultBoxError> { database::QueryInfo::new(CONV_MESSAGES_TABLE) .cond_u64("conv_id", conv_id) .set_custom_where("id > ?") .add_custom_where_argument_u64(last_message_id) .set_order("id") .exec(db_to_conversation_message) } /// Indicate that a user has seen the last messages of a conversation pub fn mark_user_seen(conv_id: u64, user_id: UserID) -> ResultBoxError<()> { database::UpdateInfo::new(CONV_USERS_TABLE) .cond_u64("conv_id", conv_id) .cond_user_id("user_id", user_id) .cond_legacy_bool("saw_last_message", false) .set_legacy_bool("saw_last_message", true) .exec() } /// Turn a database entry into a ConversationInfo object fn db_to_conversation_info(row: &database::RowResult) -> ResultBoxError { let conv_id = row.get_u64("id")?; Ok(Conversation { id: conv_id, owner_id: row.get_user_id("owner_id")?, name: row.get_optional_str("name")?, members: get_list_members(conv_id)?, can_everyone_add_members: row.get_legacy_bool("can_everyone_add_members")?, last_active: row.get_u64("last_active")?, time_create: row.get_u64("time_add")?, following: row.get_legacy_bool("following")?, saw_last_message: row.get_legacy_bool("saw_last_message")?, }) } /// Turn a database entry into a ConversationMessgae object fn db_to_conversation_message(row: &database::RowResult) -> ResultBoxError { Ok(ConversationMessage { id: row.get_u64("id")?, time_sent: row.get_u64("time_insert")?, conv_id: row.get_u64("conv_id")?, user_id: row.get_user_id("user_id")?, message: row.get_optional_str("message")?, image_path: row.get_optional_str("image_path")?, }) }