From cb97004d3f6dae2afba4767e178ffbb730f62734 Mon Sep 17 00:00:00 2001 From: Paul Makles Date: Mon, 16 Oct 2023 09:33:36 +0100 Subject: [PATCH] feat(core): provide user profile where appropriate --- .../src/models/messages/ops/reference.rs | 2 +- .../core/database/src/models/users/model.rs | 4 +- crates/core/database/src/util/bridge/v0.rs | 73 +++++++++++++------ crates/core/database/src/util/permissions.rs | 30 +++++--- crates/core/permissions/src/impl.rs | 28 ++++--- crates/core/permissions/src/models/mod.rs | 7 +- crates/core/permissions/src/test.rs | 2 +- crates/delta/src/routes/bots/fetch.rs | 2 +- .../delta/src/routes/channels/message_send.rs | 2 +- 9 files changed, 96 insertions(+), 54 deletions(-) diff --git a/crates/core/database/src/models/messages/ops/reference.rs b/crates/core/database/src/models/messages/ops/reference.rs index b3ddeda3..20c6ac59 100644 --- a/crates/core/database/src/models/messages/ops/reference.rs +++ b/crates/core/database/src/models/messages/ops/reference.rs @@ -60,7 +60,7 @@ impl AbstractMessages for ReferenceDb { .cloned() .collect(); - // TODO: sorting, etc + // TODO: sorting, etc (will be required for tests) Ok(matched_messages) diff --git a/crates/core/database/src/models/users/model.rs b/crates/core/database/src/models/users/model.rs index 305267b0..bb7c19b6 100644 --- a/crates/core/database/src/models/users/model.rs +++ b/crates/core/database/src/models/users/model.rs @@ -391,14 +391,14 @@ impl User { EventV1::UserRelationship { id: target.id.clone(), - user: self.clone().into(Some(&*target)).await, + user: self.clone().into(db, Some(&*target)).await, } .private(target.id.clone()) .await; EventV1::UserRelationship { id: self.id.clone(), - user: target.clone().into(Some(&*self)).await, + user: target.clone().into(db, Some(&*self)).await, } .private(self.id.clone()) .await; diff --git a/crates/core/database/src/util/bridge/v0.rs b/crates/core/database/src/util/bridge/v0.rs index b01266c4..6bc6880e 100644 --- a/crates/core/database/src/util/bridge/v0.rs +++ b/crates/core/database/src/util/bridge/v0.rs @@ -1,4 +1,7 @@ use revolt_models::v0::*; +use revolt_permissions::{calculate_user_permissions, UserPermission}; + +use crate::{util::permissions::DatabasePermissionQuery, Database}; impl crate::Bot { pub fn into_public_bot(self, user: crate::User) -> PublicBot { @@ -635,43 +638,69 @@ impl From for FieldsRole { } impl crate::User { - pub async fn into<'a, P>(self, perspective: P) -> User + pub async fn into<'a, P>(self, db: &Database, perspective: P) -> User where P: Into>, { - let relationship = if let Some(perspective) = perspective.into() { + let perspective = perspective.into(); + let (relationship, can_see_profile) = if self.bot.is_some() { + (RelationshipStatus::None, true) + } else if let Some(perspective) = perspective { + let mut query = DatabasePermissionQuery::new(db, perspective).user(&self); + if perspective.id == self.id { - RelationshipStatus::User + (RelationshipStatus::User, true) } else { - perspective - .relations - .as_ref() - .map(|relations| { - relations - .iter() - .find(|relationship| relationship.id == self.id) - .map(|relationship| relationship.status.clone().into()) - .unwrap_or_default() - }) - .unwrap_or_default() + ( + perspective + .relations + .as_ref() + .map(|relations| { + relations + .iter() + .find(|relationship| relationship.id == self.id) + .map(|relationship| relationship.status.clone().into()) + .unwrap_or_default() + }) + .unwrap_or_default(), + calculate_user_permissions(&mut query) + .await + .has_user_permission(UserPermission::ViewProfile), + ) } } else { - RelationshipStatus::None + (RelationshipStatus::None, false) }; - // do permission stuff here - // TODO: implement permissions =) - let can_see_profile = false; - User { username: self.username, discriminator: self.discriminator, display_name: self.display_name, avatar: self.avatar.map(|file| file.into()), - relations: vec![], + relations: if let Some(crate::User { id, .. }) = perspective { + if id == &self.id { + self.relations + .unwrap_or_default() + .into_iter() + .map(|relation| relation.into()) + .collect() + } else { + vec![] + } + } else { + vec![] + }, badges: self.badges.unwrap_or_default() as u32, - status: None, - profile: None, + status: if can_see_profile { + self.status.map(|status| status.into()) + } else { + None + }, + profile: if can_see_profile { + self.profile.map(|profile| profile.into()) + } else { + None + }, flags: self.flags.unwrap_or_default() as u32, privileged: self.privileged, bot: self.bot.map(|bot| bot.into()), diff --git a/crates/core/database/src/util/permissions.rs b/crates/core/database/src/util/permissions.rs index d9be51b8..b875ed47 100644 --- a/crates/core/database/src/util/permissions.rs +++ b/crates/core/database/src/util/permissions.rs @@ -1,7 +1,8 @@ use std::borrow::Cow; use revolt_permissions::{ - calculate_user_permissions, ChannelType, Override, PermissionQuery, RelationshipStatus, + calculate_user_permissions, ChannelType, Override, PermissionQuery, PermissionValue, + RelationshipStatus, }; use crate::{Channel, Database, Member, Server, User}; @@ -19,7 +20,8 @@ pub struct DatabasePermissionQuery<'a> { member: Option>, // flag_known_relationship: Option<&'a RelationshipStatus>, - cached_user_permission: Option, + cached_user_permission: Option, + cached_mutual_connection: Option, cached_permission: Option, } @@ -49,6 +51,10 @@ impl PermissionQuery for DatabasePermissionQuery<'_> { /// Get the relationship with have with the currently selected user 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 { @@ -82,14 +88,17 @@ impl PermissionQuery for DatabasePermissionQuery<'_> { /// Do we have a mutual connection with the currently selected user? async fn have_mutual_connection(&mut self) -> bool { - if let Some(user) = &self.user { - // TODO: cache result? - matches!( - self.perspective - .has_mutual_connection(self.database, &user.id) - .await, - Ok(true) - ) + 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 } @@ -352,6 +361,7 @@ impl<'a> DatabasePermissionQuery<'a> { server: None, member: None, + cached_mutual_connection: None, cached_user_permission: None, cached_permission: None, } diff --git a/crates/core/permissions/src/impl.rs b/crates/core/permissions/src/impl.rs index 2d424cf6..e3af670b 100644 --- a/crates/core/permissions/src/impl.rs +++ b/crates/core/permissions/src/impl.rs @@ -5,37 +5,37 @@ use crate::{ }; /// Calculate permissions against a user -pub async fn calculate_user_permissions(query: &mut P) -> u32 { +pub async fn calculate_user_permissions(query: &mut P) -> PermissionValue { if query.are_we_privileged().await { - return u32::MAX; + return u64::MAX.into(); } if query.are_the_users_same().await { - return u32::MAX; + return u64::MAX.into(); } - let mut permissions = 0_u32; + let mut permissions = 0_u64; match query.user_relationship().await { - RelationshipStatus::Friend => return u32::MAX, + RelationshipStatus::Friend => return u64::MAX.into(), RelationshipStatus::Blocked | RelationshipStatus::BlockedOther => { - return UserPermission::Access as u32 + return (UserPermission::Access as u64).into() } RelationshipStatus::Incoming | RelationshipStatus::Outgoing => { - permissions = UserPermission::Access as u32; + permissions = UserPermission::Access as u64; } _ => {} } if query.have_mutual_connection().await { - permissions = UserPermission::Access + UserPermission::ViewProfile; + permissions = UserPermission::Access as u64 + UserPermission::ViewProfile as u64; if query.user_is_bot().await || query.are_we_a_bot().await { - permissions += UserPermission::SendMessage as u32; + permissions += UserPermission::SendMessage as u64; } - permissions + permissions.into() } else { - permissions + permissions.into() } } @@ -81,9 +81,7 @@ pub async fn calculate_channel_permissions(query: &mut P) -> query.set_recipient_as_user().await; let permissions = calculate_user_permissions(query).await; - if (permissions & UserPermission::SendMessage as u32) - == UserPermission::SendMessage as u32 - { + if permissions.has_user_permission(UserPermission::SendMessage) { (*DEFAULT_PERMISSION_DIRECT_MESSAGE).into() } else { (*DEFAULT_PERMISSION_VIEW_ONLY).into() @@ -121,7 +119,7 @@ pub async fn calculate_channel_permissions(query: &mut P) -> if !permissions.has_channel_permission(ChannelPermission::ViewChannel) { permissions.revoke_all(); } - + permissions } else { 0_u64.into() diff --git a/crates/core/permissions/src/models/mod.rs b/crates/core/permissions/src/models/mod.rs index aefd8454..3210a42e 100644 --- a/crates/core/permissions/src/models/mod.rs +++ b/crates/core/permissions/src/models/mod.rs @@ -8,7 +8,7 @@ pub use server::*; pub use user::*; /// Holds a permission value to manipulate. -#[derive(Debug)] +#[derive(Clone, Debug)] pub struct PermissionValue(u64); impl PermissionValue { @@ -43,6 +43,11 @@ impl PermissionValue { (self.0 & v) == v } + /// Check whether certain a user permission has been granted + pub fn has_user_permission(&self, permission: UserPermission) -> bool { + self.has(permission as u64) + } + /// Check whether certain a channel permission has been granted pub fn has_channel_permission(&self, permission: ChannelPermission) -> bool { self.has(permission as u64) diff --git a/crates/core/permissions/src/test.rs b/crates/core/permissions/src/test.rs index d58e8919..e4dadd48 100644 --- a/crates/core/permissions/src/test.rs +++ b/crates/core/permissions/src/test.rs @@ -12,7 +12,7 @@ async fn validate_user_permissions() { let mut query = Scenario {}; let perms = calculate_user_permissions(&mut query).await; - assert_eq!(perms, u32::MAX); + assert!(perms.has(u64::MAX)); let perms = calculate_channel_permissions(&mut query).await; let value: u64 = perms.into(); diff --git a/crates/delta/src/routes/bots/fetch.rs b/crates/delta/src/routes/bots/fetch.rs index 932895b4..6e922f71 100644 --- a/crates/delta/src/routes/bots/fetch.rs +++ b/crates/delta/src/routes/bots/fetch.rs @@ -23,7 +23,7 @@ pub async fn fetch_bot( } Ok(Json(FetchBotResponse { - user: db.fetch_user(&bot.id).await?.into(None).await, + user: db.fetch_user(&bot.id).await?.into(db, None).await, bot: bot.into(), })) } diff --git a/crates/delta/src/routes/channels/message_send.rs b/crates/delta/src/routes/channels/message_send.rs index 143b9c3b..a194fc9d 100644 --- a/crates/delta/src/routes/channels/message_send.rs +++ b/crates/delta/src/routes/channels/message_send.rs @@ -62,7 +62,7 @@ pub async fn message_send( } // Create the message - let author: v0::User = user.clone().into(Some(&user)).await; + let author: v0::User = user.clone().into(db, Some(&user)).await; Ok(Json( Message::create_from_api( db,