forked from jmug/stoatchat
229 lines
6.8 KiB
Rust
229 lines
6.8 KiB
Rust
use super::mutual::has_mutual_connection;
|
|
use crate::database::channel::Channel;
|
|
use crate::database::guild::{fetch_guild, fetch_member, Guild, Member, MemberKey};
|
|
use crate::database::user::{User, UserRelationship};
|
|
|
|
use num_enum::TryFromPrimitive;
|
|
|
|
#[derive(Debug, PartialEq, Eq, TryFromPrimitive)]
|
|
#[repr(u8)]
|
|
pub enum Relationship {
|
|
Friend = 0,
|
|
Outgoing = 1,
|
|
Incoming = 2,
|
|
Blocked = 3,
|
|
BlockedOther = 4,
|
|
NONE = 5,
|
|
SELF = 6,
|
|
}
|
|
|
|
#[derive(Debug, PartialEq, Eq, TryFromPrimitive, Copy, Clone)]
|
|
#[repr(u32)]
|
|
pub enum Permission {
|
|
Access = 1,
|
|
CreateInvite = 2,
|
|
KickMembers = 4,
|
|
BanMembers = 8,
|
|
ReadMessages = 16,
|
|
SendMessages = 32,
|
|
ManageMessages = 64,
|
|
ManageChannels = 128,
|
|
ManageServer = 256,
|
|
ManageRoles = 512,
|
|
SendDirectMessages = 1024,
|
|
}
|
|
|
|
bitfield! {
|
|
pub struct MemberPermissions(MSB0 [u32]);
|
|
u32;
|
|
pub get_access, set_access: 31;
|
|
pub get_create_invite, set_create_invite: 30;
|
|
pub get_kick_members, set_kick_members: 29;
|
|
pub get_ban_members, set_ban_members: 28;
|
|
pub get_read_messages, set_read_messages: 27;
|
|
pub get_send_messages, set_send_messages: 26;
|
|
pub get_manage_messages, set_manage_messages: 25;
|
|
pub get_manage_channels, set_manage_channels: 24;
|
|
pub get_manage_server, set_manage_server: 23;
|
|
pub get_manage_roles, set_manage_roles: 22;
|
|
pub get_send_direct_messages, set_send_direct_messages: 21;
|
|
}
|
|
|
|
pub fn get_relationship_internal(
|
|
user_id: &str,
|
|
target_id: &str,
|
|
relationships: &Option<Vec<UserRelationship>>,
|
|
) -> Relationship {
|
|
if user_id == target_id {
|
|
return Relationship::SELF;
|
|
}
|
|
|
|
if let Some(arr) = &relationships {
|
|
for entry in arr {
|
|
if entry.id == target_id {
|
|
match entry.status {
|
|
0 => return Relationship::Friend,
|
|
1 => return Relationship::Outgoing,
|
|
2 => return Relationship::Incoming,
|
|
3 => return Relationship::Blocked,
|
|
4 => return Relationship::BlockedOther,
|
|
_ => return Relationship::NONE,
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Relationship::NONE
|
|
}
|
|
|
|
pub fn get_relationship(a: &User, b: &User) -> Relationship {
|
|
if a.id == b.id {
|
|
return Relationship::SELF;
|
|
}
|
|
|
|
get_relationship_internal(&a.id, &b.id, &a.relations)
|
|
}
|
|
|
|
pub struct PermissionCalculator {
|
|
pub user: User,
|
|
pub channel: Option<Channel>,
|
|
pub guild: Option<Guild>,
|
|
pub member: Option<Member>,
|
|
}
|
|
|
|
impl PermissionCalculator {
|
|
pub fn new(user: User) -> PermissionCalculator {
|
|
PermissionCalculator {
|
|
user,
|
|
channel: None,
|
|
guild: None,
|
|
member: None,
|
|
}
|
|
}
|
|
|
|
pub fn channel(self, channel: Channel) -> PermissionCalculator {
|
|
PermissionCalculator {
|
|
channel: Some(channel),
|
|
..self
|
|
}
|
|
}
|
|
|
|
pub fn guild(self, guild: Guild) -> PermissionCalculator {
|
|
PermissionCalculator {
|
|
guild: Some(guild),
|
|
..self
|
|
}
|
|
}
|
|
|
|
pub async fn fetch_data(mut self) -> PermissionCalculator {
|
|
let guild = if let Some(value) = self.guild {
|
|
Some(value)
|
|
} else if let Some(channel) = &self.channel {
|
|
match channel.channel_type {
|
|
0..=1 => None,
|
|
2 => {
|
|
if let Some(id) = &channel.guild {
|
|
if let Ok(result) = fetch_guild(id).await {
|
|
result
|
|
} else {
|
|
None
|
|
}
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
_ => None,
|
|
}
|
|
} else {
|
|
None
|
|
};
|
|
|
|
if let Some(guild) = &guild {
|
|
if let Ok(result) = fetch_member(MemberKey(guild.id.clone(), self.user.id.clone())).await {
|
|
self.member = result;
|
|
}
|
|
}
|
|
|
|
self.guild = guild;
|
|
self
|
|
}
|
|
|
|
pub async fn calculate(&self) -> u32 {
|
|
let mut permissions: u32 = 0;
|
|
if let Some(guild) = &self.guild {
|
|
if let Some(_member) = &self.member {
|
|
// ? logic should match mutual.rs#has_mutual_connection
|
|
if guild.owner == self.user.id {
|
|
return u32::MAX;
|
|
}
|
|
|
|
permissions = guild.default_permissions as u32;
|
|
}
|
|
}
|
|
|
|
if let Some(channel) = &self.channel {
|
|
match channel.channel_type {
|
|
0 => {
|
|
if let Some(arr) = &channel.recipients {
|
|
let mut other_user = None;
|
|
for item in arr {
|
|
if item != &self.user.id {
|
|
other_user = Some(item);
|
|
}
|
|
}
|
|
|
|
if let Some(other) = other_user {
|
|
let relationship = get_relationship_internal(
|
|
&self.user.id,
|
|
&other,
|
|
&self.user.relations,
|
|
);
|
|
|
|
if relationship == Relationship::Friend {
|
|
permissions = 1024 + 128 + 32 + 16 + 1;
|
|
} else if relationship == Relationship::Blocked
|
|
|| relationship == Relationship::BlockedOther
|
|
{
|
|
permissions = 1;
|
|
} else if has_mutual_connection(&self.user.id, other, true).await {
|
|
permissions = 1024 + 128 + 32 + 16 + 1;
|
|
} else {
|
|
permissions = 1;
|
|
}
|
|
} else {
|
|
// ? In this case, it is a "self DM".
|
|
return 1024 + 128 + 32 + 16 + 1;
|
|
}
|
|
}
|
|
}
|
|
1 => {
|
|
if let Some(id) = &channel.owner {
|
|
if &self.user.id == id {
|
|
return u32::MAX;
|
|
}
|
|
}
|
|
|
|
if let Some(arr) = &channel.recipients {
|
|
for item in arr {
|
|
if item == &self.user.id {
|
|
permissions = 177;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
2 => {
|
|
// nothing implemented yet
|
|
}
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
permissions
|
|
}
|
|
|
|
pub async fn as_permission(&self) -> MemberPermissions<[u32; 1]> {
|
|
MemberPermissions([self.calculate().await])
|
|
}
|
|
}
|