diff --git a/crates/core/database/src/models/users/model.rs b/crates/core/database/src/models/users/model.rs index 8b0fcfe0..7967ad5c 100644 --- a/crates/core/database/src/models/users/model.rs +++ b/crates/core/database/src/models/users/model.rs @@ -162,6 +162,20 @@ impl User { Ok(user) } + /// Check whether two users have a mutual connection + /// + /// This will check if user and user_b share a server or a group. + pub async fn has_mutual_connection(&self, db: &Database, user_b: &str) -> Result { + Ok(!db + .fetch_mutual_server_ids(&self.id, user_b) + .await? + .is_empty() + || !db + .fetch_mutual_channel_ids(&self.id, user_b) + .await? + .is_empty()) + } + /// Sanitise and validate a username can be used pub fn validate_username(username: String) -> Result { // Copy the username for validation diff --git a/crates/core/database/src/util/permissions.rs b/crates/core/database/src/util/permissions.rs index 1c850a98..d9be51b8 100644 --- a/crates/core/database/src/util/permissions.rs +++ b/crates/core/database/src/util/permissions.rs @@ -82,75 +82,262 @@ impl PermissionQuery for DatabasePermissionQuery<'_> { /// Do we have a mutual connection with the currently selected user? async fn have_mutual_connection(&mut self) -> bool { - // TODO: User::has_mutual_connection - false + if let Some(user) = &self.user { + // TODO: cache result? + matches!( + self.perspective + .has_mutual_connection(self.database, &user.id) + .await, + Ok(true) + ) + } else { + false + } } // * For calculating server permission /// Is our perspective user the server's owner? async fn are_we_server_owner(&mut self) -> bool { - todo!() + if let Some(server) = &self.server { + server.owner == self.perspective.id + } else { + false + } } /// Is our perspective user a member of the server? async fn are_we_a_member(&mut self) -> bool { - todo!() + if let Some(server) = &self.server { + if self.member.is_some() { + true + } else { + self.database + .fetch_member(&server.id, &self.perspective.id) + .await + .is_ok() + } + } else { + false + } } /// Get default server permission async fn get_default_server_permissions(&mut self) -> u64 { - todo!() + if let Some(server) = &self.server { + server.default_permissions as u64 + } else { + 0 + } } /// Get the ordered role overrides (from lowest to highest) for this member in this server async fn get_our_server_role_overrides(&mut self) -> Vec { - todo!() + 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::>(); + + roles.sort_by(|a, b| b.0.cmp(&a.0)); + roles.into_iter().map(|(_, v)| v).collect() + } else { + vec![] + } } /// Is our perspective user timed out on this server? async fn are_we_timed_out(&mut self) -> bool { - todo!() + if let Some(member) = &self.member { + member.in_timeout() + } else { + false + } } // * For calculating channel permission /// Get the type of the channel async fn get_channel_type(&mut self) -> ChannelType { - todo!() + 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 + } } /// Get the default channel permissions /// Group channel defaults should be mapped to an allow-only override async fn get_default_channel_permissions(&mut self) -> Override { - todo!() + if let Some(channel) = &self.channel { + match channel { + Cow::Borrowed(Channel::Group { permissions, .. }) + | Cow::Owned(Channel::Group { permissions, .. }) => Override { + allow: permissions.unwrap_or_default() 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() + } } /// Get the ordered role overrides (from lowest to highest) for this member in this channel async fn get_our_channel_role_overrides(&mut self) -> Vec { - todo!() + 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::>(); + + roles.sort_by(|a, b| b.0.cmp(&a.0)); + roles.into_iter().map(|(_, v)| v).collect() + } else { + vec![] + } + } + _ => vec![], + } + } else { + vec![] + } } /// Do we own this group or saved messages channel if it is one of those? async fn do_we_own_the_channel(&mut self) -> bool { - todo!() + 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 + } } /// Are we a recipient of this channel? async fn are_we_part_of_the_channel(&mut self) -> bool { - todo!() + 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 + } } /// Set the current user as the recipient of this channel /// (this will only ever be called for DirectMessage channels, use unimplemented!() for other code paths) async fn set_recipient_as_user(&mut self) { - todo!() + 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!(), + } + } } /// Set the current server as the server owning this channel /// (this will only ever be called for server channels, use unimplemented!() for other code paths) async fn set_server_from_channel(&mut self) { - todo!() + 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 Ok(server) = self.database.fetch_server(server).await { + self.server.replace(Cow::Owned(server)); + } + } + _ => unimplemented!(), + } + } } } diff --git a/crates/core/permissions/src/models/server.rs b/crates/core/permissions/src/models/server.rs index 6320248d..e4a47549 100644 --- a/crates/core/permissions/src/models/server.rs +++ b/crates/core/permissions/src/models/server.rs @@ -2,7 +2,7 @@ use schemars::JsonSchema; /// Representation of a single permission override -#[derive(Debug, Clone, Eq, PartialEq)] +#[derive(Debug, Clone, Eq, PartialEq, Default)] #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] #[cfg_attr(feature = "schemas", derive(JsonSchema))] pub struct Override {