mirror of
https://gitlab.com/comunic/comunicapiv3
synced 2024-12-27 05:58:51 +00:00
Can create group conversation
This commit is contained in:
parent
1fc6f08b19
commit
63c284c322
@ -67,4 +67,5 @@ pub mod call_peer_ready;
|
||||
pub mod call_peer_interrupted_streaming;
|
||||
pub mod res_check_password_token;
|
||||
pub mod removed_user_from_conv_message;
|
||||
pub mod user_is_writing_message_in_conversation;
|
||||
pub mod user_is_writing_message_in_conversation;
|
||||
pub mod res_create_conversation_for_group;
|
20
src/api_data/res_create_conversation_for_group.rs
Normal file
20
src/api_data/res_create_conversation_for_group.rs
Normal file
@ -0,0 +1,20 @@
|
||||
//! # Conversation for group creation result
|
||||
//!
|
||||
//! This structure returns the ID of the create conversation
|
||||
|
||||
use serde::Serialize;
|
||||
|
||||
use crate::data::conversation::ConvID;
|
||||
|
||||
#[derive(Serialize)]
|
||||
pub struct ResCreateConversationForGroup {
|
||||
conv_id: u64
|
||||
}
|
||||
|
||||
impl ResCreateConversationForGroup {
|
||||
pub fn new(conv_id: ConvID) -> Self {
|
||||
Self {
|
||||
conv_id: conv_id.id()
|
||||
}
|
||||
}
|
||||
}
|
@ -45,6 +45,7 @@ pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
can_everyone_add_members: r.post_bool_opt("canEveryoneAddMembers", true),
|
||||
color: r.post_color_opt("color")?,
|
||||
group_id: None,
|
||||
group_min_membership_level: None,
|
||||
logo: None,
|
||||
};
|
||||
|
||||
@ -146,7 +147,7 @@ pub fn add_member(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
r.bad_request("This user is already a member of this conversation!".to_string())?;
|
||||
}
|
||||
|
||||
conversations_helper::add_member(conv.id, &user_to_add, true, false, r.user_id_ref()?)?;
|
||||
conversations_helper::add_member(conv.id, &user_to_add, true, false, Some(r.user_id_ref()?))?;
|
||||
|
||||
r.success("The user was added to the conversation!")
|
||||
}
|
||||
@ -194,7 +195,7 @@ pub fn remove_member(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
r.bad_request("This user is not a member of this conversation!".to_string())?;
|
||||
}
|
||||
|
||||
conversations_helper::remove_member(&user_to_remove, conv.id, r.user_id_ref()?)?;
|
||||
conversations_helper::remove_member(&user_to_remove, conv.id, Some(r.user_id_ref()?))?;
|
||||
|
||||
r.ok()
|
||||
}
|
||||
@ -225,6 +226,7 @@ pub fn find_private(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
color: None,
|
||||
logo: None,
|
||||
group_id: None,
|
||||
group_min_membership_level: None,
|
||||
};
|
||||
let conv_id = conversations_helper::create(&new_conv)?;
|
||||
list.push(conv_id);
|
||||
|
@ -8,20 +8,35 @@ use crate::api_data::advanced_group_api::AdvancedGroupApi;
|
||||
use crate::api_data::group_api::GroupApi;
|
||||
use crate::api_data::group_member_api::GroupMemberAPI;
|
||||
use crate::api_data::res_change_group_logo::ResChangeGroupLogo;
|
||||
use crate::api_data::res_create_conversation_for_group::ResCreateConversationForGroup;
|
||||
use crate::api_data::res_create_group::GroupCreationResult;
|
||||
use crate::constants::{DEFAULT_GROUP_LOGO, PATH_GROUPS_LOGOS};
|
||||
use crate::data::base_request_handler::BaseRequestHandler;
|
||||
use crate::data::error::Res;
|
||||
use crate::data::group::{Group, GroupAccessLevel, GroupPostsCreationLevel, GroupRegistrationLevel, GroupVisibilityLevel};
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::group_member::{GroupMember, GroupMembershipLevel};
|
||||
use crate::data::http_request_handler::HttpRequestHandler;
|
||||
use crate::data::new_group::NewGroup;
|
||||
use crate::data::notification::NotifEventType;
|
||||
use crate::helpers::{groups_helper, notifications_helper, virtual_directory_helper};
|
||||
use crate::helpers::{conversations_helper, groups_helper, notifications_helper, virtual_directory_helper};
|
||||
use crate::helpers::virtual_directory_helper::VirtualDirType;
|
||||
use crate::routes::RequestResult;
|
||||
use crate::utils::date_utils::time;
|
||||
|
||||
impl HttpRequestHandler {
|
||||
/// Get membership level for a conversation
|
||||
pub fn post_group_membership_level_for_conversation(&mut self, name: &str) -> Res<GroupMembershipLevel> {
|
||||
let level = GroupMembershipLevel::from_api(&self.post_string(name)?);
|
||||
|
||||
if !level.is_at_least_member() {
|
||||
self.bad_request("Specified membership level is not enough!".to_string())?;
|
||||
}
|
||||
|
||||
Ok(level)
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new group
|
||||
pub fn create(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let new_group = NewGroup {
|
||||
@ -153,6 +168,17 @@ pub fn delete_logo(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
r.set_response(ResChangeGroupLogo::new(DEFAULT_GROUP_LOGO))
|
||||
}
|
||||
|
||||
/// Create a new group's conversation
|
||||
pub fn create_conversation(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let group = r.post_group_id_with_access("group_id", GroupAccessLevel::ADMIN_ACCESS)?;
|
||||
let min_membership_level = r.post_group_membership_level_for_conversation("min_membership_level")?;
|
||||
let name = r.post_string("name")?;
|
||||
|
||||
let conv_id = conversations_helper::create_conversation_for_group(group, min_membership_level, &name)?;
|
||||
|
||||
r.set_response(ResCreateConversationForGroup::new(conv_id))
|
||||
}
|
||||
|
||||
/// Get the list of members of a group
|
||||
pub fn get_members(r: &mut HttpRequestHandler) -> RequestResult {
|
||||
let group_id = r.post_group_id("id")?;
|
||||
|
@ -4,6 +4,7 @@
|
||||
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::user::UserID;
|
||||
use crate::data::group_member::GroupMembershipLevel;
|
||||
|
||||
#[derive(Copy, Debug, PartialEq, Eq, Clone, Hash)]
|
||||
pub struct ConvID(u64);
|
||||
@ -38,6 +39,7 @@ pub struct Conversation {
|
||||
pub logo: Option<String>,
|
||||
pub creation_time: u64,
|
||||
pub group_id: Option<GroupID>,
|
||||
pub min_group_membership_level: Option<GroupMembershipLevel>,
|
||||
pub can_everyone_add_members: bool,
|
||||
pub last_activity: u64,
|
||||
pub members: Vec<ConversationMember>,
|
||||
@ -59,6 +61,11 @@ impl Conversation {
|
||||
|
||||
/// Check out whether this conversation is managed or not
|
||||
pub fn is_managed(&self) -> bool {
|
||||
self.is_linked_to_group()
|
||||
}
|
||||
|
||||
/// Check if this conversation is linked to a group
|
||||
pub fn is_linked_to_group(&self) -> bool {
|
||||
self.group_id.is_some()
|
||||
}
|
||||
|
||||
|
@ -5,7 +5,7 @@
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::user::UserID;
|
||||
|
||||
#[derive(PartialEq, Eq, PartialOrd)]
|
||||
#[derive(PartialEq, Eq, PartialOrd, Debug)]
|
||||
pub enum GroupMembershipLevel {
|
||||
ADMINISTRATOR = 0,
|
||||
MODERATOR = 1,
|
||||
@ -20,6 +20,13 @@ pub enum GroupMembershipLevel {
|
||||
}
|
||||
|
||||
impl GroupMembershipLevel {
|
||||
pub fn is_at_least_member(&self) -> bool {
|
||||
matches!(
|
||||
&self,
|
||||
GroupMembershipLevel::ADMINISTRATOR | GroupMembershipLevel::MODERATOR | GroupMembershipLevel::MEMBER
|
||||
)
|
||||
}
|
||||
|
||||
pub fn to_api(&self) -> String {
|
||||
match self {
|
||||
GroupMembershipLevel::ADMINISTRATOR => "administrator",
|
||||
@ -54,6 +61,10 @@ pub struct GroupMember {
|
||||
}
|
||||
|
||||
impl GroupMember {
|
||||
pub fn is_admin(&self) -> bool {
|
||||
self.level == GroupMembershipLevel::ADMINISTRATOR
|
||||
}
|
||||
|
||||
/// Check if a member of a group is a least a moderator of this group
|
||||
pub fn is_moderator(&self) -> bool {
|
||||
self.level <= GroupMembershipLevel::MODERATOR
|
||||
|
@ -5,6 +5,7 @@
|
||||
use std::collections::HashSet;
|
||||
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::group_member::GroupMembershipLevel;
|
||||
use crate::data::user::UserID;
|
||||
|
||||
#[derive(Debug)]
|
||||
@ -12,6 +13,7 @@ pub struct NewConversation {
|
||||
pub owner_id: UserID,
|
||||
pub name: Option<String>,
|
||||
pub group_id: Option<GroupID>,
|
||||
pub group_min_membership_level: Option<GroupMembershipLevel>,
|
||||
pub color: Option<String>,
|
||||
pub logo: Option<String>,
|
||||
pub owner_following: bool,
|
||||
|
@ -6,10 +6,12 @@ use crate::constants::database_tables_names::{CONV_LIST_TABLE, CONV_MEMBERS_TABL
|
||||
use crate::data::conversation::{Conversation, ConversationMember, ConvID, NewConversationSettings};
|
||||
use crate::data::conversation_message::{ConversationMessage, ConversationMessageFile, ConversationServerMessageType, UserAddedAnotherUserToConversation, UserRemovedAnotherUserToConversation};
|
||||
use crate::data::error::{ExecError, Res, ResultBoxError};
|
||||
use crate::data::group_id::GroupID;
|
||||
use crate::data::group_member::GroupMembershipLevel;
|
||||
use crate::data::new_conversation::NewConversation;
|
||||
use crate::data::new_conversation_message::NewConversationMessage;
|
||||
use crate::data::user::{User, UserID};
|
||||
use crate::helpers::{database, events_helper};
|
||||
use crate::helpers::{database, events_helper, groups_helper};
|
||||
use crate::helpers::database::{InsertQuery, UpdateInfo};
|
||||
use crate::helpers::events_helper::Event;
|
||||
use crate::utils::date_utils::time;
|
||||
@ -26,25 +28,47 @@ pub fn create(conv: &NewConversation) -> Res<ConvID> {
|
||||
.add_opt_str("logo", Option::from(&conv.logo))
|
||||
.add_legacy_bool("can_everyone_add_members", conv.can_everyone_add_members)
|
||||
.add_opt_group_id("group_id", conv.group_id.clone())
|
||||
.add_opt_u32("min_group_membership_level",
|
||||
conv.group_min_membership_level.as_ref().map(|s| s.to_db()))
|
||||
.insert()?
|
||||
.map(|i| ConvID::new(i))
|
||||
.ok_or(ExecError::new("missing result conv id!"))?;
|
||||
|
||||
// Add the creator of the conversation
|
||||
add_member(conv_id, &conv.owner_id, conv.owner_following, true, &conv.owner_id)?;
|
||||
// Initialize the list of members of the group
|
||||
if conv.group_id.is_some() {
|
||||
update_members_list_for_group_conversation(conv_id)?;
|
||||
} else {
|
||||
// Add the creator of the conversation
|
||||
add_member(conv_id, &conv.owner_id, conv.owner_following, true, Some(&conv.owner_id))?;
|
||||
|
||||
// Add other members to the conversation
|
||||
for member in &conv.members {
|
||||
if !member.eq(&conv.owner_id) {
|
||||
add_member(conv_id, member, true, false, &conv.owner_id)?;
|
||||
// Add other members to the conversation
|
||||
for member in &conv.members {
|
||||
if !member.eq(&conv.owner_id) {
|
||||
add_member(conv_id, member, true, false, Some(&conv.owner_id))?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(conv_id)
|
||||
}
|
||||
|
||||
/// Create a conversation for a group
|
||||
pub fn create_conversation_for_group(group_id: GroupID, min_membership_level: GroupMembershipLevel, name: &String) -> Res<ConvID> {
|
||||
create(&NewConversation {
|
||||
owner_id: UserID::invalid(),
|
||||
name: Some(name.to_string()),
|
||||
group_id: Some(group_id),
|
||||
group_min_membership_level: Some(min_membership_level),
|
||||
color: None,
|
||||
logo: None,
|
||||
owner_following: false,
|
||||
members: Default::default(),
|
||||
can_everyone_add_members: false,
|
||||
})
|
||||
}
|
||||
|
||||
/// Add a member to a conversation
|
||||
pub fn add_member(conv_id: ConvID, user_id: &UserID, following: bool, admin: bool, adder: &UserID) -> Res {
|
||||
pub fn add_member(conv_id: ConvID, user_id: &UserID, following: bool, admin: bool, adder: Option<&UserID>) -> Res {
|
||||
InsertQuery::new(CONV_MEMBERS_TABLE)
|
||||
.add_conv_id("conv_id", conv_id)
|
||||
.add_user_id("user_id", user_id)
|
||||
@ -54,21 +78,25 @@ pub fn add_member(conv_id: ConvID, user_id: &UserID, following: bool, admin: boo
|
||||
.add_u64("last_message_seen", 0)
|
||||
.insert()?;
|
||||
|
||||
// Create a message
|
||||
if adder != user_id {
|
||||
send_message(
|
||||
&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserAddedAnotherUserToConversation(UserAddedAnotherUserToConversation {
|
||||
user_who_added: adder.clone(),
|
||||
user_added: user_id.clone(),
|
||||
}),
|
||||
)
|
||||
)?;
|
||||
} else {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id, ConversationServerMessageType::UserCreatedConversation(user_id.clone()),
|
||||
))?;
|
||||
// Send the messages (if possible, no messages are created for groups conversations)
|
||||
if let Some(adder) = adder {
|
||||
|
||||
// Create a message
|
||||
if adder != user_id {
|
||||
send_message(
|
||||
&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserAddedAnotherUserToConversation(UserAddedAnotherUserToConversation {
|
||||
user_who_added: adder.clone(),
|
||||
user_added: user_id.clone(),
|
||||
}),
|
||||
)
|
||||
)?;
|
||||
} else {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id, ConversationServerMessageType::UserCreatedConversation(user_id.clone()),
|
||||
))?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
@ -427,10 +455,50 @@ pub fn remove_user_from_conversation(user_id: &UserID, conv: &Conversation, remo
|
||||
if conv.is_last_admin(user_id) {
|
||||
delete_conversation(conv)
|
||||
} else {
|
||||
remove_member(user_id, conv.id, remover)
|
||||
remove_member(user_id, conv.id, Some(remover))
|
||||
}
|
||||
}
|
||||
|
||||
/// Update the list of members for a group conversation
|
||||
pub fn update_members_list_for_group_conversation(conv_id: ConvID) -> Res {
|
||||
let conv = get_single(conv_id)?;
|
||||
|
||||
if !conv.is_linked_to_group() {
|
||||
return Err(ExecError::boxed_new("Attempted to update members list for a non-group conversation!"));
|
||||
}
|
||||
|
||||
let group_members = groups_helper::get_list_members(conv.group_id.as_ref().unwrap())?;
|
||||
|
||||
// Add missing memberships / Update existing invalid memberships
|
||||
for member in &group_members {
|
||||
let conv_member = conv.members.iter().filter(|f| f.user_id == member.user_id).next();
|
||||
|
||||
if let Some(conv_member) = conv_member {
|
||||
// Update admin status, if required
|
||||
if conv_member.is_admin != member.is_admin() {
|
||||
set_admin(&conv_id, &member.user_id, member.is_admin())?;
|
||||
}
|
||||
}
|
||||
|
||||
// Create the member
|
||||
else if conv.min_group_membership_level.as_ref().unwrap() >= &member.level {
|
||||
add_member(conv_id, &member.user_id, true, member.is_admin(), None)?;
|
||||
}
|
||||
}
|
||||
|
||||
// Remove memberships that have to be removed
|
||||
for conv_member in &conv.members {
|
||||
let member = group_members.iter().filter(|m| m.user_id == conv_member.user_id).next();
|
||||
|
||||
// Remove the member, if required
|
||||
if member.is_none() || conv.min_group_membership_level.as_ref().unwrap() < &member.unwrap().level {
|
||||
remove_member(&conv_member.user_id, conv_id, None)?;
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove permanently a conversation
|
||||
pub fn delete_conversation(conv: &Conversation) -> ResultBoxError<()> {
|
||||
// Delete all the messages of the conversations
|
||||
@ -460,7 +528,7 @@ pub fn delete_conversation(conv: &Conversation) -> ResultBoxError<()> {
|
||||
}
|
||||
|
||||
/// Delete a conversation membership
|
||||
pub fn remove_member(user_id: &UserID, conv_id: ConvID, remover: &UserID) -> ResultBoxError<()> {
|
||||
pub fn remove_member(user_id: &UserID, conv_id: ConvID, remover: Option<&UserID>) -> ResultBoxError<()> {
|
||||
for msg in get_user_messages_for_conversations(conv_id, user_id)? {
|
||||
delete_message(&msg)?;
|
||||
}
|
||||
@ -472,19 +540,21 @@ pub fn remove_member(user_id: &UserID, conv_id: ConvID, remover: &UserID) -> Res
|
||||
.exec()?;
|
||||
|
||||
// Create a message
|
||||
if remover == user_id {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserLeftConversation(user_id.clone()),
|
||||
))?;
|
||||
} else {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserRemovedFromConversation(UserRemovedAnotherUserToConversation {
|
||||
user_who_removed: remover.clone(),
|
||||
user_removed: user_id.clone(),
|
||||
}),
|
||||
))?;
|
||||
if let Some(remover) = remover {
|
||||
if remover == user_id {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserLeftConversation(user_id.clone()),
|
||||
))?;
|
||||
} else {
|
||||
send_message(&NewConversationMessage::new_server_message(
|
||||
conv_id,
|
||||
ConversationServerMessageType::UserRemovedFromConversation(UserRemovedAnotherUserToConversation {
|
||||
user_who_removed: remover.clone(),
|
||||
user_removed: user_id.clone(),
|
||||
}),
|
||||
))?;
|
||||
}
|
||||
}
|
||||
|
||||
// Propagate event
|
||||
@ -537,6 +607,8 @@ fn db_to_conversation_info(row: &database::RowResult) -> ResultBoxError<Conversa
|
||||
last_activity: row.get_u64("last_activity")?,
|
||||
creation_time: row.get_u64("creation_time")?,
|
||||
group_id: row.get_optional_group_id("group_id")?,
|
||||
min_group_membership_level: row.get_optional_u32("min_group_membership_level")?
|
||||
.map(GroupMembershipLevel::from_db),
|
||||
})
|
||||
}
|
||||
|
||||
|
@ -325,6 +325,13 @@ impl<'a> RowResult<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_optional_u32(&self, name: &str) -> ResultBoxError<Option<u32>> {
|
||||
match self.is_null(name)? {
|
||||
true => Ok(None),
|
||||
false => Ok(Some(self.get_u32(name)?))
|
||||
}
|
||||
}
|
||||
|
||||
/// Get an optional unsigned number => Set to None if value is null / empty / 0
|
||||
pub fn get_optional_positive_u64(&self, name: &str) -> ResultBoxError<Option<u64>> {
|
||||
Ok(match self.get_optional_u64(name)? {
|
||||
@ -615,6 +622,14 @@ impl InsertQuery {
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an optional number. If None, Null will be inserted
|
||||
pub fn add_opt_u32(mut self, key: &str, value: Option<u32>) -> InsertQuery {
|
||||
self.values.insert(key.to_string(), value
|
||||
.map(|u| Value::UInt(u as u64))
|
||||
.unwrap_or(Value::NULL));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add an optional user ID. If None, Null will be inserted
|
||||
pub fn add_opt_user_id(self, key: &str, value: Option<UserID>) -> InsertQuery {
|
||||
self.add_opt_u64(key, value.map(|u| u.id()))
|
||||
|
@ -487,6 +487,8 @@ pub fn delete(group_id: &GroupID) -> ResultBoxError {
|
||||
// Delete all group related notifications
|
||||
notifications_helper::delete_all_related_with_group(group_id)?;
|
||||
|
||||
// TODO : delete all conversations related with the group
|
||||
|
||||
// Delete all group members
|
||||
database::DeleteQuery::new(GROUPS_MEMBERS_TABLE)
|
||||
.cond_group_id("groups_id", group_id)
|
||||
|
@ -227,6 +227,7 @@ pub fn get_routes() -> Vec<Route> {
|
||||
Route::post("/groups/checkVirtualDirectory", Box::new(groups_controller::check_virtual_dir)),
|
||||
Route::post("/groups/upload_logo", Box::new(groups_controller::upload_logo)),
|
||||
Route::post("/groups/delete_logo", Box::new(groups_controller::delete_logo)),
|
||||
Route::post("/groups/create_conversation", Box::new(groups_controller::create_conversation)),
|
||||
Route::post("/groups/get_members", Box::new(groups_controller::get_members)),
|
||||
Route::post("/groups/invite", Box::new(groups_controller::invite_user)),
|
||||
Route::post("/groups/cancel_invitation", Box::new(groups_controller::cancel_invitation)),
|
||||
|
Loading…
Reference in New Issue
Block a user