mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-11-22 13:29:21 +00:00
Continue refactoring
This commit is contained in:
parent
2cc8984dfa
commit
fbf4728347
@ -53,7 +53,7 @@ impl AccountExportAPI {
|
||||
conversations_list: ConversationAPI::for_list(&export.conversations),
|
||||
conversations_messages: export.conversation_messages
|
||||
.iter()
|
||||
.map(|r| (r.0.clone(), ConversationMessageAPI::for_list(r.1)))
|
||||
.map(|r| (r.0.id(), ConversationMessageAPI::for_list(r.1)))
|
||||
.collect(),
|
||||
friends_list: FriendAPI::from_list(&export.friends_list),
|
||||
groups: export.groups
|
||||
|
@ -17,7 +17,7 @@ pub struct CallPeerInterruptedStreamingAPI {
|
||||
impl CallPeerInterruptedStreamingAPI {
|
||||
pub fn new(call_id: &ConvID, peer_id: &UserID) -> Self {
|
||||
Self {
|
||||
callID: call_id.clone(),
|
||||
callID: call_id.id(),
|
||||
peerID: peer_id.id(),
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,7 @@ pub struct CallPeerReadyAPI {
|
||||
impl CallPeerReadyAPI {
|
||||
pub fn new(call_id: &ConvID, user_id: &UserID) -> Self {
|
||||
Self {
|
||||
callID: call_id.clone(),
|
||||
callID: call_id.id(),
|
||||
peerID: user_id.id(),
|
||||
}
|
||||
}
|
||||
|
@ -1,54 +1,58 @@
|
||||
//! # Conversation API object
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::api_data::legacy_api_bool::LegacyBool;
|
||||
use crate::controllers::calls_controller;
|
||||
use crate::data::conversation::Conversation;
|
||||
use crate::data::conversation::{Conversation, ConversationMember};
|
||||
use crate::helpers::calls_helper;
|
||||
|
||||
/// Special implementation of conversation name (false if none / the name otherwise)
|
||||
struct ConvName(Option<String>);
|
||||
|
||||
impl Serialize for ConvName {
|
||||
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
|
||||
S: Serializer {
|
||||
match &self.0 {
|
||||
None => serializer.serialize_bool(false),
|
||||
Some(n) => serializer.serialize_str(n)
|
||||
}
|
||||
}
|
||||
#[derive(Serialize)]
|
||||
struct ConversationMembersAPI {
|
||||
user_id: u64,
|
||||
last_message_seen: u64,
|
||||
following: bool,
|
||||
is_admin: bool,
|
||||
}
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ConversationAPI {
|
||||
ID: u64,
|
||||
ID_owner: u64,
|
||||
last_active: u64,
|
||||
name: ConvName,
|
||||
following: LegacyBool,
|
||||
saw_last_message: LegacyBool,
|
||||
members: Vec<u64>,
|
||||
canEveryoneAddMembers: bool,
|
||||
id: u64,
|
||||
last_activity: u64,
|
||||
name: Option<String>,
|
||||
color: Option<String>,
|
||||
background: Option<String>,
|
||||
group_id: Option<u64>,
|
||||
members: Vec<ConversationMembersAPI>,
|
||||
can_everyone_add_members: bool,
|
||||
can_have_call: bool,
|
||||
can_have_video_call: bool,
|
||||
has_call_now: bool,
|
||||
}
|
||||
|
||||
impl ConversationMembersAPI {
|
||||
pub fn new(m: &ConversationMember) -> Self {
|
||||
Self {
|
||||
user_id: m.user_id.id(),
|
||||
last_message_seen: m.last_message_seen,
|
||||
following: m.following,
|
||||
is_admin: m.is_admin,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ConversationAPI {
|
||||
/// Construct a new Conversation instance
|
||||
pub fn new(conv: &Conversation) -> ConversationAPI {
|
||||
ConversationAPI {
|
||||
ID: conv.id,
|
||||
ID_owner: conv.owner_id.id(),
|
||||
last_active: conv.last_active,
|
||||
name: ConvName(conv.name.clone()),
|
||||
following: LegacyBool(conv.following),
|
||||
saw_last_message: LegacyBool(conv.saw_last_message),
|
||||
members: conv.members.iter().map(|x| x.id()).collect(),
|
||||
canEveryoneAddMembers: conv.can_everyone_add_members,
|
||||
id: conv.id.id(),
|
||||
last_activity: conv.last_activity,
|
||||
name: conv.name.clone(),
|
||||
members: conv.members.iter().map(ConversationMembersAPI::new).collect(),
|
||||
can_everyone_add_members: conv.can_everyone_add_members,
|
||||
color: conv.color.clone(),
|
||||
background: conv.background.clone(),
|
||||
group_id: conv.group_id.as_ref().map(|i| i.id()),
|
||||
|
||||
can_have_call: calls_helper::can_have_call(conv),
|
||||
can_have_video_call: calls_helper::can_have_video_calls(conv),
|
||||
|
@ -79,7 +79,7 @@ impl ConversationMessageAPI {
|
||||
|
||||
ConversationMessageAPI {
|
||||
id: msg.id,
|
||||
conv_id: msg.conv_id,
|
||||
conv_id: msg.conv_id.id(),
|
||||
user_id: msg.user_id.clone().map(|u| u.id()),
|
||||
time_insert: msg.time_sent,
|
||||
message: msg.message.clone(),
|
||||
|
@ -1,37 +0,0 @@
|
||||
//! # Conversation refresh result
|
||||
//!
|
||||
//! Note : this structure is now deprecated and should no longer be used for further developments
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::api_data::conversation_message_api::ConversationMessageAPI;
|
||||
use crate::data::conversation_message::ConversationMessage;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ConversationRefreshResultAPI {
|
||||
#[serde(flatten)]
|
||||
list: HashMap<String, Vec<ConversationMessageAPI>>,
|
||||
}
|
||||
|
||||
impl ConversationRefreshResultAPI {
|
||||
/// Create a new list
|
||||
pub fn new(list: HashMap<u64, Vec<ConversationMessage>>) -> ConversationRefreshResultAPI {
|
||||
let list = list
|
||||
.iter()
|
||||
.map(|v| (
|
||||
format!("conversation-{}", v.0),
|
||||
ConversationMessageAPI::for_list(v.1)
|
||||
))
|
||||
.collect();
|
||||
|
||||
ConversationRefreshResultAPI {
|
||||
list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub struct JoinedCallMessage {
|
||||
impl JoinedCallMessage {
|
||||
pub fn new(call_id: &ConvID, user_id: &UserID) -> Self {
|
||||
Self {
|
||||
callID: call_id.clone(),
|
||||
callID: call_id.id(),
|
||||
userID: user_id.id(),
|
||||
}
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ pub struct LeftCallMessage {
|
||||
impl LeftCallMessage {
|
||||
pub fn new(call_id: &ConvID, user_id: &UserID) -> Self {
|
||||
Self {
|
||||
callID: call_id.clone(),
|
||||
callID: call_id.id(),
|
||||
userID: user_id.id(),
|
||||
}
|
||||
}
|
||||
|
@ -21,7 +21,6 @@ pub mod conversation_api;
|
||||
mod legacy_api_bool;
|
||||
pub mod res_find_private_conversations;
|
||||
pub mod conversation_message_api;
|
||||
pub mod conversations_refresh_api;
|
||||
pub mod res_count_unread_conversations;
|
||||
pub mod list_unread_conversations_api;
|
||||
pub mod global_search_result_api;
|
||||
|
@ -19,7 +19,7 @@ pub struct NewCallSignalAPI {
|
||||
impl NewCallSignalAPI {
|
||||
pub fn new(call_id: &ConvID, peer_id: &UserID, data: &str) -> Res<Self> {
|
||||
Ok(Self {
|
||||
callID: call_id.clone(),
|
||||
callID: call_id.id(),
|
||||
peerID: peer_id.id(),
|
||||
data: serde_json::from_str(data)?,
|
||||
})
|
||||
|
@ -3,6 +3,7 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use serde::{Serialize};
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[allow(non_snake_case)]
|
||||
@ -13,9 +14,9 @@ pub struct ResCreateConversation {
|
||||
|
||||
impl ResCreateConversation {
|
||||
/// Construct a new Result instance
|
||||
pub fn new(conv_id: u64) -> ResCreateConversation {
|
||||
pub fn new(conv_id: ConvID) -> ResCreateConversation {
|
||||
ResCreateConversation {
|
||||
conversationID: conv_id,
|
||||
conversationID: conv_id.id(),
|
||||
success: "The conversation was successfully created!".to_string(),
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,8 @@
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
#[derive(Serialize)]
|
||||
#[allow(non_snake_case)]
|
||||
pub struct ResFindPrivateConversations {
|
||||
@ -12,9 +14,9 @@ pub struct ResFindPrivateConversations {
|
||||
|
||||
impl ResFindPrivateConversations {
|
||||
/// Construct a new instance of this structure
|
||||
pub fn new(list: Vec<u64>) -> ResFindPrivateConversations {
|
||||
pub fn new(list: Vec<ConvID>) -> ResFindPrivateConversations {
|
||||
ResFindPrivateConversations {
|
||||
conversationsID: list
|
||||
conversationsID: list.iter().map(|i| i.id()).collect()
|
||||
}
|
||||
}
|
||||
}
|
@ -36,7 +36,6 @@ pub mod database_tables_names {
|
||||
pub const CONV_LIST_TABLE: &str = "comunic_conversations_list";
|
||||
pub const CONV_MEMBERS_TABLE: &str = "comunic_conversations_members";
|
||||
pub const CONV_MESSAGES_TABLE: &str = "comunic_conversations_messages";
|
||||
pub const CONV_INFO_VIEW: &str = "comunic_conversations_info";
|
||||
|
||||
/// Posts table
|
||||
pub const POSTS_TABLE: &str = "texte";
|
||||
@ -163,4 +162,7 @@ pub const INITIAL_REFRESH_LOAD_INTERVAL: Duration = Duration::from_secs(5);
|
||||
pub const CLEAN_UP_INTERVAL: Duration = Duration::from_secs(60 * 60);
|
||||
|
||||
/// Minimal mobile version supported
|
||||
pub const MIN_SUPPORTED_MOBILE_VERSION: &str = "1.1.1";
|
||||
pub const MIN_SUPPORTED_MOBILE_VERSION: &str = "1.1.1";
|
||||
|
||||
/// Minimum message length
|
||||
pub const MIN_CONVERSATION_MESSAGE_LENGTH: usize = 1;
|
@ -13,7 +13,6 @@ use crate::api_data::joined_call_message::JoinedCallMessage;
|
||||
use crate::api_data::left_call_message::LeftCallMessage;
|
||||
use crate::api_data::new_call_signal::NewCallSignalAPI;
|
||||
use crate::api_data::user_calls_config::UserCallsConfig;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::call_signal::{CallSignal, CloseCallStream, IceCandidate, NewUserCallSignal, SdpType, UserCallOfferRequest};
|
||||
@ -27,11 +26,12 @@ use crate::data::user_ws_message::UserWsMessage;
|
||||
use crate::data::user_ws_request_handler::UserWsRequestHandler;
|
||||
use crate::helpers::{calls_helper, conversations_helper, events_helper};
|
||||
use crate::helpers::events_helper::Event;
|
||||
use crate::routes::RequestResult;
|
||||
|
||||
impl UserWsRequestHandler {
|
||||
/// Get the ID of a call included in a WebSocket request
|
||||
fn post_call_id(&mut self, name: &str) -> Res<ConvID> {
|
||||
let conv_id = self.post_u64(name)?;
|
||||
let conv_id = ConvID::new(self.post_u64(name)?);
|
||||
|
||||
if !self.get_conn().is_having_call_with_conversation(&conv_id) {
|
||||
self.forbidden("You do not belong to this call!".to_string())?;
|
||||
@ -125,7 +125,7 @@ pub fn is_conversation_having_call(conv_id: &ConvID) -> bool {
|
||||
});
|
||||
|
||||
if let Err(e) = res {
|
||||
eprintln!("Failed to check if a conversation is having call! Conversation: {} / Error: {:#?}", conv_id, e);
|
||||
eprintln!("Failed to check if a conversation is having call! Conversation: {} / Error: {:#?}", conv_id.id(), e);
|
||||
}
|
||||
|
||||
found
|
||||
@ -133,10 +133,10 @@ pub fn is_conversation_having_call(conv_id: &ConvID) -> bool {
|
||||
|
||||
/// Join a call
|
||||
pub fn join_call(r: &mut UserWsRequestHandler) -> RequestResult {
|
||||
let conv_id = r.post_conv_id("convID")?;
|
||||
let conv_id = r.post_conv("convID")?.conv_id;
|
||||
|
||||
// Check if the conversation can have a call
|
||||
let conv = conversations_helper::get_single(conv_id, r.user_id_ref()?)?;
|
||||
let conv = conversations_helper::get_single(conv_id)?;
|
||||
if !calls_helper::can_have_call(&conv) {
|
||||
r.forbidden("This conversation can not be used to make calls!".to_string())?;
|
||||
}
|
||||
@ -177,7 +177,7 @@ pub fn leave_call(r: &mut UserWsRequestHandler) -> RequestResult {
|
||||
// Warning ! For some technical reasons, we do not check if the user
|
||||
// really belongs to the conversation, so be careful when manipulating
|
||||
// conversation ID here
|
||||
let conv_id = r.post_u64("convID")?;
|
||||
let conv_id = ConvID::new(r.post_u64("convID")?);
|
||||
|
||||
// Check if the user was not in the conversation
|
||||
if !r.get_conn().is_having_call_with_conversation(&conv_id) {
|
||||
@ -208,7 +208,7 @@ pub fn get_members_list(r: &mut UserWsRequestHandler) -> RequestResult {
|
||||
|
||||
/// Get the hash associated to a call
|
||||
pub fn gen_call_hash(call_id: &ConvID, peer_id: &UserID) -> String {
|
||||
format!("{}-{}", call_id, peer_id.id())
|
||||
format!("{}-{}", call_id.id(), peer_id.id())
|
||||
}
|
||||
|
||||
/// Handles client signal
|
||||
@ -357,7 +357,7 @@ pub fn make_user_leave_call(conv_id: &ConvID, connection: &UserWsConnection) ->
|
||||
|
||||
// Notify user (if possible)
|
||||
if connection.session.connected() {
|
||||
user_ws_controller::send_to_client(connection, &UserWsMessage::no_id_message("call_closed", conv_id)?)?;
|
||||
user_ws_controller::send_to_client(connection, &UserWsMessage::no_id_message("call_closed", conv_id.id())?)?;
|
||||
}
|
||||
|
||||
// Close main stream (sender)
|
||||
@ -418,7 +418,7 @@ pub fn handle_event(e: &events_helper::Event) -> Res {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let call_id = split[0].parse::<u64>()?;
|
||||
let call_id = ConvID::new(split[0].parse::<u64>()?);
|
||||
let peer_id = UserID::new(split[1].parse::<u64>()?);
|
||||
|
||||
let target_user = UserID::new(msg.peer_id.parse::<u64>()?);
|
||||
|
@ -2,18 +2,18 @@
|
||||
//!
|
||||
//! @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::routes::RequestResult;
|
||||
use crate::constants::MIN_CONVERSATION_MESSAGE_LENGTH;
|
||||
use crate::controllers::user_ws_controller;
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::conversation::{ConversationMemberSetting, NewConversationSettings};
|
||||
use crate::data::conversation_message::ConversationMessageFile;
|
||||
use crate::data::error::Res;
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::new_conversation::NewConversation;
|
||||
@ -23,6 +23,7 @@ use crate::data::user_ws_connection::UserWsConnection;
|
||||
use crate::data::user_ws_message::UserWsMessage;
|
||||
use crate::helpers::{conversations_helper, events_helper, user_helper};
|
||||
use crate::helpers::events_helper::Event;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::utils::string_utils::remove_html_nodes;
|
||||
|
||||
/// Create a new conversation
|
||||
@ -58,6 +59,9 @@ pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
owner_following: r.post_bool("follow")?,
|
||||
members,
|
||||
can_everyone_add_members: r.post_bool_opt("canEveryoneAddMembers", true),
|
||||
color: r.post_color_opt("color")?,
|
||||
group_id: None,
|
||||
background: None,// TODO : add support for background
|
||||
};
|
||||
|
||||
// Create the conversation
|
||||
@ -74,77 +78,94 @@ pub fn get_list(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
|
||||
/// 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()?)?;
|
||||
let conv = r.post_conv("conversationID")?;
|
||||
let conv = conversations_helper::get_single(conv.conv_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)?;
|
||||
let conv_membership = r.post_conv("conversationID")?;
|
||||
let conv = conversations_helper::get_single(conv_membership.conv_id)?;
|
||||
|
||||
// Update following state, if required
|
||||
if r.has_post_parameter("following") {
|
||||
conversations_helper::set_following(
|
||||
&r.user_id()?,
|
||||
conv_id,
|
||||
conv_membership.member_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::<Vec<UserID>>();
|
||||
if r.has_post_parameter("members") && !conv.is_managed() {
|
||||
let mut members = r.post_users_id("members")?
|
||||
.into_iter()
|
||||
.map(|user_id| ConversationMemberSetting { user_id, set_admin: false })
|
||||
.collect::<Vec<ConversationMemberSetting>>();
|
||||
let admins = r.post_users_id("admins")?;
|
||||
|
||||
let can_everyone_add_members = conversations_helper::can_everyone_add_members(conv_id)?;
|
||||
let can_everyone_add_members = conversations_helper::can_everyone_add_members(conv_membership.conv_id)?;
|
||||
|
||||
if !is_moderator && !can_everyone_add_members {
|
||||
if !conv_membership.is_admin && !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()))?;
|
||||
}
|
||||
// Set same admin status as earlier
|
||||
if !conv_membership.is_admin {
|
||||
members = members
|
||||
.into_iter()
|
||||
.map(|mut n| {
|
||||
n.set_admin = conv.is_admin(&n.user_id);
|
||||
n
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
if !members.contains(&r.user_id()?) {
|
||||
members.push(r.user_id()?);
|
||||
// If the user is an admin, use the values he gave
|
||||
else {
|
||||
members = members
|
||||
.into_iter()
|
||||
.map(|mut n| {
|
||||
n.set_admin = admins.contains(&n.user_id);
|
||||
n
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
conversations_helper::set_members(conv_id, &members, is_moderator)?;
|
||||
// Current user can not touch his own membership, so revert it back forcefully
|
||||
members = members
|
||||
.into_iter()
|
||||
.filter(|m| !m.user_id.eq(&conv_membership.user_id))
|
||||
.collect::<Vec<ConversationMemberSetting>>();
|
||||
|
||||
members.push(ConversationMemberSetting {
|
||||
user_id: r.user_id()?,
|
||||
set_admin: conv_membership.is_admin,
|
||||
});
|
||||
|
||||
|
||||
conversations_helper::set_members(conv_membership.conv_id, &members, conv_membership.is_admin)?;
|
||||
}
|
||||
|
||||
// Change moderator settings
|
||||
if r.has_post_parameter("name") || r.has_post_parameter("canEveryoneAddMembers") {
|
||||
if !is_moderator {
|
||||
if r.has_post_parameter("name")
|
||||
&& r.has_post_parameter("canEveryoneAddMembers")
|
||||
&& r.has_post_parameter("color") {
|
||||
if !conv_membership.is_admin {
|
||||
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)?;
|
||||
}
|
||||
let new_settings = NewConversationSettings {
|
||||
conv_id: conv_membership.conv_id,
|
||||
name: r.post_string_optional("name").map(|s| remove_html_nodes(&s)),
|
||||
color: r.post_color_opt("color")?,
|
||||
can_everyone_add_members: r.post_bool("canEveryoneAddMembers")?,
|
||||
};
|
||||
|
||||
|
||||
// Change "canEveryoneAddMembers" parameter
|
||||
if r.has_post_parameter("canEveryoneAddMembers") {
|
||||
conversations_helper::set_can_everyone_add_members(
|
||||
conv_id, r.post_bool("canEveryoneAddMembers")?)?;
|
||||
}
|
||||
conversations_helper::set_settings(new_settings)?;
|
||||
}
|
||||
|
||||
r.success("Conversation information successfully updated!")
|
||||
@ -169,6 +190,9 @@ pub fn find_private(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
owner_following: true,
|
||||
members: vec![r.user_id()?, other_user],
|
||||
can_everyone_add_members: true,
|
||||
color: r.post_color_opt("color")?,
|
||||
background: None,
|
||||
group_id: None,
|
||||
};
|
||||
let conv_id = conversations_helper::create(&new_conv)?;
|
||||
list.push(conv_id);
|
||||
@ -177,80 +201,25 @@ pub fn find_private(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
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<String, HashMap<String, serde_json::Value>> =
|
||||
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::<u64>()?;
|
||||
|
||||
// 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 conv = r.post_conv("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)?,
|
||||
0 => conversations_helper::get_last_messages(conv.member_id, 10)?,
|
||||
|
||||
// Get new messages
|
||||
_ => conversations_helper::get_new_messages(conv_id, last_message_id)?,
|
||||
_ => conversations_helper::get_new_messages(conv.member_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 conv = r.post_conv("conversationID")?;
|
||||
let max_id = r.post_u64("oldest_message_id")? - 1;
|
||||
|
||||
// Determine limit
|
||||
@ -261,31 +230,44 @@ pub fn get_older_messages(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
_ => 60
|
||||
};
|
||||
|
||||
let messages = conversations_helper::get_older_messages(conv_id, max_id, limit)?;
|
||||
let messages = conversations_helper::get_older_messages(conv.member_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)?;
|
||||
let conv = r.post_conv("conversationID")?;
|
||||
|
||||
// TODO : add support for other files type
|
||||
|
||||
// Get image
|
||||
let image_path = match r.has_file("image") {
|
||||
let file = match r.has_file("image") {
|
||||
false => None,
|
||||
true => Some(r.save_post_image("image", "conversations", 1200, 1200)?)
|
||||
true => {
|
||||
let path = r.save_post_image("image", "conversations", 1200, 1200)?;
|
||||
Some(ConversationMessageFile {
|
||||
path: path.clone(),
|
||||
size: std::fs::metadata(&path)?.len(),
|
||||
name: "picture.png".to_string(),
|
||||
thumbnail: Some(r.save_post_image("image", "conversations", 50, 50)?),
|
||||
r#type: "image/png".to_string(),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
if image_path == None && message.len() < 3 {
|
||||
r.bad_request("Message is empty!".to_string())?;
|
||||
}
|
||||
let message = if let None = file {
|
||||
Some(r.post_string_without_html("message", MIN_CONVERSATION_MESSAGE_LENGTH, true)?)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
conversations_helper::send_message(&NewConversationMessage {
|
||||
user_id: r.user_id()?,
|
||||
conv_id,
|
||||
user_id: Some(r.user_id()?),
|
||||
conv_id: conv.conv_id,
|
||||
message,
|
||||
image_path,
|
||||
file,
|
||||
server_message: None,
|
||||
})?;
|
||||
|
||||
r.success("Conversation message was successfully sent!")
|
||||
@ -307,9 +289,14 @@ pub fn list_unread(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
|
||||
/// Delete a conversation
|
||||
pub fn delete_conversation(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let conv_id = r.post_conv_id("conversationID")?;
|
||||
let conv_membership = r.post_conv("conversationID")?;
|
||||
let conv = conversations_helper::get_single(conv_membership.conv_id)?;
|
||||
|
||||
conversations_helper::remove_user_from_conversation(&r.user_id()?, conv_id)?;
|
||||
if conv.is_managed() {
|
||||
r.bad_request("This conversation is managed, it can not be deleted by this way!".to_string())?;
|
||||
}
|
||||
|
||||
conversations_helper::remove_user_from_conversation(&r.user_id()?, &conv, r.user_id_ref()?)?;
|
||||
|
||||
r.success("The conversation has been deleted")
|
||||
}
|
||||
@ -362,7 +349,7 @@ pub fn handle_event(e: &events_helper::Event) -> Res {
|
||||
user_ws_controller::send_message_to_specific_connections(
|
||||
|f| f.conversations.contains(&msg.conv_id),
|
||||
|_| UserWsMessage::no_id_message("new_conv_message", ConversationMessageAPI::new(msg)),
|
||||
Some(|conn: &UserWsConnection| conversations_helper::mark_user_seen(msg.conv_id, conn.user_id())),
|
||||
Some(|conn: &UserWsConnection| conversations_helper::mark_user_seen(msg.conv_id, conn.user_id(), msg.id)),
|
||||
)?;
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@ use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::Res;
|
||||
use crate::data::post::PostAccessLevel;
|
||||
use crate::data::user_ws_request_handler::UserWsRequestHandler;
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
/// Update incognito status of the connection
|
||||
pub fn set_incognito(r: &mut UserWsRequestHandler) -> Res {
|
||||
@ -17,14 +18,14 @@ pub fn set_incognito(r: &mut UserWsRequestHandler) -> Res {
|
||||
|
||||
/// Register a conversation
|
||||
pub fn register_conv(r: &mut UserWsRequestHandler) -> Res {
|
||||
let conv_id = r.post_conv_id("convID")?;
|
||||
let conv_id = r.post_conv("convID")?.conv_id;
|
||||
r.update_conn(|c| { c.conversations.insert(conv_id); })?;
|
||||
r.success("ok")
|
||||
}
|
||||
|
||||
/// Un-register a conversation
|
||||
pub fn unregister_conv(r: &mut UserWsRequestHandler) -> Res {
|
||||
let conv_id = r.post_u64("convID")?;
|
||||
let conv_id = ConvID::new(r.post_u64("convID")?);
|
||||
r.update_conn(|c| { c.conversations.remove(&conv_id); })?;
|
||||
r.success("ok")
|
||||
}
|
||||
|
@ -5,7 +5,7 @@
|
||||
use std::collections::{HashMap, HashSet};
|
||||
|
||||
use crate::data::comment::Comment;
|
||||
use crate::data::conversation::Conversation;
|
||||
use crate::data::conversation::{Conversation, ConvID};
|
||||
use crate::data::conversation_message::ConversationMessage;
|
||||
use crate::data::error::ResultBoxError;
|
||||
use crate::data::friend::Friend;
|
||||
@ -24,7 +24,7 @@ pub struct AccountExport {
|
||||
pub survey_responses: Vec<SurveyResponse>,
|
||||
pub all_conversation_messages: Vec<ConversationMessage>,
|
||||
pub conversations: Vec<Conversation>,
|
||||
pub conversation_messages: HashMap<u64, Vec<ConversationMessage>>,
|
||||
pub conversation_messages: HashMap<ConvID, Vec<ConversationMessage>>,
|
||||
pub friends_list: Vec<Friend>,
|
||||
pub groups: Vec<GroupID>,
|
||||
}
|
||||
@ -56,7 +56,7 @@ impl AccountExport {
|
||||
|
||||
// Conversation members
|
||||
for conv in &self.conversations {
|
||||
conv.members.iter().for_each(|f| { set.insert(f.clone()); });
|
||||
conv.members_ids().into_iter().for_each(|f| { set.insert(f); });
|
||||
}
|
||||
|
||||
// Conversation messages
|
||||
|
@ -12,7 +12,7 @@ use serde::Serialize;
|
||||
use crate::api_data::http_error::HttpError;
|
||||
use crate::constants::PASSWORD_MIN_LENGTH;
|
||||
use crate::data::comment::Comment;
|
||||
use crate::data::conversation::ConvID;
|
||||
use crate::data::conversation::{ConversationMember, ConvID};
|
||||
use crate::data::custom_emoji::CustomEmoji;
|
||||
use crate::data::error::{ExecError, Res, ResultBoxError};
|
||||
use crate::data::group::GroupAccessLevel;
|
||||
@ -24,9 +24,10 @@ use crate::helpers::{account_helper, comments_helper, conversations_helper, cust
|
||||
use crate::helpers::virtual_directory_helper::VirtualDirType;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::utils::pdf_utils::is_valid_pdf;
|
||||
use crate::utils::string_utils::{check_emoji_code, check_string_before_insert, check_url, remove_html_nodes};
|
||||
use crate::utils::string_utils::{check_emoji_code, check_string_before_insert, check_url, remove_html_nodes, check_html_color};
|
||||
use crate::utils::user_data_utils::{generate_new_user_data_file_name, prepare_file_creation, user_data_path};
|
||||
use crate::utils::virtual_directories_utils;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Serialize)]
|
||||
struct SuccessMessage {
|
||||
@ -239,6 +240,18 @@ pub trait BaseRequestHandler {
|
||||
}
|
||||
}
|
||||
|
||||
/// Get a string included in the request. If none found, or if string is empty, returns [None]
|
||||
fn post_string_optional(&mut self, name: &str) -> Option<String> {
|
||||
match self.post_parameter_opt(name) {
|
||||
Some(RequestValue::String(s)) => {
|
||||
if s.is_empty() {
|
||||
None
|
||||
} else { Some(s.to_string()) }
|
||||
}
|
||||
_ => None
|
||||
}
|
||||
}
|
||||
|
||||
/// Check out whether a file was included in the request or not
|
||||
fn has_file(&self, name: &str) -> bool {
|
||||
self.post_parameter_opt(name)
|
||||
@ -420,6 +433,22 @@ pub trait BaseRequestHandler {
|
||||
Ok(user_id)
|
||||
}
|
||||
|
||||
/// Get a list of users ID included in the request
|
||||
fn post_users_id(&mut self, name: &str) -> ResultBoxError<HashSet<UserID>> {
|
||||
let users = self.post_numbers_list(name, 1)?
|
||||
.iter()
|
||||
.map(|u| UserID::new(u.clone()))
|
||||
.collect::<HashSet<UserID>>();
|
||||
|
||||
for user in &users {
|
||||
if !user_helper::exists(user)? {
|
||||
self.not_found(format!("User {} not found!", user.id()))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(users)
|
||||
}
|
||||
|
||||
/// Get the ID of a friend included in a POST request
|
||||
///
|
||||
/// *Note :* This function does not check whether the user exists or not before checking if the
|
||||
@ -461,14 +490,14 @@ pub trait BaseRequestHandler {
|
||||
}
|
||||
|
||||
/// Get & return the ID of the conversation included in the POST request
|
||||
fn post_conv_id(&mut self, name: &str) -> ResultBoxError<ConvID> {
|
||||
let conv_id = self.post_u64(name)?;
|
||||
fn post_conv(&mut self, name: &str) -> ResultBoxError<ConversationMember> {
|
||||
let conv_id = ConvID::new(self.post_u64(name)?);
|
||||
let membership = self.ok_or_forbidden(
|
||||
conversations_helper::get_user_membership(&self.user_id()?, conv_id),
|
||||
&format!("You do not belong to conversation {} !", conv_id.id()),
|
||||
)?;
|
||||
|
||||
if !conversations_helper::does_user_belongs_to(&self.user_id()?, conv_id)? {
|
||||
self.forbidden(format!("You do not belong to conversation {} !", conv_id))?;
|
||||
}
|
||||
|
||||
Ok(conv_id)
|
||||
Ok(membership)
|
||||
}
|
||||
|
||||
/// Get the ID
|
||||
@ -624,4 +653,20 @@ pub trait BaseRequestHandler {
|
||||
|
||||
Ok(info)
|
||||
}
|
||||
|
||||
/// Get a color included in the request
|
||||
fn post_color_opt(&mut self, field: &str) -> Res<Option<String>> {
|
||||
let color = self.post_string_optional(field);
|
||||
|
||||
match color {
|
||||
None => Ok(None),
|
||||
Some(color) => {
|
||||
if !check_html_color(&color) {
|
||||
self.bad_request(format!("Invalid color specified in '{}' !", field))?;
|
||||
}
|
||||
|
||||
Ok(Some(color))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -2,20 +2,94 @@
|
||||
//!
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::user::UserID;
|
||||
|
||||
pub type ConvID = u64;
|
||||
#[derive(Copy, Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub struct ConvID(u64);
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
impl ConvID {
|
||||
pub fn new(id: u64) -> Self {
|
||||
ConvID(id)
|
||||
}
|
||||
|
||||
pub fn id(&self) -> u64 {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct ConversationMember {
|
||||
pub member_id: u64,
|
||||
pub conv_id: ConvID,
|
||||
pub user_id: UserID,
|
||||
pub added_on: u64,
|
||||
pub following: bool,
|
||||
pub is_admin: bool,
|
||||
pub last_message_seen: u64,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct Conversation {
|
||||
pub id: ConvID,
|
||||
pub owner_id: UserID,
|
||||
pub name: Option<String>,
|
||||
pub members: Vec<UserID>,
|
||||
pub color: Option<String>,
|
||||
pub background: Option<String>,
|
||||
pub creation_time: u64,
|
||||
pub group_id: Option<GroupID>,
|
||||
pub can_everyone_add_members: bool,
|
||||
pub last_active: u64,
|
||||
pub time_create: u64,
|
||||
pub last_activity: u64,
|
||||
pub members: Vec<ConversationMember>,
|
||||
}
|
||||
|
||||
pub following: bool,
|
||||
pub saw_last_message: bool,
|
||||
impl PartialEq for Conversation {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id.eq(&other.id)
|
||||
}
|
||||
}
|
||||
|
||||
impl Eq for Conversation {}
|
||||
|
||||
impl Conversation {
|
||||
/// Get the IDs of the members in the conversation
|
||||
pub fn members_ids(&self) -> Vec<UserID> {
|
||||
self.members.iter().map(|m| m.user_id.clone()).collect()
|
||||
}
|
||||
|
||||
/// Check out whether this conversation is managed or not
|
||||
pub fn is_managed(&self) -> bool {
|
||||
self.group_id.is_some()
|
||||
}
|
||||
|
||||
/// Check out whether a given user is an admin of a conversation or not
|
||||
pub fn is_admin(&self, user_id: &UserID) -> bool {
|
||||
self
|
||||
.members
|
||||
.iter()
|
||||
.any(|m| m.user_id == user_id && m.is_admin)
|
||||
}
|
||||
|
||||
/// Check out whether a user is the last administrator of a conversation or not
|
||||
pub fn is_last_admin(&self, user_id: &UserID) -> bool {
|
||||
let admins: Vec<&ConversationMember> = self.members
|
||||
.iter()
|
||||
.filter(|m| m.is_admin)
|
||||
.collect();
|
||||
|
||||
admins.len() == 1 && admins[0].user_id == user_id
|
||||
}
|
||||
}
|
||||
|
||||
/// Structure used to update the list of members of the conversation
|
||||
pub struct ConversationMemberSetting {
|
||||
pub user_id: UserID,
|
||||
pub set_admin: bool,
|
||||
}
|
||||
|
||||
/// Structure used to update conversation settings
|
||||
pub struct NewConversationSettings {
|
||||
pub conv_id: ConvID,
|
||||
pub color: Option<String>,
|
||||
pub name: Option<String>,
|
||||
pub can_everyone_add_members: bool,
|
||||
}
|
@ -6,6 +6,7 @@ use std::collections::HashSet;
|
||||
|
||||
use crate::data::error::{ExecError, Res};
|
||||
use crate::data::user::UserID;
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
pub type ConvMessageID = u64;
|
||||
|
||||
@ -101,7 +102,7 @@ impl ConversationServerMessageType {
|
||||
pub struct ConversationMessage {
|
||||
pub id: ConvMessageID,
|
||||
pub time_sent: u64,
|
||||
pub conv_id: u64,
|
||||
pub conv_id: ConvID,
|
||||
pub user_id: Option<UserID>,
|
||||
pub message: Option<String>,
|
||||
pub server_message: Option<ConversationServerMessageType>,
|
||||
|
@ -3,11 +3,15 @@
|
||||
//! @author Pierre Huber
|
||||
|
||||
use crate::data::user::UserID;
|
||||
use crate::data::group_id::GroupID;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct NewConversation {
|
||||
pub owner_id: UserID,
|
||||
pub name: Option<String>,
|
||||
pub group_id: Option<GroupID>,
|
||||
pub color: Option<String>,
|
||||
pub background: Option<String>,
|
||||
pub owner_following: bool,
|
||||
pub members: Vec<UserID>,
|
||||
pub can_everyone_add_members: bool
|
||||
|
@ -3,11 +3,14 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::data::user::UserID;
|
||||
use crate::data::conversation::ConvID;
|
||||
use crate::data::conversation_message::{ConversationMessageFile, ConversationServerMessageType};
|
||||
|
||||
/// Information about a new conversation message
|
||||
pub struct NewConversationMessage {
|
||||
pub user_id: UserID,
|
||||
pub conv_id: u64,
|
||||
pub message: String,
|
||||
pub image_path: Option<String>
|
||||
pub user_id: Option<UserID>,
|
||||
pub conv_id: ConvID,
|
||||
pub message: Option<String>,
|
||||
pub file: Option<ConversationMessageFile>,
|
||||
pub server_message: Option<ConversationServerMessageType>
|
||||
}
|
@ -20,7 +20,7 @@ impl UserMembership {
|
||||
match self {
|
||||
UserMembership::Group(_, last_active) => *last_active,
|
||||
UserMembership::Friend(f) => f.last_activity_time,
|
||||
UserMembership::Conversation(c) => c.last_active,
|
||||
UserMembership::Conversation(c) => c.last_activity,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,7 +3,7 @@
|
||||
//! @author Pierre Hubert
|
||||
|
||||
use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_MEMBERS_TABLE, CONV_MESSAGES_TABLE};
|
||||
use crate::data::conversation::Conversation;
|
||||
use crate::data::conversation::{Conversation, ConversationMember, ConversationMemberSetting, ConvID, NewConversationSettings};
|
||||
use crate::data::conversation_message::{ConversationMessage, ConversationMessageFile, ConversationServerMessageType};
|
||||
use crate::data::error::{ExecError, Res, ResultBoxError};
|
||||
use crate::data::new_conversation::NewConversation;
|
||||
@ -11,57 +11,81 @@ use crate::data::new_conversation_message::NewConversationMessage;
|
||||
use crate::data::unread_conversation::UnreadConversation;
|
||||
use crate::data::user::{User, UserID};
|
||||
use crate::helpers::{database, events_helper};
|
||||
use crate::helpers::database::InsertQuery;
|
||||
use crate::helpers::database::{InsertQuery, UpdateInfo};
|
||||
use crate::helpers::events_helper::Event;
|
||||
use crate::utils::date_utils::time;
|
||||
use crate::utils::user_data_utils::delete_user_data_file_if_exists;
|
||||
|
||||
/// Create a new conversation. This method returns the ID of the created conversation
|
||||
pub fn create(conv: &NewConversation) -> ResultBoxError<u64> {
|
||||
pub fn create(conv: &NewConversation) -> Res<ConvID> {
|
||||
// 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("last_activity", time())
|
||||
.add_u64("creation_time", time())
|
||||
.add_opt_str("color", Option::from(&conv.color))
|
||||
.add_opt_str("background", Option::from(&conv.background))
|
||||
.add_legacy_bool("can_everyone_add_members", conv.can_everyone_add_members)
|
||||
.insert()?.ok_or(ExecError::new("missing result conv id!"))?;
|
||||
.add_opt_group_id("group_id", conv.group_id.clone())
|
||||
.insert()?
|
||||
.map(|i| ConvID::new(i))
|
||||
.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;
|
||||
let mut admin = false;
|
||||
if member.eq(&conv.owner_id) {
|
||||
follow = conv.owner_following;
|
||||
admin = true;
|
||||
}
|
||||
|
||||
add_member(conv_id, member, follow)?;
|
||||
add_member(conv_id, member, follow, admin)?;
|
||||
}
|
||||
|
||||
Ok(conv_id)
|
||||
}
|
||||
|
||||
/// Add a member to a conversation
|
||||
pub fn add_member(conv_id: u64, user_id: &UserID, following: bool) -> ResultBoxError<()> {
|
||||
pub fn add_member(conv_id: ConvID, user_id: &UserID, following: bool, admin: bool) -> Res {
|
||||
InsertQuery::new(CONV_MEMBERS_TABLE)
|
||||
.add_u64("conv_id", conv_id)
|
||||
.add_conv_id("conv_id", conv_id)
|
||||
.add_user_id("user_id", user_id)
|
||||
.add_u64("time_add", time())
|
||||
.add_u64("added_on", time())
|
||||
.add_legacy_bool("following", following)
|
||||
.add_legacy_bool("saw_last_message", true)
|
||||
.add_legacy_bool("is_admin", admin)
|
||||
.add_u64("last_message_seen", 0)
|
||||
.insert()?;
|
||||
|
||||
// TODO : create a message
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove a member from a conversation
|
||||
pub fn remove_member(conv_id: u64, user_id: &UserID) -> ResultBoxError<()> {
|
||||
database::DeleteQuery::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
/// Update admin status of a member for a conversation
|
||||
pub fn set_admin(conv_id: &ConvID, user_id: &UserID, admin: bool) -> Res {
|
||||
UpdateInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_user_id("user_id", user_id)
|
||||
.cond_conv_id("conv_id", conv_id.clone())
|
||||
.set_legacy_bool("is_admin", admin)
|
||||
.exec()
|
||||
}
|
||||
|
||||
/// Remove a member from a conversation
|
||||
pub fn remove_member(conv_id: ConvID, user_id: &UserID) -> ResultBoxError<()> {
|
||||
database::DeleteQuery::new(CONV_MEMBERS_TABLE)
|
||||
.cond_conv_id("conv_id", conv_id)
|
||||
.cond_user_id("user_id", user_id)
|
||||
.exec()?;
|
||||
|
||||
// TODO : create a message
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the list of conversations of a specific user
|
||||
pub fn get_list_user(user_id: &UserID) -> ResultBoxError<Vec<Conversation>> {
|
||||
database::QueryInfo::new(CONV_LIST_TABLE)
|
||||
@ -71,67 +95,46 @@ pub fn get_list_user(user_id: &UserID) -> ResultBoxError<Vec<Conversation>> {
|
||||
.join(CONV_MEMBERS_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")
|
||||
.add_field("l.*")
|
||||
|
||||
// Filter query
|
||||
.cond_user_id("u.user_id", user_id)
|
||||
|
||||
// Sort results
|
||||
.set_order("l.last_active DESC")
|
||||
.set_order("l.last_activity 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<Conversation> {
|
||||
pub fn get_single(conv_id: ConvID) -> ResultBoxError<Conversation> {
|
||||
// Tables
|
||||
database::QueryInfo::new(CONV_LIST_TABLE)
|
||||
.alias("l")
|
||||
.join(CONV_MEMBERS_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)
|
||||
|
||||
.cond_conv_id("id", conv_id)
|
||||
.query_row(db_to_conversation_info)
|
||||
}
|
||||
|
||||
/// Get the list of members of a conversation
|
||||
pub fn get_list_members(conv_id: u64) -> ResultBoxError<Vec<UserID>> {
|
||||
pub fn get_list_members(conv_id: ConvID) -> Res<Vec<ConversationMember>> {
|
||||
database::QueryInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
.add_field("user_id")
|
||||
.exec(|res| res.get_user_id("user_id"))
|
||||
.cond_conv_id("conv_id", conv_id)
|
||||
.exec(db_to_conversation_member)
|
||||
}
|
||||
|
||||
/// Check if a user belongs to a conversation or not
|
||||
pub fn does_user_belongs_to(user_id: &UserID, conv_id: u64) -> ResultBoxError<bool> {
|
||||
Ok(database::QueryInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
pub fn get_user_membership(user_id: &UserID, conv_id: ConvID) -> Res<ConversationMember> {
|
||||
database::QueryInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_conv_id("conv_id", conv_id)
|
||||
.cond_user_id("user_id", user_id)
|
||||
.exec_count()? > 0)
|
||||
.query_row(db_to_conversation_member)
|
||||
}
|
||||
|
||||
/// 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<bool> {
|
||||
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<bool> {
|
||||
pub fn can_everyone_add_members(conv_id: ConvID) -> ResultBoxError<bool> {
|
||||
database::QueryInfo::new(CONV_LIST_TABLE)
|
||||
.cond_u64("id", conv_id)
|
||||
.cond_conv_id("id", conv_id)
|
||||
.add_field("can_everyone_add_members")
|
||||
.query_row(|f| f.get_legacy_bool("can_everyone_add_members"))
|
||||
}
|
||||
@ -146,25 +149,28 @@ pub fn set_following(user_id: &UserID, conv_id: u64, following: bool) -> ResultB
|
||||
}
|
||||
|
||||
/// Set a new list of members for a given conversation
|
||||
pub fn set_members(conv_id: u64, new_list: &Vec<UserID>, can_delete: bool) -> ResultBoxError<()> {
|
||||
pub fn set_members(conv_id: ConvID, new_list: &Vec<ConversationMemberSetting>, 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;
|
||||
if let Some(user) = curr_list.iter().filter(|m| m.user_id == member.user_id).next() {
|
||||
// Check if we have to update admin state
|
||||
if user.is_admin != member.set_admin {
|
||||
set_admin(&conv_id, &member.user_id, member.set_admin)?;
|
||||
}
|
||||
} else {
|
||||
add_member(conv_id, &member.user_id, true, member.set_admin)?;
|
||||
}
|
||||
|
||||
add_member(conv_id, member, true)?;
|
||||
}
|
||||
|
||||
// Remove a member
|
||||
if can_delete {
|
||||
for member in curr_list {
|
||||
if new_list.contains(&member) {
|
||||
if new_list.iter().any(|m| m.user_id.eq(&member.user_id)) {
|
||||
continue;
|
||||
}
|
||||
remove_member(conv_id, &member)?;
|
||||
remove_member(conv_id, &member.user_id)?;
|
||||
}
|
||||
}
|
||||
|
||||
@ -173,23 +179,17 @@ pub fn set_members(conv_id: u64, new_list: &Vec<UserID>, can_delete: bool) -> Re
|
||||
}
|
||||
|
||||
/// Set a new name to the conversation
|
||||
pub fn set_name(conv_id: u64, name: Option<String>) -> ResultBoxError<()> {
|
||||
pub fn set_settings(settings: NewConversationSettings) -> Res {
|
||||
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)
|
||||
.cond_conv_id("id", settings.conv_id)
|
||||
.set_opt_str("name", settings.name)
|
||||
.set_opt_str("color", settings.color)
|
||||
.set_legacy_bool("can_everyone_add_members", settings.can_everyone_add_members)
|
||||
.exec()
|
||||
}
|
||||
|
||||
/// Search for private conversation between two users
|
||||
pub fn find_private(user_1: &UserID, user_2: &UserID) -> ResultBoxError<Vec<u64>> {
|
||||
pub fn find_private(user_1: &UserID, user_2: &UserID) -> ResultBoxError<Vec<ConvID>> {
|
||||
database::QueryInfo::new(CONV_MEMBERS_TABLE)
|
||||
.alias("t1")
|
||||
|
||||
@ -201,7 +201,7 @@ pub fn find_private(user_1: &UserID, user_2: &UserID) -> ResultBoxError<Vec<u64>
|
||||
.cond_user_id("t2.user_id", user_2)
|
||||
.set_custom_where(format!("(SELECT COUNT(*) FROM {} WHERE conv_id = t1.conv_id) = 2", CONV_MEMBERS_TABLE).as_ref())
|
||||
.add_field("t1.conv_id AS conv_id")
|
||||
.exec(|f| f.get_u64("conv_id"))
|
||||
.exec(|f| f.get_conv_id("conv_id"))
|
||||
}
|
||||
|
||||
/// Get the last messages posted in a conversation
|
||||
@ -247,9 +247,9 @@ pub fn get_older_messages(conv_id: u64, start_id: u64, limit: u64) -> ResultBoxE
|
||||
}
|
||||
|
||||
/// Get all the messages of a single user for a conversation
|
||||
pub fn get_user_messages_for_conversations(conv_id: u64, user_id: &UserID) -> ResultBoxError<Vec<ConversationMessage>> {
|
||||
pub fn get_user_messages_for_conversations(conv_id: ConvID, user_id: &UserID) -> ResultBoxError<Vec<ConversationMessage>> {
|
||||
database::QueryInfo::new(CONV_MESSAGES_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
.cond_conv_id("conv_id", conv_id)
|
||||
.cond_user_id("user_id", user_id)
|
||||
.exec(db_to_conversation_message)
|
||||
}
|
||||
@ -293,16 +293,16 @@ pub fn delete_all_user_messages(user_id: &UserID) -> ResultBoxError {
|
||||
/// Remove the user from all the conversations he belongs to
|
||||
pub fn delete_all_user_conversations(user_id: &UserID) -> ResultBoxError {
|
||||
for conversation in &get_list_user(user_id)? {
|
||||
remove_user_from_conversation(user_id, conversation.id)?;
|
||||
remove_user_from_conversation(user_id, conversation, user_id)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Get the entire list of messages of a given conversation
|
||||
pub fn get_all_messages(conv_id: u64) -> ResultBoxError<Vec<ConversationMessage>> {
|
||||
pub fn get_all_messages(conv_id: ConvID) -> ResultBoxError<Vec<ConversationMessage>> {
|
||||
database::QueryInfo::new(CONV_MESSAGES_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
.cond_conv_id("conv_id", conv_id)
|
||||
.exec(db_to_conversation_message)
|
||||
}
|
||||
|
||||
@ -318,39 +318,45 @@ pub fn send_message(msg: &NewConversationMessage) -> ResultBoxError<()> {
|
||||
let t = time();
|
||||
|
||||
// Insert the message in the database
|
||||
let msg_id = database::InsertQuery::new(CONV_MESSAGES_TABLE)
|
||||
.add_u64("conv_id", msg.conv_id)
|
||||
.add_user_id("user_id", &msg.user_id)
|
||||
.add_u64("time_insert", t)
|
||||
.add_str("message", msg.message.as_str())
|
||||
.add_opt_str("image_path", msg.image_path.as_ref())
|
||||
.insert_expect_result()?;
|
||||
let mut msg_request = database::InsertQuery::new(CONV_MESSAGES_TABLE)
|
||||
.add_conv_id("conv_id", msg.conv_id)
|
||||
.add_u64("user_id", msg.user_id.as_ref().map(|u| u.id()).unwrap_or(0))
|
||||
.add_u64("time_sent", t);
|
||||
|
||||
if let Some(server_msg) = &msg.server_message {
|
||||
msg_request = msg_request.add_str("message", &server_msg.to_db());
|
||||
} else if let Some(message) = &msg.message {
|
||||
msg_request = msg_request.add_str("message", message);
|
||||
}
|
||||
|
||||
if let Some(file) = &msg.file {
|
||||
msg_request = msg_request.add_str("file_path", &file.path)
|
||||
.add_u64("file_size", file.size)
|
||||
.add_str("file_name", &file.name)
|
||||
.add_str("file_type", &file.r#type)
|
||||
.add_opt_str("file_thumbnail", Option::from(&file.thumbnail));
|
||||
}
|
||||
|
||||
let msg_id = msg_request.insert_expect_result()?;
|
||||
|
||||
// Update the last activity of the conversation
|
||||
database::UpdateInfo::new(CONV_LIST_TABLE)
|
||||
.cond_u64("id", msg.conv_id)
|
||||
.set_u64("last_active", t)
|
||||
.cond_conv_id("id", msg.conv_id)
|
||||
.set_u64("last_activity", t)
|
||||
.exec()?;
|
||||
|
||||
// Get the list of users to notify after the update
|
||||
let list_to_notify = database::QueryInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", msg.conv_id)
|
||||
.cond_legacy_bool("saw_last_message", true)
|
||||
.cond_conv_id("conv_id", msg.conv_id)
|
||||
.cond_legacy_bool("following", true)
|
||||
.set_custom_where("user_id != ?")
|
||||
.add_custom_where_argument_user_id(&msg.user_id)
|
||||
.add_custom_where_argument_user_id(msg.user_id.as_ref().unwrap_or(&UserID::invalid()))
|
||||
.exec(|r| r.get_user_id("user_id"))?;
|
||||
|
||||
// Mark all the users of the conversation as unread
|
||||
database::UpdateInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", msg.conv_id)
|
||||
.cond_legacy_bool("saw_last_message", true)
|
||||
|
||||
.custom_where("user_id != ?")
|
||||
.add_custom_where_arg_u64(msg.user_id.id())
|
||||
|
||||
.set_legacy_bool("saw_last_message", false)
|
||||
.exec()?;
|
||||
// Mark the user has seen his message
|
||||
if let Some(user_id) = &msg.user_id {
|
||||
mark_user_seen(msg.conv_id, user_id, msg_id)?;
|
||||
}
|
||||
|
||||
// Send an event (updated_number_unread_conversations)
|
||||
events_helper::propagate_event(&Event::UpdatedNumberUnreadConversations(&list_to_notify))?;
|
||||
@ -419,34 +425,32 @@ pub fn get_list_unread(user_id: &UserID) -> ResultBoxError<Vec<UnreadConversatio
|
||||
|
||||
.cond_user_id("users.user_id", user_id)
|
||||
.cond_legacy_bool("users.following", true)
|
||||
.cond_legacy_bool("users.saw_last_message", false)
|
||||
|
||||
.set_custom_where("list.last_active = messages.time_insert")
|
||||
.set_custom_where("list.last_activity = messages.time_insert AND user.last_message_seen < messages.id")
|
||||
|
||||
.set_order("list.last_active DESC")
|
||||
.set_order("list.last_activity DESC")
|
||||
|
||||
.add_field("messages.conv_id")
|
||||
.add_field("name")
|
||||
.add_field("last_active")
|
||||
.add_field("last_activity")
|
||||
.add_field("messages.user_id")
|
||||
.add_field("message")
|
||||
|
||||
.exec(|res| Ok(UnreadConversation {
|
||||
id: res.get_u64("conv_id")?,
|
||||
name: res.get_optional_str("name")?,
|
||||
last_active: res.get_u64("last_active")?,
|
||||
last_active: res.get_u64("last_activity")?,
|
||||
user_id: res.get_user_id("user_id")?,
|
||||
message: res.get_str("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<()> {
|
||||
pub fn mark_user_seen(conv_id: ConvID, user_id: &UserID, last_msg: u64) -> ResultBoxError<()> {
|
||||
database::UpdateInfo::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
.cond_conv_id("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)
|
||||
.set_u64("last_message_seen", last_msg)
|
||||
.exec()?;
|
||||
|
||||
// Push an event (updated_number_unread_conversations)
|
||||
@ -456,36 +460,41 @@ pub fn mark_user_seen(conv_id: u64, user_id: &UserID) -> ResultBoxError<()> {
|
||||
}
|
||||
|
||||
/// Remove a user from a conversation
|
||||
pub fn remove_user_from_conversation(user_id: &UserID, conv_id: u64) -> ResultBoxError<()> {
|
||||
if is_user_moderator(user_id, conv_id)? {
|
||||
delete_conversation(conv_id)
|
||||
pub fn remove_user_from_conversation(user_id: &UserID, conv: &Conversation, remover: &UserID) -> ResultBoxError<()> {
|
||||
if conv.is_last_admin(user_id) {
|
||||
delete_conversation(conv)
|
||||
} else {
|
||||
delete_member(user_id, conv_id)
|
||||
delete_member(user_id, conv.id, remover)
|
||||
}
|
||||
}
|
||||
|
||||
/// Remove permanently a conversation
|
||||
pub fn delete_conversation(conv_id: u64) -> ResultBoxError<()> {
|
||||
pub fn delete_conversation(conv: &Conversation) -> ResultBoxError<()> {
|
||||
// Delete all the messages of the conversations
|
||||
for message in get_all_messages(conv_id)? {
|
||||
for message in get_all_messages(conv.id)? {
|
||||
delete_message(&message)?;
|
||||
}
|
||||
|
||||
// Delete all the members of the conversation
|
||||
database::DeleteQuery::new(CONV_MEMBERS_TABLE)
|
||||
.cond_u64("conv_id", conv_id)
|
||||
.cond_conv_id("conv_id", conv.id)
|
||||
.exec()?;
|
||||
|
||||
// Delete associated background image, if any
|
||||
if let Some(image) = &conv.background {
|
||||
delete_user_data_file_if_exists(image)?;
|
||||
}
|
||||
|
||||
// Delete the conversation entry itself
|
||||
database::DeleteQuery::new(CONV_LIST_TABLE)
|
||||
.cond_u64("id", conv_id)
|
||||
.cond_conv_id("id", conv.id)
|
||||
.exec()?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete a conversation membership
|
||||
pub fn delete_member(user_id: &UserID, conv_id: u64) -> ResultBoxError<()> {
|
||||
pub fn delete_member(user_id: &UserID, conv_id: ConvID, _remover: &UserID) -> ResultBoxError<()> {
|
||||
for msg in get_user_messages_for_conversations(conv_id, user_id)? {
|
||||
delete_message(&msg)?;
|
||||
}
|
||||
@ -507,17 +516,30 @@ pub fn is_message_owner(user_id: &UserID, message_id: u64) -> ResultBoxError<boo
|
||||
|
||||
/// Turn a database entry into a ConversationInfo object
|
||||
fn db_to_conversation_info(row: &database::RowResult) -> ResultBoxError<Conversation> {
|
||||
let conv_id = row.get_u64("id")?;
|
||||
let conv_id = row.get_conv_id("id")?;
|
||||
Ok(Conversation {
|
||||
id: conv_id,
|
||||
owner_id: row.get_user_id("owner_id")?,
|
||||
color: row.get_optional_str("color")?,
|
||||
background: row.get_optional_str("background")?,
|
||||
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")?,
|
||||
last_activity: row.get_u64("last_activity")?,
|
||||
creation_time: row.get_u64("creation_time")?,
|
||||
group_id: row.get_optional_group_id("group_id")?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Turn a database entry into a ConversationMember object
|
||||
fn db_to_conversation_member(row: &database::RowResult) -> Res<ConversationMember> {
|
||||
Ok(ConversationMember {
|
||||
member_id: row.get_u64("id")?,
|
||||
conv_id: row.get_conv_id("conv_id")?,
|
||||
user_id: row.get_user_id("user_id")?,
|
||||
added_on: row.get_u64("added_on")?,
|
||||
following: row.get_legacy_bool("following")?,
|
||||
saw_last_message: row.get_legacy_bool("saw_last_message")?,
|
||||
is_admin: row.get_legacy_bool("is_admin")?,
|
||||
last_message_seen: row.get_u64("last_message_seen")?,
|
||||
})
|
||||
}
|
||||
|
||||
@ -529,10 +551,10 @@ fn db_to_conversation_message(row: &database::RowResult) -> ResultBoxError<Conve
|
||||
false => Some(row.get_user_id("user_id")?)
|
||||
};
|
||||
|
||||
let file = match row.is_null_or_empty("filepath")? {
|
||||
let file = match row.is_null_or_empty("file_path")? {
|
||||
true => None,
|
||||
false => Some(ConversationMessageFile {
|
||||
path: row.get_str("filepath")?,
|
||||
path: row.get_str("file_path")?,
|
||||
size: row.get_u64("file_size")?,
|
||||
name: row.get_str("file_name")?,
|
||||
thumbnail: row.get_optional_str("file_thumbnail")?,
|
||||
@ -553,7 +575,7 @@ fn db_to_conversation_message(row: &database::RowResult) -> ResultBoxError<Conve
|
||||
Ok(ConversationMessage {
|
||||
id: row.get_u64("id")?,
|
||||
time_sent: row.get_u64("time_sent")?,
|
||||
conv_id: row.get_u64("conv_id")?,
|
||||
conv_id: row.get_conv_id("conv_id")?,
|
||||
user_id,
|
||||
message,
|
||||
server_message,
|
||||
|
@ -12,6 +12,7 @@ use crate::data::config::{conf, DatabaseConfig};
|
||||
use crate::data::error::{ExecError, ResultBoxError};
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::user::UserID;
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
/// Database access helper
|
||||
///
|
||||
@ -174,6 +175,11 @@ impl QueryInfo {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cond_conv_id(mut self, key: &str, val: ConvID) -> QueryInfo {
|
||||
self.conditions.insert(key.to_string(), mysql::Value::from(val.id()));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cond_legacy_bool(mut self, key: &str, val: bool) -> QueryInfo {
|
||||
let val = match val {
|
||||
true => 1,
|
||||
@ -358,6 +364,19 @@ impl<'a> RowResult<'a> {
|
||||
Ok(GroupID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Get the optional ID of a group included in the response
|
||||
pub fn get_optional_group_id(&self, name: &str) -> ResultBoxError<Option<GroupID>> {
|
||||
Ok(match self.get_optional_u64(name)? {
|
||||
None | Some(0) => None,
|
||||
Some(id) => Some(GroupID::new(id))
|
||||
})
|
||||
}
|
||||
|
||||
/// Get the ID of a conversation included in the response
|
||||
pub fn get_conv_id(&self, name: &str) -> ResultBoxError<ConvID> {
|
||||
Ok(ConvID::new(self.get_u64(name)?))
|
||||
}
|
||||
|
||||
/// Find a string included in the request
|
||||
pub fn get_str(&self, name: &str) -> Result<String, Box<dyn Error>> {
|
||||
let value = self.row.get_opt(self.find_col(name)?);
|
||||
@ -588,6 +607,19 @@ impl InsertQuery {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an optional number. If None, Null will be inserted
|
||||
pub fn add_opt_u64(mut self, key: &str, value: Option<u64>) -> InsertQuery {
|
||||
self.values.insert(key.to_string(), value
|
||||
.map(|u| Value::UInt(u))
|
||||
.unwrap_or(Value::NULL));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an optional number. If None, Null will be inserted
|
||||
pub fn add_opt_group_id(self, key: &str, value: Option<GroupID>) -> InsertQuery {
|
||||
self.add_opt_u64(key, value.map(|u| u.id()))
|
||||
}
|
||||
|
||||
/// Add an integer
|
||||
pub fn add_i64(mut self, key: &str, value: i64) -> InsertQuery {
|
||||
self.values.insert(key.to_string(), Value::from(value));
|
||||
@ -619,6 +651,12 @@ impl InsertQuery {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn add_conv_id(mut self, key: &str, value: ConvID) -> InsertQuery {
|
||||
self.values.insert(key.to_string(), Value::from(value.id()));
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// Legacy database boolean (1 = true / 0 = false)
|
||||
pub fn add_legacy_bool(mut self, key: &str, value: bool) -> InsertQuery {
|
||||
@ -758,6 +796,11 @@ impl DeleteQuery {
|
||||
self
|
||||
}
|
||||
|
||||
pub fn cond_conv_id(mut self, key: &str, value: ConvID) -> DeleteQuery {
|
||||
self.conditions.insert(key.to_string(), Value::from(value.id()));
|
||||
self
|
||||
}
|
||||
|
||||
/// Execute the delete query
|
||||
pub fn exec(self) -> ResultBoxError<()> {
|
||||
delete(self)
|
||||
@ -832,6 +875,13 @@ impl UpdateInfo {
|
||||
self
|
||||
}
|
||||
|
||||
/// Filter with a conversation id
|
||||
pub fn cond_conv_id(mut self, name: &str, val: ConvID) -> UpdateInfo {
|
||||
self.cond.insert(name.to_string(), Value::UInt(val.id()));
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
/// Filter with an unsigned integer
|
||||
pub fn cond_u64(mut self, name: &str, val: u64) -> UpdateInfo {
|
||||
self.cond.insert(name.to_string(), Value::UInt(val));
|
||||
|
@ -196,7 +196,6 @@ pub fn get_routes() -> Vec<Route> {
|
||||
Route::post("/conversations/getInfosOne", Box::new(conversations_controller::get_single)),
|
||||
Route::post("/conversations/updateSettings", Box::new(conversations_controller::update_settings)),
|
||||
Route::post("/conversations/getPrivate", Box::new(conversations_controller::find_private)),
|
||||
Route::post("/conversations/refresh", Box::new(conversations_controller::refresh_list)),
|
||||
Route::post("/conversations/refresh_single", Box::new(conversations_controller::refresh_single)),
|
||||
Route::post("/conversations/get_older_messages", Box::new(conversations_controller::get_older_messages)),
|
||||
Route::post("/conversations/sendMessage", Box::new(conversations_controller::send_message)),
|
||||
@ -205,6 +204,7 @@ pub fn get_routes() -> Vec<Route> {
|
||||
Route::post("/conversations/delete", Box::new(conversations_controller::delete_conversation)),
|
||||
Route::post("/conversations/updateMessage", Box::new(conversations_controller::update_message)),
|
||||
Route::post("/conversations/deleteMessage", Box::new(conversations_controller::delete_message)),
|
||||
// TODO : add a route to mark messages seen
|
||||
|
||||
|
||||
// Search controller
|
||||
|
@ -92,4 +92,18 @@ pub fn check_youtube_id(id: &str) -> bool {
|
||||
pub fn check_emoji_code(shortcut: &str) -> bool {
|
||||
let r = Regex::new(r"^:[a-zA-Z0-9]+:$").unwrap();
|
||||
r.is_match(shortcut)
|
||||
}
|
||||
|
||||
/// Check the validity of an HTML color
|
||||
///
|
||||
/// ```
|
||||
/// use comunic_server::utils::string_utils::check_emoji_code;
|
||||
///
|
||||
/// assert_eq!(check_emoji_code("AAFF00"), true);
|
||||
/// assert_eq!(check_emoji_code("ABC"), false);
|
||||
/// assert_eq!(check_emoji_code("UUFF00"), false);
|
||||
/// ```
|
||||
pub fn check_html_color(color: &str) -> bool {
|
||||
let r = Regex::new(r"^:[A-F0-9]{6}:$").unwrap();
|
||||
r.is_match(color)
|
||||
}
|
Loading…
Reference in New Issue
Block a user