feat(core): provide user profile where appropriate

This commit is contained in:
Paul Makles
2023-10-16 09:33:36 +01:00
parent 0b6e5dd9db
commit cb97004d3f
9 changed files with 96 additions and 54 deletions

View File

@@ -60,7 +60,7 @@ impl AbstractMessages for ReferenceDb {
.cloned()
.collect();
// TODO: sorting, etc
// TODO: sorting, etc (will be required for tests)
Ok(matched_messages)

View File

@@ -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;

View File

@@ -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<crate::FieldsRole> 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<Option<&'a crate::User>>,
{
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()),

View File

@@ -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<Cow<'a, Member>>,
// flag_known_relationship: Option<&'a RelationshipStatus>,
cached_user_permission: Option<u32>,
cached_user_permission: Option<PermissionValue>,
cached_mutual_connection: Option<bool>,
cached_permission: Option<u64>,
}
@@ -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,
}

View File

@@ -5,37 +5,37 @@ use crate::{
};
/// Calculate permissions against a user
pub async fn calculate_user_permissions<P: PermissionQuery>(query: &mut P) -> u32 {
pub async fn calculate_user_permissions<P: PermissionQuery>(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<P: PermissionQuery>(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<P: PermissionQuery>(query: &mut P) ->
if !permissions.has_channel_permission(ChannelPermission::ViewChannel) {
permissions.revoke_all();
}
permissions
} else {
0_u64.into()

View File

@@ -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)

View File

@@ -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();

View File

@@ -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(),
}))
}

View File

@@ -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,