From b89a319cfb1157375c5326c6da1c49d15039c4c6 Mon Sep 17 00:00:00 2001 From: Pierre HUBERT Date: Wed, 24 Jun 2020 14:08:46 +0200 Subject: [PATCH] Determine access level of a user over a group --- src/data/group.rs | 2 +- src/data/group_member.rs | 1 + src/data/http_request_handler.rs | 2 + src/helpers/database.rs | 10 ++++ src/helpers/groups_helper.rs | 89 +++++++++++++++++++++++++++++++- 5 files changed, 102 insertions(+), 2 deletions(-) diff --git a/src/data/group.rs b/src/data/group.rs index 22373f1..c360510 100644 --- a/src/data/group.rs +++ b/src/data/group.rs @@ -11,7 +11,7 @@ pub enum GroupVisibilityLevel { } #[allow(non_camel_case_types)] -#[derive(Eq, PartialEq, Hash)] +#[derive(Eq, PartialEq, Hash, Debug)] pub enum GroupAccessLevel { //Can not even know if the group exists or not NO_ACCESS = 0, diff --git a/src/data/group_member.rs b/src/data/group_member.rs index ceedcd5..5fd9fd8 100644 --- a/src/data/group_member.rs +++ b/src/data/group_member.rs @@ -5,6 +5,7 @@ use crate::data::user::UserID; use crate::data::group_id::GroupID; +#[derive(PartialEq, Eq)] pub enum GroupMembershipLevel { ADMINISTRATOR = 0, MODERATOR = 1, diff --git a/src/data/http_request_handler.rs b/src/data/http_request_handler.rs index a157e17..e606a57 100644 --- a/src/data/http_request_handler.rs +++ b/src/data/http_request_handler.rs @@ -465,8 +465,10 @@ impl HttpRequestHandler { /// Get the ID of a group included in a request with a check for access level of current user pub fn post_group_id_with_access(&mut self, name: &str, min_level: GroupAccessLevel) -> ResultBoxError { let group_id = self.post_group_id(name)?; + let access_level = groups_helper::get_access_level(&group_id, self.user_id_opt())?; // TODO : add security checks + println!("Curr access level: {:?} / Expected: {:?}", access_level, min_level); Ok(group_id) } diff --git a/src/helpers/database.rs b/src/helpers/database.rs index 83c2c0c..8a661e8 100644 --- a/src/helpers/database.rs +++ b/src/helpers/database.rs @@ -261,6 +261,16 @@ impl<'a> RowResult<'a> { } } + pub fn get_u32(&self, name: &str) -> ResultBoxError { + let value = self.row.get_opt(self.find_col(name)?); + + match value { + None => Err(ExecError::boxed_string( + format!("Could not extract integer field {} !", name))), + Some(s) => Ok(s?) + } + } + /// Find an integer included in the request pub fn get_usize(&self, name: &str) -> Result> { let value = self.row.get_opt(self.find_col(name)?); diff --git a/src/helpers/groups_helper.rs b/src/helpers/groups_helper.rs index 53c1fad..7ecd218 100644 --- a/src/helpers/groups_helper.rs +++ b/src/helpers/groups_helper.rs @@ -4,7 +4,7 @@ use crate::constants::database_tables_names::{GROUPS_LIST_TABLE, GROUPS_MEMBERS_TABLE}; use crate::data::error::{ExecError, ResultBoxError}; -use crate::data::group::GroupVisibilityLevel; +use crate::data::group::{GroupAccessLevel, GroupVisibilityLevel}; use crate::data::group_id::GroupID; use crate::data::group_member::{GroupMember, GroupMembershipLevel}; use crate::data::new_group::NewGroup; @@ -20,6 +20,15 @@ impl GroupVisibilityLevel { GroupVisibilityLevel::SECRETE_GROUP => 2, } } + + pub fn from_db(level: u32) -> GroupVisibilityLevel { + match level { + 0 => GroupVisibilityLevel::OPEN_GROUP, + 1 => GroupVisibilityLevel::PRIVATE_GROUP, + 2 => GroupVisibilityLevel::SECRETE_GROUP, + _ => GroupVisibilityLevel::SECRETE_GROUP + } + } } impl GroupMembershipLevel { @@ -33,6 +42,18 @@ impl GroupMembershipLevel { GroupMembershipLevel::VISITOR => 5, } } + + pub fn from_db(level: u32) -> GroupMembershipLevel { + match level { + 0 => GroupMembershipLevel::ADMINISTRATOR, + 1 => GroupMembershipLevel::MODERATOR, + 2 => GroupMembershipLevel::MEMBER, + 3 => GroupMembershipLevel::INVITED, + 4 => GroupMembershipLevel::PENDING, + 5 => GroupMembershipLevel::VISITOR, + _ => GroupMembershipLevel::VISITOR + } + } } /// Create a new group. Returns the ID of the new group @@ -106,4 +127,70 @@ pub fn search_group(query: &str, limit: u64) -> ResultBoxError> { .set_limit(limit) .add_field("id") .exec(|row| row.get_group_id("id")) +} + +/// 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 { + None => Ok(GroupMembershipLevel::VISITOR), + Some(user_id) => { + let level = database::QueryInfo::new(GROUPS_MEMBERS_TABLE) + .cond_group_id("groups_id", group_id) + .cond_user_id("user_id", user_id) + .add_field("level") + .query_row(|f| f.get_u32("level")) + .unwrap_or(GroupMembershipLevel::VISITOR.to_db()); + + Ok(GroupMembershipLevel::from_db(level)) + } + } +} + +/// Get the visibility level of a group +pub fn get_visibility(group_id: &GroupID) -> ResultBoxError { + let result = database::QueryInfo::new(GROUPS_LIST_TABLE) + .cond_group_id("id", group_id) + .add_field("visibility") + .query_row(|f| f.get_u32("visibility"))?; + + Ok(GroupVisibilityLevel::from_db(result)) +} + +/// Get the current access level of a user over a group +pub fn get_access_level(group_id: &GroupID, user_id: Option) -> ResultBoxError { + let membership_level = get_membership_level(group_id, user_id)?; + + // Check if the user is a confirmed member of group + if membership_level == GroupMembershipLevel::ADMINISTRATOR { + return Ok(GroupAccessLevel::ADMIN_ACCESS); + } + if membership_level == GroupMembershipLevel::MODERATOR { + return Ok(GroupAccessLevel::MODERATOR_ACCESS); + } + if membership_level == GroupMembershipLevel::MEMBER { + return Ok(GroupAccessLevel::MEMBER_ACCESS); + } + + let visibility_level = get_visibility(group_id)?; + + + //If the group is open, everyone has view access + if visibility_level == GroupVisibilityLevel::OPEN_GROUP { + return Ok(GroupAccessLevel::VIEW_ACCESS); + } + + //Else, all pending and invited membership get limited access + if membership_level == GroupMembershipLevel::PENDING || + membership_level == GroupMembershipLevel::INVITED { + return Ok(GroupAccessLevel::LIMITED_ACCESS); + } + + //Private groups gives limited access + if visibility_level == GroupVisibilityLevel::PRIVATE_GROUP { + return Ok(GroupAccessLevel::LIMITED_ACCESS); + } + + // Else the user can not see the group + // Especially in the case of secrete group + Ok(GroupAccessLevel::NO_ACCESS) } \ No newline at end of file