//! # Conversations controller //! //! @author Pierre Hubert use std::collections::HashMap; use crate::api_data::conversation_api::ConversationAPI; use crate::api_data::conversation_message_api::ConversationMessageAPI; use crate::api_data::conversations_refresh_api::ConversationRefreshResultAPI; use crate::api_data::list_unread_conversations_api::UnreadConversationAPI; use crate::api_data::res_count_unread_conversations::ResultCountUnreadConversations; use crate::api_data::res_create_conversation::ResCreateConversation; use crate::api_data::res_find_private_conversations::ResFindPrivateConversations; use crate::controllers::routes::RequestResult; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::new_conversation::NewConversation; use crate::data::new_conversation_message::NewConversationMessage; use crate::data::user::UserID; use crate::helpers::{conversations_helper, user_helper}; use crate::utils::string_utils::remove_html_nodes; /// Create a new conversation pub fn create(r: &mut HttpRequestHandler) -> RequestResult { let name = r.post_string("name")?; let mut members = r.post_numbers_list("users", 1)? .iter() .map(|f| UserID::new(f.clone())) .collect::>(); // Adapt name let name = match name.as_str() { "false" => None, s => Some(s.to_string()) }; // Check if members exists for user in &members { if !user_helper::exists(user)? { r.not_found(format!("User {} not found!", user.id()))?; } } // Add current user ID if required let curr_user_id = r.user_id()?; if !members.contains(&curr_user_id) { members.push(curr_user_id); } let conv = NewConversation { owner_id: r.user_id()?, name, owner_following: r.post_bool("follow")?, members, can_everyone_add_members: r.post_bool_opt("canEveryoneAddMembers", true), }; // Create the conversation let conv_id = conversations_helper::create(&conv)?; r.set_response(ResCreateConversation::new(conv_id)) } /// Get the list of conversations of a user pub fn get_list(r: &mut HttpRequestHandler) -> RequestResult { let list = conversations_helper::get_list_user(&r.user_id()?)?; r.set_response(list.iter().map(|c| ConversationAPI::new(c)).collect::>()) } /// Get information about a single conversation pub fn get_single(r: &mut HttpRequestHandler) -> RequestResult { let conversation_id = r.post_conv_id("conversationID")?; let conv = conversations_helper::get_single(conversation_id, &r.user_id()?)?; r.set_response(ConversationAPI::new(&conv)) } /// Update the settings of a conversation pub fn update_settings(r: &mut HttpRequestHandler) -> RequestResult { let conv_id = r.post_conv_id("conversationID")?; let is_moderator = conversations_helper::is_user_moderator(&r.user_id()?, conv_id)?; // Update following state, if required if r.has_post_parameter("following") { conversations_helper::set_following( &r.user_id()?, conv_id, r.post_bool("following")?, )?; } // Update members list if r.has_post_parameter("members") { let mut members = r.post_numbers_list("members", 1)? .iter() .map(|f| UserID::new(f.clone())) .collect::>(); let can_everyone_add_members = conversations_helper::can_everyone_add_members(conv_id)?; if !is_moderator && !can_everyone_add_members { r.forbidden("You can not update the list of members of this conversation!".to_string())?; } // Check if the members of the conversation really exists for member in &members { if !user_helper::exists(member)? { r.not_found(format!("User {} not found!", member.id()))?; } } if !members.contains(&r.user_id()?) { members.push(r.user_id()?); } conversations_helper::set_members(conv_id, &members, is_moderator)?; } // Change moderator settings if r.has_post_parameter("name") || r.has_post_parameter("canEveryoneAddMembers") { if !is_moderator { r.forbidden("You are not allowed to perform changes on this conversation!".to_string())?; } // Change conversation name if r.has_post_parameter("name") { let name = r.post_string_opt("name", 0, true)?; let name = if name.eq("false") || name.is_empty() { None } else { Some(remove_html_nodes(&name)) }; conversations_helper::set_name(conv_id, name)?; } // Change "canEveryoneAddMembers" parameter if r.has_post_parameter("canEveryoneAddMembers") { conversations_helper::set_can_everyone_add_members( conv_id, r.post_bool("canEveryoneAddMembers")?)?; } } r.success("Conversation information successfully updated!") } /// Find a private conversation pub fn find_private(r: &mut HttpRequestHandler) -> RequestResult { let other_user = r.post_user_id("otherUser")?; let allow_create = r.post_bool_opt("allowCreate", false); // Query the database let mut list = conversations_helper::find_private(&r.user_id()?, &other_user)?; if list.is_empty() { if !allow_create { return r.not_found(format!("Not any private conversation was found. The server was not allowed to create a new one...")); } let new_conv = NewConversation { owner_id: r.user_id()?, name: None, owner_following: true, members: vec![r.user_id()?, other_user], can_everyone_add_members: true, }; let conv_id = conversations_helper::create(&new_conv)?; list.push(conv_id); } r.set_response(ResFindPrivateConversations::new(list)) } /// DEPRECATED : refresh current user conversations /// /// This method was used only by ComunicWeb before the introduction of WebSockets pub fn refresh_list(r: &mut HttpRequestHandler) -> RequestResult { let mut list = HashMap::new(); // Check for new conversations if r.has_post_parameter("newConversations") { for conv_id in r.post_numbers_list("newConversations", 0)? { if !conversations_helper::does_user_belongs_to(&r.user_id()?, conv_id)? { r.forbidden(format!("Your do not belongs to conversation {} !", conv_id))?; } let list_conv = conversations_helper::get_last_messages(conv_id , 10)?; list.insert(conv_id as u64, list_conv); conversations_helper::mark_user_seen(conv_id as u64, &r.user_id()?)?; } } // Check for refresh of already initialized conversations if r.has_post_parameter("toRefresh") { let v: HashMap> = serde_json::from_str(r.post_string("toRefresh")?.as_str())?; for (k, v) in v { // Get conversation ID if !k.starts_with("conversation-") { return r.bad_request("Entries of 'toRefresh' must start with 'conversation-'!".to_string()); } let conv_id = k.replace("conversation-", "").parse::()?; // Extract last message id if !v.contains_key("last_message_id") { return r.bad_request(format!("Missing 'last_message_id' in conversation {}!", conv_id)); } let last_message_id = v["last_message_id"].as_u64().unwrap_or(0); // Check user rights if !conversations_helper::does_user_belongs_to(&r.user_id()?, conv_id)? { return r.forbidden(format!("You do not belong to conversation {}!", conv_id)); } let list_conv = conversations_helper::get_new_messages(conv_id, last_message_id)?; list.insert(conv_id, list_conv); conversations_helper::mark_user_seen(conv_id as u64, &r.user_id()?)?; } } r.set_response(ConversationRefreshResultAPI::new(list)) } /// Refresh a single conversation pub fn refresh_single(r: &mut HttpRequestHandler) -> RequestResult { let conv_id = r.post_conv_id("conversationID")?; let last_message_id = r.post_u64("last_message_id")?; let messages = match last_message_id { // Get latest messages of the conversation 0 => conversations_helper::get_last_messages(conv_id, 10)?, // Get new messages _ => conversations_helper::get_new_messages(conv_id, last_message_id)?, }; conversations_helper::mark_user_seen(conv_id, &r.user_id()?)?; r.set_response(ConversationMessageAPI::for_list(&messages)) } /// Get older messages of a conversation pub fn get_older_messages(r: &mut HttpRequestHandler) -> RequestResult { let conv_id = r.post_conv_id("conversationID")?; let max_id = r.post_u64("oldest_message_id")? - 1; // Determine limit let limit = r.post_u64("limit")?; let limit = match limit { 0 => 1, 1..=60 => limit, _ => 60 }; let messages = conversations_helper::get_older_messages(conv_id, max_id, limit)?; r.set_response(ConversationMessageAPI::for_list(&messages)) } /// Send a new message pub fn send_message(r: &mut HttpRequestHandler) -> RequestResult { let conv_id = r.post_conv_id("conversationID")?; let message = r.post_string_without_html("message", 0, false)?; // Get image let image_path = match r.has_file("image") { false => None, true => Some(r.save_post_image("image", "conversations", 1200, 1200)?) }; if image_path == None && message.len() < 3 { r.bad_request("Message is empty!".to_string())?; } conversations_helper::send_message(&NewConversationMessage { user_id: r.user_id()?, conv_id, message, image_path, })?; r.success("Conversation message was successfully sent!") } /// Count the number of unread conversation of the user pub fn count_unread(r: &mut HttpRequestHandler) -> RequestResult { let num = conversations_helper::count_unread_for_user(&r.user_id()?)?; r.set_response(ResultCountUnreadConversations::new(num)) } /// Get the list of unread conversations of a user pub fn list_unread(r: &mut HttpRequestHandler) -> RequestResult { let list = conversations_helper::get_list_unread(&r.user_id()?)?; r.set_response(UnreadConversationAPI::for_list(&list)) } /// Delete a conversation pub fn delete_conversation(r: &mut HttpRequestHandler) -> RequestResult { let conv_id = r.post_conv_id("conversationID")?; conversations_helper::remove_user_from_conversation(&r.user_id()?, conv_id)?; r.success("The conversation has been deleted") } /// Update a single conversation message pub fn update_message(r: &mut HttpRequestHandler) -> RequestResult { let msg_id = r.post_u64("messageID")?; let new_content = r.post_string_opt("content", 3, true)?; if !conversations_helper::is_message_owner(&r.user_id()?, msg_id)? { r.forbidden("You are not the owner of this message!".to_string())?; } conversations_helper::update_message_content(msg_id, &new_content)?; r.success("Conversation message content successfully updated") } /// Delete a conversation message pub fn delete_message(r: &mut HttpRequestHandler) -> RequestResult { let msg_id = r.post_u64("messageID")?; if !conversations_helper::is_message_owner(&r.user_id()?, msg_id)? { r.forbidden("You are not the owner of this message!".to_string())?; } conversations_helper::delete_message_by_id(msg_id)?; r.success("The message has been successfully deleted!") }