onechatsocial_database/util/
permissions.rsuse std::borrow::Cow;
use onechatsocial_permissions::{
calculate_user_permissions, ChannelType, Override, PermissionQuery, PermissionValue,
RelationshipStatus, DEFAULT_PERMISSION_DIRECT_MESSAGE,
};
use crate::{Channel, Database, Member, Server, User};
#[derive(Clone)]
pub struct DatabasePermissionQuery<'a> {
#[allow(dead_code)]
database: &'a Database,
perspective: &'a User,
user: Option<Cow<'a, User>>,
channel: Option<Cow<'a, Channel>>,
server: Option<Cow<'a, Server>>,
member: Option<Cow<'a, Member>>,
cached_user_permission: Option<PermissionValue>,
cached_mutual_connection: Option<bool>,
cached_permission: Option<u64>,
}
#[async_trait]
impl PermissionQuery for DatabasePermissionQuery<'_> {
async fn are_we_privileged(&mut self) -> bool {
self.perspective.privileged
}
async fn are_we_a_bot(&mut self) -> bool {
self.perspective.bot.is_some()
}
async fn are_the_users_same(&mut self) -> bool {
if let Some(other_user) = &self.user {
self.perspective.id == other_user.id
} else {
false
}
}
async fn user_relationship(&mut self) -> RelationshipStatus {
if let Some(other_user) = &self.user {
if self.perspective.id == other_user.id {
return RelationshipStatus::User;
}
if let Some(relations) = &self.perspective.relations {
for entry in relations {
if entry.id == other_user.id {
return match entry.status {
crate::RelationshipStatus::None => RelationshipStatus::None,
crate::RelationshipStatus::User => RelationshipStatus::User,
crate::RelationshipStatus::Friend => RelationshipStatus::Friend,
crate::RelationshipStatus::Outgoing => RelationshipStatus::Outgoing,
crate::RelationshipStatus::Incoming => RelationshipStatus::Incoming,
crate::RelationshipStatus::Blocked => RelationshipStatus::Blocked,
crate::RelationshipStatus::BlockedOther => {
RelationshipStatus::BlockedOther
}
};
}
}
}
}
RelationshipStatus::None
}
async fn user_is_bot(&mut self) -> bool {
if let Some(other_user) = &self.user {
other_user.bot.is_some()
} else {
false
}
}
async fn have_mutual_connection(&mut self) -> bool {
if let Some(value) = self.cached_mutual_connection {
value
} else if let Some(user) = &self.user {
let value = self
.perspective
.has_mutual_connection(self.database, &user.id)
.await
.unwrap_or_default();
self.cached_mutual_connection = Some(value);
matches!(value, true)
} else {
false
}
}
async fn are_we_server_owner(&mut self) -> bool {
if let Some(server) = &self.server {
server.owner == self.perspective.id
} else {
false
}
}
async fn are_we_a_member(&mut self) -> bool {
if let Some(server) = &self.server {
if self.member.is_some() {
true
} else if let Ok(member) = self
.database
.fetch_member(&server.id, &self.perspective.id)
.await
{
self.member = Some(Cow::Owned(member));
true
} else {
false
}
} else {
false
}
}
async fn get_default_server_permissions(&mut self) -> u64 {
if let Some(server) = &self.server {
server.default_permissions as u64
} else {
0
}
}
async fn get_our_server_role_overrides(&mut self) -> Vec<Override> {
if let Some(server) = &self.server {
let member_roles = self
.member
.as_ref()
.map(|member| member.roles.clone())
.unwrap_or_default();
let mut roles = server
.roles
.iter()
.filter(|(id, _)| member_roles.contains(id))
.map(|(_, role)| {
let v: Override = role.permissions.into();
(role.rank, v)
})
.collect::<Vec<(i64, Override)>>();
roles.sort_by(|a, b| b.0.cmp(&a.0));
roles.into_iter().map(|(_, v)| v).collect()
} else {
vec![]
}
}
async fn are_we_timed_out(&mut self) -> bool {
if let Some(member) = &self.member {
member.in_timeout()
} else {
false
}
}
async fn get_channel_type(&mut self) -> ChannelType {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::DirectMessage { .. })
| Cow::Owned(Channel::DirectMessage { .. }) => ChannelType::DirectMessage,
Cow::Borrowed(Channel::Group { .. }) | Cow::Owned(Channel::Group { .. }) => {
ChannelType::Group
}
Cow::Borrowed(Channel::SavedMessages { .. })
| Cow::Owned(Channel::SavedMessages { .. }) => ChannelType::SavedMessages,
Cow::Borrowed(Channel::TextChannel { .. })
| Cow::Owned(Channel::TextChannel { .. })
| Cow::Borrowed(Channel::VoiceChannel { .. })
| Cow::Owned(Channel::VoiceChannel { .. }) => ChannelType::ServerChannel,
}
} else {
ChannelType::Unknown
}
}
async fn get_default_channel_permissions(&mut self) -> Override {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::Group { permissions, .. })
| Cow::Owned(Channel::Group { permissions, .. }) => Override {
allow: permissions.unwrap_or(*DEFAULT_PERMISSION_DIRECT_MESSAGE as i64) as u64,
deny: 0,
},
Cow::Borrowed(Channel::TextChannel {
default_permissions,
..
})
| Cow::Owned(Channel::TextChannel {
default_permissions,
..
})
| Cow::Borrowed(Channel::VoiceChannel {
default_permissions,
..
})
| Cow::Owned(Channel::VoiceChannel {
default_permissions,
..
}) => default_permissions.unwrap_or_default().into(),
_ => Default::default(),
}
} else {
Default::default()
}
}
async fn get_our_channel_role_overrides(&mut self) -> Vec<Override> {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::TextChannel {
role_permissions, ..
})
| Cow::Owned(Channel::TextChannel {
role_permissions, ..
})
| Cow::Borrowed(Channel::VoiceChannel {
role_permissions, ..
})
| Cow::Owned(Channel::VoiceChannel {
role_permissions, ..
}) => {
if let Some(server) = &self.server {
let member_roles = self
.member
.as_ref()
.map(|member| member.roles.clone())
.unwrap_or_default();
let mut roles = role_permissions
.iter()
.filter(|(id, _)| member_roles.contains(id))
.filter_map(|(id, permission)| {
server.roles.get(id).map(|role| {
let v: Override = (*permission).into();
(role.rank, v)
})
})
.collect::<Vec<(i64, Override)>>();
roles.sort_by(|a, b| b.0.cmp(&a.0));
roles.into_iter().map(|(_, v)| v).collect()
} else {
vec![]
}
}
_ => vec![],
}
} else {
vec![]
}
}
async fn do_we_own_the_channel(&mut self) -> bool {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::Group { owner, .. })
| Cow::Owned(Channel::Group { owner, .. }) => owner == &self.perspective.id,
Cow::Borrowed(Channel::SavedMessages { user, .. })
| Cow::Owned(Channel::SavedMessages { user, .. }) => user == &self.perspective.id,
_ => false,
}
} else {
false
}
}
async fn are_we_part_of_the_channel(&mut self) -> bool {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::DirectMessage { recipients, .. })
| Cow::Owned(Channel::DirectMessage { recipients, .. })
| Cow::Borrowed(Channel::Group { recipients, .. })
| Cow::Owned(Channel::Group { recipients, .. }) => {
recipients.contains(&self.perspective.id)
}
_ => false,
}
} else {
false
}
}
async fn set_recipient_as_user(&mut self) {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::DirectMessage { recipients, .. })
| Cow::Owned(Channel::DirectMessage { recipients, .. }) => {
let recipient_id = recipients
.iter()
.find(|recipient| recipient != &&self.perspective.id)
.expect("Missing recipient for DM");
if let Ok(user) = self.database.fetch_user(recipient_id).await {
self.user.replace(Cow::Owned(user));
}
}
_ => unimplemented!(),
}
}
}
async fn set_server_from_channel(&mut self) {
if let Some(channel) = &self.channel {
match channel {
Cow::Borrowed(Channel::TextChannel { server, .. })
| Cow::Owned(Channel::TextChannel { server, .. })
| Cow::Borrowed(Channel::VoiceChannel { server, .. })
| Cow::Owned(Channel::VoiceChannel { server, .. }) => {
if let Some(known_server) =
if let Some(Cow::Borrowed(known_server)) = self.server {
Some(known_server)
} else if let Some(Cow::Owned(ref known_server)) = self.server {
Some(known_server)
} else {
None
}
{
if server == &known_server.id {
return;
}
}
if let Ok(server) = self.database.fetch_server(server).await {
self.server.replace(Cow::Owned(server));
}
}
_ => unimplemented!(),
}
}
}
}
impl<'a> DatabasePermissionQuery<'a> {
pub fn new(database: &'a Database, perspective: &'a User) -> DatabasePermissionQuery<'a> {
DatabasePermissionQuery {
database,
perspective,
user: None,
channel: None,
server: None,
member: None,
cached_mutual_connection: None,
cached_user_permission: None,
cached_permission: None,
}
}
pub async fn calc_user(mut self) -> DatabasePermissionQuery<'a> {
if self.cached_user_permission.is_some() {
return self;
}
if self.user.is_none() {
panic!("Expected `PermissionCalculator.user to exist.");
}
DatabasePermissionQuery {
cached_user_permission: Some(calculate_user_permissions(&mut self).await),
..self
}
}
pub async fn calc(self) -> DatabasePermissionQuery<'a> {
if self.cached_permission.is_some() {
return self;
}
self
}
pub fn user(self, user: &'a User) -> DatabasePermissionQuery {
DatabasePermissionQuery {
user: Some(Cow::Borrowed(user)),
..self
}
}
pub fn channel(self, channel: &'a Channel) -> DatabasePermissionQuery {
DatabasePermissionQuery {
channel: Some(Cow::Borrowed(channel)),
..self
}
}
pub fn server(self, server: &'a Server) -> DatabasePermissionQuery {
DatabasePermissionQuery {
server: Some(Cow::Borrowed(server)),
..self
}
}
pub fn member(self, member: &'a Member) -> DatabasePermissionQuery {
DatabasePermissionQuery {
member: Some(Cow::Borrowed(member)),
..self
}
}
pub fn user_ref(&self) -> &Option<Cow<User>> {
&self.user
}
pub fn channel_ref(&self) -> &Option<Cow<Channel>> {
&self.channel
}
pub fn server_ref(&self) -> &Option<Cow<Server>> {
&self.server
}
pub fn member_ref(&self) -> &Option<Cow<Member>> {
&self.member
}
}
pub fn perms<'a>(database: &'a Database, perspective: &'a User) -> DatabasePermissionQuery<'a> {
DatabasePermissionQuery::new(database, perspective)
}