Re-structure Permissions; add perm to view users from mutual groups.

This commit is contained in:
Paul Makles
2021-01-26 21:12:23 +00:00
parent 23ec2d61f1
commit f42480886b
17 changed files with 210 additions and 58 deletions

View File

@@ -1,4 +1,8 @@
use crate::database::*;
use crate::util::result::Result;
use super::PermissionCalculator;
use num_enum::TryFromPrimitive;
use std::ops;
@@ -21,40 +25,90 @@ bitfield! {
impl_op_ex!(+ |a: &ChannelPermission, b: &ChannelPermission| -> u32 { *a as u32 | *b as u32 });
impl_op_ex_commutative!(+ |a: &u32, b: &ChannelPermission| -> u32 { *a | *b as u32 });
pub async fn calculate(user: &User, target: &Channel) -> ChannelPermissions<[u32; 1]> {
/*pub async fn calculate(user: &User, target: &Channel) -> Result<u32> {
match target {
Channel::SavedMessages { user: owner, .. } => {
if &user.id == owner {
ChannelPermissions([ChannelPermission::View
Ok(ChannelPermission::View
+ ChannelPermission::SendMessage
+ ChannelPermission::ManageMessages])
+ ChannelPermission::ManageMessages)
} else {
ChannelPermissions([0])
Ok(0)
}
}
Channel::DirectMessage { recipients, .. } => {
if recipients.iter().find(|x| *x == &user.id).is_some() {
if let Some(recipient) = recipients.iter().find(|x| *x != &user.id) {
let perms = super::user::calculate(&user, recipient).await;
let perms = super::user::get(&user, recipient).await?;
if perms.get_send_message() {
return ChannelPermissions([
ChannelPermission::View + ChannelPermission::SendMessage
]);
return Ok(ChannelPermission::View + ChannelPermission::SendMessage);
}
return ChannelPermissions([ChannelPermission::View as u32]);
return Ok(ChannelPermission::View as u32);
}
}
ChannelPermissions([0])
Ok(0)
}
Channel::Group { recipients, .. } => {
if recipients.iter().find(|x| *x == &user.id).is_some() {
ChannelPermissions([ChannelPermission::View + ChannelPermission::SendMessage])
Ok(ChannelPermission::View + ChannelPermission::SendMessage)
} else {
ChannelPermissions([0])
Ok(0)
}
}
}
}
pub async fn get(user: &User, target: &Channel) -> Result<ChannelPermissions<[u32; 1]>> {
Ok(ChannelPermissions([calculate(&user, &target).await?]))
}*/
impl<'a> PermissionCalculator<'a> {
pub async fn calculate_channel(self) -> Result<u32> {
let channel = if let Some(channel) = self.channel {
channel
} else {
unreachable!()
};
match channel {
Channel::SavedMessages { user: owner, .. } => {
if &self.perspective.id == owner {
Ok(ChannelPermission::View
+ ChannelPermission::SendMessage
+ ChannelPermission::ManageMessages)
} else {
Ok(0)
}
}
Channel::DirectMessage { recipients, .. } => {
if recipients.iter().find(|x| *x == &self.perspective.id).is_some() {
if let Some(recipient) = recipients.iter().find(|x| *x != &self.perspective.id) {
let perms = self.for_user(recipient).await?;
if perms.get_send_message() {
return Ok(ChannelPermission::View + ChannelPermission::SendMessage);
}
return Ok(ChannelPermission::View as u32);
}
}
Ok(0)
}
Channel::Group { recipients, .. } => {
if recipients.iter().find(|x| *x == &self.perspective.id).is_some() {
Ok(ChannelPermission::View + ChannelPermission::SendMessage)
} else {
Ok(0)
}
}
}
}
pub async fn for_channel(self) -> Result<ChannelPermissions<[u32; 1]>> {
Ok(ChannelPermissions([ self.calculate_channel().await? ]))
}
}

View File

@@ -1,4 +1,38 @@
pub use crate::database::*;
pub mod channel;
pub mod user;
pub use user::get_relationship;
pub struct PermissionCalculator<'a> {
perspective: &'a User,
user: Option<&'a User>,
channel: Option<&'a Channel>,
}
impl<'a> PermissionCalculator<'a> {
pub fn new(perspective: &'a User) -> PermissionCalculator {
PermissionCalculator {
perspective,
user: None,
channel: None
}
}
pub fn with_user(self, user: &'a User) -> PermissionCalculator {
PermissionCalculator {
user: Some(&user),
..self
}
}
pub fn with_channel(self, channel: &'a Channel) -> PermissionCalculator {
PermissionCalculator {
channel: Some(&channel),
..self
}
}
}

View File

@@ -1,52 +1,33 @@
use crate::database::*;
use num_enum::TryFromPrimitive;
use crate::util::result::{Error, Result};
use super::PermissionCalculator;
use std::ops;
use mongodb::bson::doc;
use num_enum::TryFromPrimitive;
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, Copy, Clone)]
#[repr(u32)]
pub enum UserPermission {
Access = 1,
SendMessage = 2,
Invite = 4,
ViewProfile = 2,
SendMessage = 4,
Invite = 8
}
bitfield! {
pub struct UserPermissions(MSB0 [u32]);
u32;
pub get_access, _: 31;
pub get_send_message, _: 30;
pub get_invite, _: 29;
pub get_view_profile, _: 30;
pub get_send_message, _: 29;
pub get_invite, _: 28;
}
impl_op_ex!(+ |a: &UserPermission, b: &UserPermission| -> u32 { *a as u32 | *b as u32 });
impl_op_ex_commutative!(+ |a: &u32, b: &UserPermission| -> u32 { *a | *b as u32 });
pub async fn calculate(user: &User, target: &str) -> UserPermissions<[u32; 1]> {
// if friends; Access + Message + Invite
// if mutually know each other:
// and has DMs from users enabled -> Access + Message
// otherwise -> Access
// otherwise; None
let mut permissions: u32 = 0;
match get_relationship(&user, &target) {
RelationshipStatus::Friend => {
return UserPermissions([UserPermission::Access
+ UserPermission::SendMessage
+ UserPermission::Invite])
}
RelationshipStatus::Blocked | RelationshipStatus::BlockedOther => {
return UserPermissions([UserPermission::Access as u32])
}
RelationshipStatus::Incoming | RelationshipStatus::Outgoing => {
permissions = UserPermission::Access as u32;
}
_ => {}
}
UserPermissions([permissions])
}
pub fn get_relationship(a: &User, b: &str) -> RelationshipStatus {
if a.id == b {
return RelationshipStatus::Friend;
@@ -60,3 +41,53 @@ pub fn get_relationship(a: &User, b: &str) -> RelationshipStatus {
RelationshipStatus::None
}
impl<'a> PermissionCalculator<'a> {
pub async fn calculate_user(self, target: &str) -> Result<u32> {
let mut permissions: u32 = 0;
match get_relationship(&self.perspective, &target) {
RelationshipStatus::Friend => {
return Ok(u32::MAX)
}
RelationshipStatus::Blocked | RelationshipStatus::BlockedOther => {
return Ok(UserPermission::Access as u32)
}
RelationshipStatus::Incoming | RelationshipStatus::Outgoing => {
permissions = UserPermission::Access as u32;
// ! INFO: if we add boolean switch for permission to
// ! message people who have mutual, we need to get
// ! rid of this return statement.
return Ok(permissions);
}
_ => {}
}
if get_collection("channels")
.find_one(
doc! {
"type": "Group",
"$and": {
"recipients": &self.perspective.id,
"recipients": target
}
},
None
)
.await
.map_err(|_| Error::DatabaseError { operation: "find", with: "channels" })?
.is_some() {
return Ok(UserPermission::Access as u32);
}
Ok(permissions)
}
pub async fn for_user(self, target: &str) -> Result<UserPermissions<[u32; 1]>> {
Ok(UserPermissions([ self.calculate_user(&target).await? ]))
}
pub async fn for_user_given(self) -> Result<UserPermissions<[u32; 1]>> {
let id = &self.user.unwrap().id;
Ok(UserPermissions([ self.calculate_user(&id).await? ]))
}
}