diff --git a/src/api_data/group_api.rs b/src/api_data/group_api.rs new file mode 100644 index 0000000..cfa86bc --- /dev/null +++ b/src/api_data/group_api.rs @@ -0,0 +1,44 @@ +//! # Group information api +//! +//! @author Pierre Hubert +use serde::Serialize; + +use crate::data::error::ResultBoxError; +use crate::data::group::Group; +use crate::data::user::UserID; +use crate::helpers::groups_helper; + +#[derive(Serialize)] +pub struct GroupApi { + id: u64, + name: String, + icon_url: String, + number_members: u64, + visibility: String, + registration_level: String, + posts_level: String, + virtual_directory: String, + membership: String, + following: bool, +} + +impl GroupApi { + /// Construct a new group membership instance + pub fn new(g: &Group, user_id: Option) -> ResultBoxError { + let membership = groups_helper::get_membership(&g.id, user_id)?; + + Ok(GroupApi { + id: g.id.id(), + name: g.name.clone(), + icon_url: g.get_logo_url(), + number_members: groups_helper::count_members(&g.id)? as u64, + visibility: g.visibility.to_api(), + registration_level: g.registration_level.to_api(), + posts_level: g.posts_creation_level.to_api(), + virtual_directory: g.virtual_directory.clone().unwrap_or("null".to_string()), + + membership: membership.level.to_api(), + following: membership.following, + }) + } +} \ No newline at end of file diff --git a/src/api_data/mod.rs b/src/api_data/mod.rs index 17d2360..785f64a 100644 --- a/src/api_data/mod.rs +++ b/src/api_data/mod.rs @@ -23,4 +23,5 @@ pub mod conversations_refresh_api; pub mod res_count_unread_conversations; pub mod list_unread_conversations_api; pub mod global_search_result_api; -pub mod res_create_group; \ No newline at end of file +pub mod res_create_group; +pub mod group_api; \ No newline at end of file diff --git a/src/constants.rs b/src/constants.rs index 270759c..c036e7a 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -42,5 +42,8 @@ pub const DEFAULT_ACCOUNT_IMAGE: &str = "avatars/0Reverse.png"; /// The account image to show for users who are not allowed to access other users account images pub const ERROR_ACCOUNT_IMAGE: &str = "avatars/0Red.png"; +/// The group logo to use when no custom logo have been uploaded +pub const DEFAULT_GROUP_LOGO: &str = "groups_logo/default.png"; + /// Maximum requests size (50 Mo) pub const MAX_REQUEST_SIZE: usize = 50000000; \ No newline at end of file diff --git a/src/controllers/groups_controller.rs b/src/controllers/groups_controller.rs index bdc00d1..f85ec20 100644 --- a/src/controllers/groups_controller.rs +++ b/src/controllers/groups_controller.rs @@ -8,6 +8,7 @@ use crate::data::group::GroupAccessLevel; use crate::data::http_request_handler::HttpRequestHandler; use crate::data::new_group::NewGroup; use crate::helpers::groups_helper; +use crate::api_data::group_api::GroupApi; /// Create a new group pub fn create(r: &mut HttpRequestHandler) -> RequestResult { @@ -36,7 +37,5 @@ 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)?; - println!("Group info: {:#?}", group); - - r.success("continue implementation") + r.set_response(GroupApi::new(&group, r.user_id_opt())?) } \ No newline at end of file diff --git a/src/data/group.rs b/src/data/group.rs index 9bd991c..86b6ab6 100644 --- a/src/data/group.rs +++ b/src/data/group.rs @@ -2,7 +2,9 @@ //! //! Group visibility level +use crate::constants::DEFAULT_GROUP_LOGO; use crate::data::group_id::GroupID; +use crate::utils::user_data_utils::user_data_url; #[allow(non_camel_case_types)] #[derive(Eq, PartialEq, Hash, Debug)] @@ -12,6 +14,16 @@ pub enum GroupVisibilityLevel { SECRETE_GROUP, } +impl GroupVisibilityLevel { + pub fn to_api(&self) -> String { + match self { + GroupVisibilityLevel::OPEN_GROUP => "open", + GroupVisibilityLevel::PRIVATE_GROUP => "private", + GroupVisibilityLevel::SECRETE_GROUP => "secrete", + }.to_string() + } +} + #[allow(non_camel_case_types)] #[derive(Eq, PartialEq, Hash, Debug)] pub enum GroupRegistrationLevel { @@ -20,6 +32,16 @@ pub enum GroupRegistrationLevel { CLOSED_REGISTRATION = 2, } +impl GroupRegistrationLevel { + pub fn to_api(&self) -> String { + match self { + GroupRegistrationLevel::OPEN_REGISTRATION => "open", + GroupRegistrationLevel::MODERATED_REGISTRATION => "moderated", + GroupRegistrationLevel::CLOSED_REGISTRATION => "closed", + }.to_string() + } +} + #[allow(non_camel_case_types)] #[derive(Eq, PartialEq, Hash, Debug)] pub enum GroupPostsCreationLevel { @@ -30,6 +52,15 @@ pub enum GroupPostsCreationLevel { POSTS_LEVEL_ALL_MEMBERS = 1, } +impl GroupPostsCreationLevel { + pub fn to_api(&self) -> String { + match self { + GroupPostsCreationLevel::POSTS_LEVEL_MODERATORS => "moderators", + GroupPostsCreationLevel::POSTS_LEVEL_ALL_MEMBERS => "members", + }.to_string() + } +} + #[allow(non_camel_case_types)] #[derive(Eq, PartialEq, Hash, Debug, PartialOrd)] pub enum GroupAccessLevel { @@ -57,7 +88,6 @@ pub enum GroupAccessLevel { pub struct Group { pub id: GroupID, pub name: String, - pub members_count: u64, pub visibility: GroupVisibilityLevel, pub registration_level: GroupRegistrationLevel, pub posts_creation_level: GroupPostsCreationLevel, @@ -68,6 +98,21 @@ pub struct Group { pub url: Option, } +impl Group { + /// Determine the path of the logo to use for this group + pub fn get_logo_path(&self) -> &str { + match &self.logo { + None => DEFAULT_GROUP_LOGO, + Some(l) => l, + } + } + + /// Get the current URL for the logo of this group + pub fn get_logo_url(&self) -> String { + user_data_url(self.get_logo_path()) + } +} + #[cfg(test)] mod tests { use crate::data::group::GroupAccessLevel; diff --git a/src/data/group_member.rs b/src/data/group_member.rs index 5fd9fd8..bc617d0 100644 --- a/src/data/group_member.rs +++ b/src/data/group_member.rs @@ -15,6 +15,19 @@ pub enum GroupMembershipLevel { VISITOR = 5, //Simple visit } +impl GroupMembershipLevel { + pub fn to_api(&self) -> String { + match self { + GroupMembershipLevel::ADMINISTRATOR => "administrator", + GroupMembershipLevel::MODERATOR => "moderator", + GroupMembershipLevel::MEMBER => "member", + GroupMembershipLevel::INVITED => "invited", + GroupMembershipLevel::PENDING => "pending", + GroupMembershipLevel::VISITOR => "visitor", + }.to_string() + } +} + pub struct GroupMember { pub id: u64, pub user_id: UserID, diff --git a/src/helpers/database.rs b/src/helpers/database.rs index 8a661e8..88fdf11 100644 --- a/src/helpers/database.rs +++ b/src/helpers/database.rs @@ -170,6 +170,12 @@ impl QueryInfo { self } + /// Add a custom u32 WHERE value + pub fn add_custom_where_argument_u32(mut self, val: u32) -> QueryInfo { + self.custom_where_ars.push(mysql::Value::UInt(val as u64)); + self + } + /// Add a custom string WHERE value pub fn add_custom_where_argument_str(mut self, val: &str) -> QueryInfo { self.custom_where_ars.push(mysql::Value::from(val)); diff --git a/src/helpers/groups_helper.rs b/src/helpers/groups_helper.rs index ae3ac2a..ee59ffb 100644 --- a/src/helpers/groups_helper.rs +++ b/src/helpers/groups_helper.rs @@ -172,6 +172,27 @@ pub fn search_group(query: &str, limit: u64) -> ResultBoxError> { .exec(|row| row.get_group_id("id")) } +/// Get information about the membership of a user over a group +pub fn get_membership(group_id: &GroupID, user_id: Option) -> ResultBoxError { + if user_id == None { + return Ok(GroupMember { + id: 0, + user_id: 0, + group_id: group_id.clone(), + time_create: 0, + level: GroupMembershipLevel::VISITOR, + following: false, + }); + } + + let user_id = user_id.unwrap(); + + database::QueryInfo::new(GROUPS_MEMBERS_TABLE) + .cond_group_id("groups_id", group_id) + .cond_user_id("user_id", user_id) + .query_row(db_to_group_member) +} + /// Get the membership level of a user for a group pub fn get_membership_level(group_id: &GroupID, user_id: Option) -> ResultBoxError { match user_id { @@ -242,17 +263,18 @@ pub fn get_access_level(group_id: &GroupID, user_id: Option) -> ResultBo pub fn count_members(group_id: &GroupID) -> ResultBoxError { database::QueryInfo::new(GROUPS_MEMBERS_TABLE) .cond_group_id("groups_id", group_id) + .set_custom_where("level <= ?") + .add_custom_where_argument_u32(GroupMembershipLevel::MEMBER.to_db()) .exec_count() } -/// Turn a database entry into a group object +/// Turn a database entry into a group struct fn db_to_group(row: &database::RowResult) -> ResultBoxError { let group_id = row.get_group_id("id")?; Ok(Group { id: group_id.clone(), name: row.get_str("name")?, - members_count: count_members(&group_id)? as u64, visibility: GroupVisibilityLevel::from_db(row.get_u32("visibility")?), registration_level: GroupRegistrationLevel::from_db(row.get_u32("registration_level")?), posts_creation_level: GroupPostsCreationLevel::from_db(row.get_u32("posts_level")?), @@ -262,4 +284,16 @@ fn db_to_group(row: &database::RowResult) -> ResultBoxError { description: row.get_optional_str("description")?, url: row.get_optional_str("url")?, }) +} + +/// Turn a database entry into a group member struct +fn db_to_group_member(row: &database::RowResult) -> ResultBoxError { + Ok(GroupMember { + id: row.get_u64("id")?, + user_id: row.get_user_id("user_id")?, + group_id: row.get_group_id("groups_id")?, + time_create: row.get_u64("time_create")?, + level: GroupMembershipLevel::from_db(row.get_u32("level")?), + following: row.get_legacy_bool("following")?, + }) } \ No newline at end of file