//! # Groups controller //! //! @author Pierre Hubert use std::collections::HashMap; 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_group::GroupCreationResult; use crate::constants::{DEFAULT_GROUP_LOGO, PATH_GROUPS_LOGOS}; use crate::controllers::routes::RequestResult; use crate::data::error::ExecError; 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::helpers::{groups_helper, virtual_directory_helper}; use crate::helpers::virtual_directory_helper::VirtualDirType; use crate::utils::date_utils::time; /// Create a new group pub fn create(r: &mut HttpRequestHandler) -> RequestResult { let new_group = NewGroup { name: r.post_string_opt("name", 3, true)?, owner_id: r.user_id()?, }; let group_id = groups_helper::create(&new_group)?; r.set_response(GroupCreationResult::new(&group_id)) } /// Get the list of groups of the current user pub fn get_list_user(r: &mut HttpRequestHandler) -> RequestResult { let list = groups_helper::get_list_user(r.user_id()?, false)? .iter() .map(|f| f.id()) .collect::>(); r.set_response(list) } /// Get information about a single group pub fn get_info_single(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::LIMITED_ACCESS)?; let group = groups_helper::get_info(&group_id)?; r.set_response(GroupApi::new(&group, r.user_id_opt())?) } /// Get information about multiple users pub fn get_info_multiple(r: &mut HttpRequestHandler) -> RequestResult { let groups_id = r.post_numbers_list("list", 1)?; let mut list = HashMap::new(); for id in groups_id { let id = GroupID::new(id as u64); if !groups_helper::exists(&id)? || groups_helper::get_access_level(&id, r.user_id_opt())? < GroupAccessLevel::LIMITED_ACCESS { r.not_found(format!("Group {} not found!", id.id()))?; } let group = groups_helper::get_info(&id)?; list.insert(id.id().to_string(), GroupApi::new(&group, r.user_id_opt())?); } r.set_response(list) } /// Get advanced information about a user pub fn get_advanced_info(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::VIEW_ACCESS)?; let group = groups_helper::get_info(&group_id)?; r.set_response(AdvancedGroupApi::new(&group, r.user_id_opt())?) } /// Get the settings of the group pub fn get_settings(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::ADMIN_ACCESS)?; let group = groups_helper::get_info(&group_id)?; // For now, this method is the same as the get advanced info method, // but this might change in the future... r.set_response(AdvancedGroupApi::new(&group, r.user_id_opt())?) } /// Set new settings to the group pub fn set_settings(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::ADMIN_ACCESS)?; let new_settings = Group { id: group_id.clone(), name: r.post_string_without_html("name", 3, true)?, visibility: GroupVisibilityLevel::from_api(&r.post_string("visibility")?), registration_level: GroupRegistrationLevel::from_api(&r.post_string("registration_level")?), posts_creation_level: GroupPostsCreationLevel::from_api(&r.post_string("posts_level")?), logo: None, virtual_directory: r.post_checked_virtual_directory_opt("virtual_directory", group_id.id(), VirtualDirType::GROUP)?, time_create: 0, description: r.post_string_without_html_opt("description", 0)?, url: r.post_url_opt("url", false)?, }; groups_helper::set_settings(&new_settings)?; r.success("Group settings have been successfully updated!") } /// Check out whether a virtual directory is available for a group or not pub fn check_virtual_dir(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::ADMIN_ACCESS)?; let dir = r.post_virtual_directory("directory")?; if !virtual_directory_helper::check_availability(&dir, group_id.id(), VirtualDirType::GROUP)? { r.forbidden("The requested virtual directory seems not to be available!".to_string())?; } r.success("Requested virtual directory seems to be available!") } /// Change a group's logo pub fn upload_logo(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::ADMIN_ACCESS)?; if !r.has_file("logo") { r.bad_request("Did not receive logo!".to_string())?; } groups_helper::delete_logo(&group_id)?; let logo_path = r.save_post_image("logo", PATH_GROUPS_LOGOS, 500, 500)?; groups_helper::set_logo_path(&group_id, Some(logo_path.clone()))?; r.set_response(ResChangeGroupLogo::new(&logo_path)) } /// Delete a group's logo pub fn delete_logo(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::ADMIN_ACCESS)?; groups_helper::delete_logo(&group_id)?; r.set_response(ResChangeGroupLogo::new(DEFAULT_GROUP_LOGO)) } /// Get the list of members of a group pub fn get_members(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::MODERATOR_ACCESS)?; let members = groups_helper::get_list_members(&group_id)?; r.set_response(GroupMemberAPI::for_list(&members)) } /// Cancel an invitation sent to a user pub fn cancel_invitation(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::MODERATOR_ACCESS)?; let user_id = r.post_user_id("userID")?; if groups_helper::get_membership_level(&group_id, Some(user_id.clone()))? != GroupMembershipLevel::INVITED { r.forbidden("This user has not been invited to join this group!".to_string())?; } groups_helper::delete_member(&group_id, &user_id)?; // TODO : delete related notifications r.success("Membership invitation has been cancelled!") } /// Invite a user to join a group pub fn invite_user(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("group_id", GroupAccessLevel::MODERATOR_ACCESS)?; let user_id = r.post_user_id("userID")?; if groups_helper::get_membership_level(&group_id, Some(user_id.clone()))? != GroupMembershipLevel::VISITOR { r.bad_request("The user is not a visitor of the group!".to_string())?; } groups_helper::send_invitation(&group_id, &user_id)?; // TODO : send a notification r.success("The user has been successfully invited to join the group!") } /// Respond to a user invitation pub fn respond_invitation(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::LIMITED_ACCESS)?; let accept = r.post_bool("accept")?; if !groups_helper::received_invitation(&group_id, &r.user_id()?)? { r.not_found("Invitation not found!".to_string())? } groups_helper::respond_invitation(&group_id, &r.user_id()?, accept)?; if accept { groups_helper::set_following(&group_id, &r.user_id()?, true)?; } // TODO : Create a notification r.success("Response to the invitation was successfully saved!") } /// Send a request to join a group pub fn send_request(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::LIMITED_ACCESS)?; if groups_helper::get_membership_level(&group_id, r.user_id_opt())? != GroupMembershipLevel::VISITOR { r.forbidden("You are not currently a visitor of the group!".to_string())?; } let group = groups_helper::get_info(&group_id)?; let level = match group.registration_level { GroupRegistrationLevel::OPEN_REGISTRATION => GroupMembershipLevel::MEMBER, GroupRegistrationLevel::MODERATED_REGISTRATION => GroupMembershipLevel::PENDING, GroupRegistrationLevel::CLOSED_REGISTRATION => { r.forbidden("You are not authorized to send a registration request for this group!".to_string())?; unreachable!(); } }; groups_helper::insert_member(&GroupMember { id: 0, user_id: r.user_id()?, group_id, time_create: time(), level, following: true, })?; // TODO : Send a notification, if required r.success("The membership has been successfully saved!") } /// Cancel a group membership request pub fn cancel_request(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::LIMITED_ACCESS)?; if groups_helper::get_membership_level(&group_id, r.user_id_opt())? != GroupMembershipLevel::PENDING { r.forbidden("You did not send a membership request to this group!".to_string())?; } groups_helper::delete_member(&group_id, &r.user_id()?)?; // TODO : delete any related notification r.success("The request has been successfully cancelled!") } /// Remove a member from a group (as a moderator or an admin) pub fn delete_member(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::MODERATOR_ACCESS)?; // Get the membership of the user making the request let curr_user_membership = groups_helper::get_membership(&group_id, r.user_id_opt())?; // Get information about the member to delete let user_id = r.post_user_id("userID")?; let membership = groups_helper::get_membership(&group_id, Some(user_id.clone()))?; if user_id == r.user_id()? && groups_helper::is_last_admin(&group_id, &r.user_id()?)? { r.forbidden("You are the last administrator of this group!".to_string())?; } // Only administrator can delete members that are more than members (moderators & administrators) if membership.level < GroupMembershipLevel::MEMBER && curr_user_membership.level != GroupMembershipLevel::ADMINISTRATOR { r.forbidden("Only administrators can delete this membership!".to_string())?; } groups_helper::delete_member(&group_id, &user_id)?; // TODO : Delete related notifications r.success("Membership of the user has been successfully deleted!") } /// Update a user's membership pub fn update_membership(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::ADMIN_ACCESS)?; let user_id = r.post_user_id("userID")?; if user_id == r.user_id()? { r.bad_request("You can not update your own membership!".to_string())?; } let level = groups_helper::get_membership_level(&group_id, Some(user_id.clone()))?; if level > GroupMembershipLevel::MEMBER { r.forbidden("This user is not a member of the group!".to_string())?; } let new_level = GroupMembershipLevel::from_api(&r.post_string("level")?); if new_level > GroupMembershipLevel::MEMBER { r.forbidden("You can not assign this visibility level!".to_string())?; } groups_helper::update_membership_level(&group_id, &user_id, new_level)?; r.success("User membership has been successfully updated!") } /// Respond to a group membership request pub fn respond_request(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::MODERATOR_ACCESS)?; let user_id = r.post_user_id("userID")?; let accept = r.post_bool("accept")?; if groups_helper::get_membership_level(&group_id, Some(user_id.clone()))? != GroupMembershipLevel::PENDING { r.forbidden("This user has not requested a membership for this group!".to_string())?; } groups_helper::respond_request(&group_id, &user_id, accept)?; // TODO : Create a notification r.success("The response to the request has been successfully saved!") } /// Get information about a single user membership over a group pub fn get_membership(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::MODERATOR_ACCESS)?; let user_id = r.post_user_id("userID")?; let membership = groups_helper::get_membership(&group_id, Some(user_id))?; r.set_response(GroupMemberAPI::new(&membership)) } /// Delete the membership of a user over a group pub fn remove_membership(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("id", GroupAccessLevel::LIMITED_ACCESS)?; if groups_helper::is_last_admin(&group_id, &r.user_id()?)? { r.forbidden("You are the last administrator of this group!".to_string())?; } groups_helper::delete_member(&group_id, &r.user_id()?)?; // TODO : delete group membership notifications r.success("Your membership has been successfully deleted!") } /// Update following status over a group pub fn set_following(r: &mut HttpRequestHandler) -> RequestResult { let group_id = r.post_group_id_with_access("groupID", GroupAccessLevel::MEMBER_ACCESS)?; let following = r.post_bool("follow")?; groups_helper::set_following(&group_id, &r.user_id()?, following)?; r.success("Following status updated.") } /// Delete a group pub fn delete_group(r: &mut HttpRequestHandler) -> RequestResult { // TODO : implement groups deletion r.internal_error(ExecError::boxed_new("Method not implemented yet")) }