mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-11-26 15:29:21 +00:00
Get the list of conversations of the user
This commit is contained in:
parent
e92b3ef821
commit
620328b33b
57
src/api_data/conversation_api.rs
Normal file
57
src/api_data/conversation_api.rs
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
//! # Conversation API object
|
||||||
|
//!
|
||||||
|
//! @author Pierre Hubert
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
use crate::api_data::legacy_api_bool::LegacyBool;
|
||||||
|
use crate::data::conversation::Conversation;
|
||||||
|
|
||||||
|
/// 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)]
|
||||||
|
#[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,
|
||||||
|
can_have_call: bool,
|
||||||
|
can_have_video_call: bool,
|
||||||
|
has_call_now: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ConversationAPI {
|
||||||
|
|
||||||
|
/// Construct a new Conversation instance
|
||||||
|
pub fn new(conv: &Conversation) -> ConversationAPI {
|
||||||
|
ConversationAPI {
|
||||||
|
ID: conv.id,
|
||||||
|
ID_owner: conv.owner_id as u64,
|
||||||
|
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.clone() as u64).collect(),
|
||||||
|
canEveryoneAddMembers: conv.can_everyone_add_members,
|
||||||
|
|
||||||
|
// TODO : update when call system is implemented
|
||||||
|
can_have_call: false,
|
||||||
|
can_have_video_call: false,
|
||||||
|
has_call_now: false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
20
src/api_data/legacy_api_bool.rs
Normal file
20
src/api_data/legacy_api_bool.rs
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
//! # Legacy API boolean
|
||||||
|
//!
|
||||||
|
//! true => 1
|
||||||
|
//! false => 0
|
||||||
|
|
||||||
|
|
||||||
|
use serde::{Serialize, Serializer};
|
||||||
|
|
||||||
|
/// Special implementation of conversation name (false if none / the name otherwise)
|
||||||
|
pub struct LegacyBool(pub bool);
|
||||||
|
|
||||||
|
impl Serialize for LegacyBool {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<<S as Serializer>::Ok, <S as Serializer>::Error> where
|
||||||
|
S: Serializer {
|
||||||
|
match &self.0 {
|
||||||
|
true => serializer.serialize_i8(1),
|
||||||
|
false => serializer.serialize_i8(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -15,3 +15,5 @@ pub mod custom_emoji;
|
|||||||
pub mod res_find_user_by_virtual_directory;
|
pub mod res_find_user_by_virtual_directory;
|
||||||
pub mod res_find_virtual_directory;
|
pub mod res_find_virtual_directory;
|
||||||
pub mod res_create_conversation;
|
pub mod res_create_conversation;
|
||||||
|
pub mod conversation_api;
|
||||||
|
mod legacy_api_bool;
|
@ -7,6 +7,7 @@ use crate::controllers::routes::RequestResult;
|
|||||||
use crate::helpers::{user_helper, conversations_helper};
|
use crate::helpers::{user_helper, conversations_helper};
|
||||||
use crate::data::new_conversation::NewConversation;
|
use crate::data::new_conversation::NewConversation;
|
||||||
use crate::api_data::res_create_conversation::ResCreateConversation;
|
use crate::api_data::res_create_conversation::ResCreateConversation;
|
||||||
|
use crate::api_data::conversation_api::ConversationAPI;
|
||||||
|
|
||||||
/// Create a new conversation
|
/// Create a new conversation
|
||||||
pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
||||||
@ -47,5 +48,8 @@ pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
|||||||
|
|
||||||
/// Get the list of conversations of a user
|
/// Get the list of conversations of a user
|
||||||
pub fn get_list(r: &mut HttpRequestHandler) -> RequestResult {
|
pub fn get_list(r: &mut HttpRequestHandler) -> RequestResult {
|
||||||
r.success("Get the list of conversations")
|
|
||||||
|
let list = conversations_helper::get_list_user(r.user_id()?)?;
|
||||||
|
|
||||||
|
r.set_response(list.iter().map(|c| ConversationAPI::new(c)).collect::<Vec<ConversationAPI>>())
|
||||||
}
|
}
|
19
src/data/conversation.rs
Normal file
19
src/data/conversation.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
//! # Conversation information
|
||||||
|
//!
|
||||||
|
//! @author Pierre Hubert
|
||||||
|
|
||||||
|
use crate::data::user::UserID;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct Conversation {
|
||||||
|
pub id: u64,
|
||||||
|
pub owner_id: UserID,
|
||||||
|
pub name: Option<String>,
|
||||||
|
pub members: Vec<UserID>,
|
||||||
|
pub can_everyone_add_members: bool,
|
||||||
|
pub last_active: u64,
|
||||||
|
pub time_create: u64,
|
||||||
|
|
||||||
|
pub following: bool,
|
||||||
|
pub saw_last_message: bool,
|
||||||
|
}
|
@ -8,3 +8,4 @@ pub mod user;
|
|||||||
pub mod user_token;
|
pub mod user_token;
|
||||||
pub mod custom_emoji;
|
pub mod custom_emoji;
|
||||||
pub mod new_conversation;
|
pub mod new_conversation;
|
||||||
|
pub mod conversation;
|
@ -4,10 +4,12 @@
|
|||||||
|
|
||||||
use crate::data::new_conversation::NewConversation;
|
use crate::data::new_conversation::NewConversation;
|
||||||
use crate::data::error::{ResultBoxError, ExecError};
|
use crate::data::error::{ResultBoxError, ExecError};
|
||||||
use crate::helpers::database::InsertQuery;
|
use crate::helpers::database::{InsertQuery};
|
||||||
use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_USERS_TABLE};
|
use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_USERS_TABLE};
|
||||||
use crate::utils::date_utils::time;
|
use crate::utils::date_utils::time;
|
||||||
use crate::data::user::UserID;
|
use crate::data::user::UserID;
|
||||||
|
use crate::data::conversation::Conversation;
|
||||||
|
use crate::helpers::database;
|
||||||
|
|
||||||
/// Create a new conversation. This method returns the ID of the created conversation
|
/// 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) -> ResultBoxError<u64> {
|
||||||
@ -46,3 +48,50 @@ pub fn add_member(conv_id: u64, user_id: UserID, following: bool) -> ResultBoxEr
|
|||||||
|
|
||||||
Ok(())
|
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)
|
||||||
|
.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 the list of members of a conversation
|
||||||
|
pub fn get_list_members(conv_id: u64) -> ResultBoxError<Vec<UserID>> {
|
||||||
|
database::QueryInfo::new(CONV_USERS_TABLE)
|
||||||
|
.cond_u64("conv_id", conv_id)
|
||||||
|
.add_field("user_id")
|
||||||
|
.exec(|res|res.get_user_id("user_id"))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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")?;
|
||||||
|
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")?,
|
||||||
|
})
|
||||||
|
}
|
@ -50,10 +50,20 @@ pub fn get_connection() -> Result<mysql::PooledConn, Box<dyn Error>> {
|
|||||||
Ok(pool.get_conn()?)
|
Ok(pool.get_conn()?)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Structure used to implement JOIN on queries
|
||||||
|
struct QueryJoin {
|
||||||
|
table: String,
|
||||||
|
table_alias: String,
|
||||||
|
condition: String,
|
||||||
|
}
|
||||||
|
|
||||||
pub struct QueryInfo {
|
pub struct QueryInfo {
|
||||||
/// Fetched table
|
/// Fetched table
|
||||||
pub table: String,
|
pub table: String,
|
||||||
|
pub table_alias: Option<String>,
|
||||||
|
|
||||||
|
/// Joins
|
||||||
|
joins: Vec<QueryJoin>,
|
||||||
|
|
||||||
/// Query limits
|
/// Query limits
|
||||||
pub conditions: collections::HashMap<String, String>,
|
pub conditions: collections::HashMap<String, String>,
|
||||||
@ -61,6 +71,9 @@ pub struct QueryInfo {
|
|||||||
/// Limit of the query (0 = no limit)
|
/// Limit of the query (0 = no limit)
|
||||||
pub limit: u64,
|
pub limit: u64,
|
||||||
|
|
||||||
|
/// Order of the query
|
||||||
|
pub order: Option<String>,
|
||||||
|
|
||||||
/// Queried arguments
|
/// Queried arguments
|
||||||
///
|
///
|
||||||
/// If this attribute is empty, all the columns of the table set are fetched
|
/// If this attribute is empty, all the columns of the table set are fetched
|
||||||
@ -72,12 +85,30 @@ impl QueryInfo {
|
|||||||
pub fn new(table: &str) -> QueryInfo {
|
pub fn new(table: &str) -> QueryInfo {
|
||||||
QueryInfo {
|
QueryInfo {
|
||||||
table: table.to_string(),
|
table: table.to_string(),
|
||||||
|
table_alias: None,
|
||||||
|
joins: Vec::new(),
|
||||||
conditions: collections::HashMap::new(),
|
conditions: collections::HashMap::new(),
|
||||||
limit: 0,
|
limit: 0,
|
||||||
|
order: None,
|
||||||
fields: Vec::new(),
|
fields: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Main fetched table alias
|
||||||
|
pub fn alias(mut self, table_alias: &str) -> QueryInfo {
|
||||||
|
self.table_alias = Some(table_alias.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn join(mut self, table: &str, table_alias: &str, cond: &str) -> QueryInfo {
|
||||||
|
self.joins.push(QueryJoin {
|
||||||
|
table: table.to_string(),
|
||||||
|
table_alias: table_alias.to_string(),
|
||||||
|
condition: cond.to_string(),
|
||||||
|
});
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn cond(mut self, key: &str, val: &str) -> QueryInfo {
|
pub fn cond(mut self, key: &str, val: &str) -> QueryInfo {
|
||||||
self.conditions.insert(key.to_string(), val.to_string());
|
self.conditions.insert(key.to_string(), val.to_string());
|
||||||
self
|
self
|
||||||
@ -109,6 +140,12 @@ impl QueryInfo {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set results ordering
|
||||||
|
pub fn set_order(mut self, order: &str) -> QueryInfo {
|
||||||
|
self.order = Some(order.to_string());
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Execute query
|
/// Execute query
|
||||||
pub fn exec<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(self, process_function: F)
|
pub fn exec<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(self, process_function: F)
|
||||||
-> Result<Vec<E>, Box<dyn Error>> {
|
-> Result<Vec<E>, Box<dyn Error>> {
|
||||||
@ -187,6 +224,11 @@ impl<'a> RowResult<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Get the ID of a user included in the request
|
||||||
|
pub fn get_user_id(&self, name: &str) -> ResultBoxError<UserID> {
|
||||||
|
self.get_int64(name)
|
||||||
|
}
|
||||||
|
|
||||||
/// Find a string included in the request
|
/// Find a string included in the request
|
||||||
pub fn get_str(&self, name: &str) -> Result<String, Box<dyn Error>> {
|
pub fn get_str(&self, name: &str) -> Result<String, Box<dyn Error>> {
|
||||||
let value = self.row.get_opt(self.find_col(name)?);
|
let value = self.row.get_opt(self.find_col(name)?);
|
||||||
@ -273,6 +315,17 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
|
|||||||
// Build query
|
// Build query
|
||||||
let mut query = format!("SELECT {} FROM {} ", select_elements, info.table);
|
let mut query = format!("SELECT {} FROM {} ", select_elements, info.table);
|
||||||
|
|
||||||
|
// Table alias (if any)
|
||||||
|
if let Some(alias) = info.table_alias {
|
||||||
|
query = query.add(format!(" {} ", alias).as_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
// Join conditions
|
||||||
|
for j in info.joins {
|
||||||
|
query = query.add(
|
||||||
|
format!(" JOIN {} {} ON {} ", j.table, j.table_alias, j.condition).as_ref());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// WHERE clause
|
// WHERE clause
|
||||||
if !info.conditions.is_empty() {
|
if !info.conditions.is_empty() {
|
||||||
@ -287,6 +340,11 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
|
|||||||
query = query.add(&where_args);
|
query = query.add(&where_args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ORDER clause
|
||||||
|
if let Some(order) = info.order {
|
||||||
|
query = query.add(format!(" ORDER BY {} ", order).as_str());
|
||||||
|
}
|
||||||
|
|
||||||
// LIMIT clause
|
// LIMIT clause
|
||||||
if info.limit > 0 {
|
if info.limit > 0 {
|
||||||
query = query.add(&format!(" LIMIT {}", info.limit));
|
query = query.add(&format!(" LIMIT {}", info.limit));
|
||||||
@ -294,7 +352,10 @@ pub fn query<E, F: Fn(&RowResult) -> ProcessRowResult<E>>(info: QueryInfo, proce
|
|||||||
|
|
||||||
// Execute query
|
// Execute query
|
||||||
let mut con = get_connection()?;
|
let mut con = get_connection()?;
|
||||||
let stmt = con.prep(&query)?;
|
let stmt = con.prep(&query).or_else(|err| {
|
||||||
|
println!("Error in SQL query: {}", &query);
|
||||||
|
Err(err)
|
||||||
|
})?;
|
||||||
|
|
||||||
let mut res = con.exec_iter(stmt, params)?;
|
let mut res = con.exec_iter(stmt, params)?;
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user