1
0
mirror of https://gitlab.com/comunic/comunicapiv3 synced 2024-11-22 21:39:21 +00:00

Start conversations system migration

This commit is contained in:
Pierre HUBERT 2021-03-02 18:57:34 +01:00
parent cd5419edea
commit 60733f2d04
7 changed files with 262 additions and 30 deletions

View File

@ -5,31 +5,86 @@
//! @author Pierre HUBERT
use serde::Serialize;
use serde_json::Value;
use crate::data::conversation_message::ConversationMessage;
use crate::data::conversation_message::{ConversationMessage, ConversationServerMessageType};
use crate::utils::user_data_utils::user_data_url;
#[derive(Serialize)]
#[allow(non_snake_case)]
struct ConversationMessageFileAPI {
url: String,
size: u64,
name: String,
thumbnail: Option<String>,
r#type: String,
}
#[derive(Serialize)]
pub struct ConversationMessageAPI {
ID: u64,
convID: u64,
ID_user: u64,
id: u64,
conv_id: u64,
user_id: Option<u64>,
time_insert: u64,
message: String,
image_path: Option<String>,
message: Option<String>,
file: Option<ConversationMessageFileAPI>,
server_message: Option<serde_json::Value>,
}
impl ConversationMessageAPI {
/// Turn a conversation message into an API entry
pub fn new(msg: &ConversationMessage) -> ConversationMessageAPI {
let file = match &msg.file {
None => None,
Some(file) => Some(ConversationMessageFileAPI {
url: user_data_url(&file.path.clone()),
size: file.size,
name: file.name.clone(),
thumbnail: file.thumbnail.clone(),
r#type: file.r#type.clone(),
})
};
let server_message = match &msg.server_message {
None => None,
Some(msg) => {
let mut value = serde_json::Map::new();
match msg {
ConversationServerMessageType::UserCreatedConversation(user) => {
value.insert("type".to_string(), Value::from("user_created_conv"));
value.insert("user_id".to_string(), Value::from(user.id()));
}
ConversationServerMessageType::UserAddedAnotherUserToConversation(msg) => {
value.insert("type".to_string(), Value::from("user_added_another"));
value.insert("user_who_added".to_string(), Value::from(msg.user_who_added.id()));
value.insert("user_added".to_string(), Value::from(msg.user_added.id()));
}
ConversationServerMessageType::UserLeftConversation(u) => {
value.insert("type".to_string(), Value::from("user_left"));
value.insert("user_id".to_string(), Value::from(u.id()));
}
ConversationServerMessageType::UserRemovedFromConversation(msg) => {
value.insert("type".to_string(), Value::from("user_removed_another"));
value.insert("user_who_removed".to_string(), Value::from(msg.user_who_removed.id()));
value.insert("user_removed".to_string(), Value::from(msg.user_removed.id()));
}
}
Some(serde_json::Value::Object(value))
}
};
ConversationMessageAPI {
ID: msg.id,
convID: msg.conv_id,
ID_user: msg.user_id.id(),
id: msg.id,
conv_id: msg.conv_id,
user_id: msg.user_id.clone().map(|u| u.id()),
time_insert: msg.time_sent,
message: msg.message.clone().unwrap_or(String::new()),
image_path: msg.image_path.as_ref().map(|f| user_data_url(f)),
message: msg.message.clone(),
file,
server_message,
}
}

View File

@ -61,7 +61,7 @@ impl AccountExport {
// Conversation messages
for (_, conv_messages) in &self.conversation_messages {
conv_messages.iter().for_each(|f| { set.insert(f.user_id.clone()); })
conv_messages.iter().for_each(|f| { set.extend(f.referenced_users_id()); })
}
Ok(set)

View File

@ -2,15 +2,141 @@
//!
//! Information about a single conversation message
use std::collections::HashSet;
use crate::data::error::{ExecError, Res};
use crate::data::user::UserID;
pub type ConvMessageID = u64;
#[derive(Debug)]
pub struct ConversationMessageFile {
pub path: String,
pub size: u64,
pub name: String,
pub thumbnail: Option<String>,
pub r#type: String,
}
#[derive(Debug)]
pub struct UserAddedAnotherUserToConversation {
pub user_who_added: UserID,
pub user_added: UserID,
}
#[derive(Debug)]
pub struct UserRemovedAnotherUserToConversation {
pub user_who_removed: UserID,
pub user_removed: UserID,
}
#[derive(Debug)]
pub enum ConversationServerMessageType {
UserCreatedConversation(UserID),
UserAddedAnotherUserToConversation(UserAddedAnotherUserToConversation),
UserLeftConversation(UserID),
UserRemovedFromConversation(UserRemovedAnotherUserToConversation),
}
impl ConversationServerMessageType {
pub fn to_db(&self) -> String {
let info = match self {
ConversationServerMessageType::UserCreatedConversation(u) => ("user_created_conv", Some(u.clone()), None),
ConversationServerMessageType::UserAddedAnotherUserToConversation(msg) => ("user_added_another_user", Some(msg.user_who_added.clone()), Some(msg.user_added.clone())),
ConversationServerMessageType::UserLeftConversation(u) => ("user_left", Some(u.clone()), None),
ConversationServerMessageType::UserRemovedFromConversation(msg) => ("user_removed", Some(msg.user_who_removed.clone()), Some(msg.user_removed.clone())),
};
format!(
"{}-{}-{}",
info.0,
info.1.map(|u| u.id()).unwrap_or(0),
info.2.map(|u| u.id()).unwrap_or(0)
)
}
pub fn from_db(str: &str) -> Res<Self> {
let split: Vec<&str> = str.split("-").collect();
if split.len() != 3 {
return Err(ExecError::boxed_new("Invalid ConversationSerMessageType"));
}
let id_1 = split[1].parse::<u64>()?;
let id_2 = split[2].parse::<u64>()?;
let info = (
split[0],
match id_1 {
0 => None,
id => Some(UserID::new(id))
},
match id_2 {
0 => None,
id => Some(UserID::new(id))
},
);
match info {
("user_created_conv", Some(user_id), _) => Ok(Self::UserCreatedConversation(user_id)),
("user_added_another_user", Some(user_id), Some(user_2)) => Ok(Self::UserAddedAnotherUserToConversation(UserAddedAnotherUserToConversation {
user_who_added: user_id,
user_added: user_2,
})),
("user_left", Some(user_id), _) => Ok(Self::UserLeftConversation(user_id)),
("user_removed", Some(user_id), Some(user_2)) => Ok(Self::UserRemovedFromConversation(UserRemovedAnotherUserToConversation {
user_who_removed: user_id,
user_removed: user_2,
})),
_ => Err(ExecError::boxed_new("Unknown server message type!"))
}
}
}
/// Information about a single conversation message
#[derive(Debug)]
pub struct ConversationMessage {
pub id: u64,
pub id: ConvMessageID,
pub time_sent: u64,
pub conv_id: u64,
pub user_id: UserID,
pub user_id: Option<UserID>,
pub message: Option<String>,
pub image_path: Option<String>,
pub server_message: Option<ConversationServerMessageType>,
pub file: Option<ConversationMessageFile>,
}
impl ConversationMessage {
/// Get the entire list of referenced users in a conversation message
pub fn referenced_users_id(&self) -> HashSet<UserID> {
let mut users = HashSet::new();
if let Some(user_id) = &self.user_id {
users.insert(user_id.clone());
}
if let Some(srv_msg) = &self.server_message {
match srv_msg {
ConversationServerMessageType::UserCreatedConversation(user) => {
users.insert(user.clone());
}
ConversationServerMessageType::UserAddedAnotherUserToConversation(msg) => {
users.insert(msg.user_who_added.clone());
users.insert(msg.user_added.clone());
}
ConversationServerMessageType::UserLeftConversation(user) => {
users.insert(user.clone());
}
ConversationServerMessageType::UserRemovedFromConversation(msg) => {
users.insert(msg.user_who_removed.clone());
users.insert(msg.user_removed.clone());
}
}
}
users
}
}

View File

@ -2,9 +2,9 @@
//!
//! @author Pierre Hubert
use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_MESSAGES_TABLE, CONV_MEMBERS_TABLE};
use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_MEMBERS_TABLE, CONV_MESSAGES_TABLE};
use crate::data::conversation::Conversation;
use crate::data::conversation_message::ConversationMessage;
use crate::data::conversation_message::{ConversationMessage, ConversationMessageFile, ConversationServerMessageType};
use crate::data::error::{ExecError, Res, ResultBoxError};
use crate::data::new_conversation::NewConversation;
use crate::data::new_conversation_message::NewConversationMessage;
@ -14,7 +14,7 @@ use crate::helpers::{database, events_helper};
use crate::helpers::database::InsertQuery;
use crate::helpers::events_helper::Event;
use crate::utils::date_utils::time;
use crate::utils::user_data_utils::user_data_path;
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> {
@ -377,11 +377,12 @@ pub fn update_message_content(msg_id: u64, new_content: &str) -> ResultBoxError<
/// Remove a message from a conversation
pub fn delete_message(msg: &ConversationMessage) -> ResultBoxError<()> {
// Delete associated image (if any)
if let Some(img) = &msg.image_path {
let path = user_data_path(img.as_ref());
if path.exists() {
std::fs::remove_file(path)?;
// Delete associated files
if let Some(file) = &msg.file {
delete_user_data_file_if_exists(&file.path)?;
if let Some(thumb) = &file.thumbnail {
delete_user_data_file_if_exists(thumb)?;
}
}
@ -523,12 +524,39 @@ fn db_to_conversation_info(row: &database::RowResult) -> ResultBoxError<Conversa
/// Turn a database entry into a ConversationMessgae object
fn db_to_conversation_message(row: &database::RowResult) -> ResultBoxError<ConversationMessage> {
let user_id = match row.is_null("user_id")? {
true => None,
false => Some(row.get_user_id("user_id")?)
};
let file = match row.is_null_or_empty("filepath")? {
true => None,
false => Some(ConversationMessageFile {
path: row.get_str("filepath")?,
size: row.get_u64("file_size")?,
name: row.get_str("file_name")?,
thumbnail: row.get_optional_str("file_thumbnail")?,
r#type: row.get_str("file_type")?,
})
};
let server_message = match &user_id {
Some(_) => None,
None => Some(ConversationServerMessageType::from_db(&row.get_str("message")?)?)
};
let message = match server_message {
None => row.get_optional_str("message")?,
Some(_) => None,
};
Ok(ConversationMessage {
id: row.get_u64("id")?,
time_sent: row.get_u64("time_insert")?,
time_sent: row.get_u64("time_sent")?,
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")?,
user_id,
message,
server_message,
file,
})
}

View File

@ -380,6 +380,15 @@ impl<'a> RowResult<'a> {
}
}
/// Check out whether a given value is null or empty or not
pub fn is_null_or_empty(&self, name: &str) -> ResultBoxError<bool> {
if self.is_null(name)? {
return Ok(true);
}
Ok(self.get_str(name)?.is_empty())
}
/// Get an optional string => Set to None if string is null / empty
pub fn get_optional_str(&self, name: &str) -> ResultBoxError<Option<String>> {
match self.is_null(name)? {

View File

@ -1,6 +1,7 @@
use comunic_server::{cleanup_thread, server};
use comunic_server::api_data::conversation_message_api::ConversationMessageAPI;
use comunic_server::data::config::{conf, Config};
use comunic_server::helpers::database;
use comunic_server::helpers::{conversations_helper, database};
#[actix_rt::main]
async fn main() -> std::io::Result<()> {
@ -18,6 +19,10 @@ async fn main() -> std::io::Result<()> {
// Start cleanup thread
cleanup_thread::start().expect("Failed to start cleanup thread!");
let msg = conversations_helper::get_last_messages(120, 100).unwrap();
println!("{:#?}", msg);
println!("{:#?}", serde_json::to_string(&ConversationMessageAPI::for_list(&msg)));
// Start the server
server::start_server(conf()).await
}

View File

@ -7,7 +7,7 @@ use std::path::{Path, PathBuf};
use serde_json::to_string;
use crate::data::config::conf;
use crate::data::error::{ExecError, ResultBoxError};
use crate::data::error::{ExecError, Res, ResultBoxError};
use crate::data::user::UserID;
use crate::utils::crypt_utils::rand_str;
@ -62,3 +62,12 @@ pub fn generate_new_user_data_file_name(dir: &Path, ext: &str) -> ResultBoxError
}
}
}
/// Delete a file from user data, if it exists
pub fn delete_user_data_file_if_exists(path: &str) -> Res {
let path = user_data_path(path.as_ref());
if path.exists() {
std::fs::remove_file(path)?;
}
Ok(())
}