Merge remote-tracking branch 'origin/main' into livekit
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use revolt_models::v0::*;
|
||||
use revolt_permissions::{calculate_user_permissions, UserPermission};
|
||||
|
||||
use crate::{util::permissions::DatabasePermissionQuery, Database};
|
||||
use crate::{util::permissions::DatabasePermissionQuery, Database, FileUsedFor};
|
||||
|
||||
impl crate::Bot {
|
||||
pub fn into_public_bot(self, user: crate::User) -> PublicBot {
|
||||
@@ -108,6 +108,7 @@ impl From<crate::Webhook> for Webhook {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
avatar: value.avatar.map(|file| file.into()),
|
||||
creator_id: value.creator_id,
|
||||
channel_id: value.channel_id,
|
||||
token: value.token,
|
||||
permissions: value.permissions,
|
||||
@@ -121,6 +122,7 @@ impl From<crate::PartialWebhook> for PartialWebhook {
|
||||
id: value.id,
|
||||
name: value.name,
|
||||
avatar: value.avatar.map(|file| file.into()),
|
||||
creator_id: value.creator_id,
|
||||
channel_id: value.channel_id,
|
||||
token: value.token,
|
||||
permissions: value.permissions,
|
||||
@@ -423,6 +425,10 @@ impl From<File> for crate::File {
|
||||
user_id: value.user_id,
|
||||
server_id: value.server_id,
|
||||
object_id: value.object_id,
|
||||
hash: None,
|
||||
uploaded_at: None,
|
||||
uploader_id: None,
|
||||
used_for: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -463,26 +469,30 @@ impl From<Metadata> for crate::Metadata {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Message> for Message {
|
||||
fn from(value: crate::Message) -> Self {
|
||||
impl crate::Message {
|
||||
pub fn into_model(self, user: Option<User>, member: Option<Member>) -> Message {
|
||||
Message {
|
||||
id: value.id,
|
||||
nonce: value.nonce,
|
||||
channel: value.channel,
|
||||
author: value.author,
|
||||
webhook: value.webhook,
|
||||
content: value.content,
|
||||
system: value.system.map(|system| system.into()),
|
||||
attachments: value
|
||||
id: self.id,
|
||||
nonce: self.nonce,
|
||||
channel: self.channel,
|
||||
author: self.author,
|
||||
user,
|
||||
member,
|
||||
webhook: self.webhook,
|
||||
content: self.content,
|
||||
system: self.system.map(Into::into),
|
||||
attachments: self
|
||||
.attachments
|
||||
.map(|v| v.into_iter().map(|f| f.into()).collect()),
|
||||
edited: value.edited,
|
||||
embeds: value.embeds,
|
||||
mentions: value.mentions,
|
||||
replies: value.replies,
|
||||
reactions: value.reactions,
|
||||
interactions: value.interactions.into(),
|
||||
masquerade: value.masquerade.map(|masq| masq.into()),
|
||||
edited: self.edited,
|
||||
embeds: self.embeds,
|
||||
mentions: self.mentions,
|
||||
replies: self.replies,
|
||||
reactions: self.reactions,
|
||||
interactions: self.interactions.into(),
|
||||
masquerade: self.masquerade.map(Into::into),
|
||||
flags: self.flags.map(|flags| flags as u32).unwrap_or_default(),
|
||||
pinned: self.pinned,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -494,9 +504,11 @@ impl From<crate::PartialMessage> for PartialMessage {
|
||||
nonce: value.nonce,
|
||||
channel: value.channel,
|
||||
author: value.author,
|
||||
user: None,
|
||||
member: None,
|
||||
webhook: value.webhook,
|
||||
content: value.content,
|
||||
system: value.system.map(|system| system.into()),
|
||||
system: value.system.map(Into::into),
|
||||
attachments: value
|
||||
.attachments
|
||||
.map(|v| v.into_iter().map(|f| f.into()).collect()),
|
||||
@@ -505,8 +517,10 @@ impl From<crate::PartialMessage> for PartialMessage {
|
||||
mentions: value.mentions,
|
||||
replies: value.replies,
|
||||
reactions: value.reactions,
|
||||
interactions: value.interactions.map(|interactions| interactions.into()),
|
||||
masquerade: value.masquerade.map(|masq| masq.into()),
|
||||
interactions: value.interactions.map(Into::into),
|
||||
masquerade: value.masquerade.map(Into::into),
|
||||
flags: value.flags.map(|flags| flags as u32),
|
||||
pinned: value.pinned,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -529,6 +543,8 @@ impl From<crate::SystemMessage> for SystemMessage {
|
||||
crate::SystemMessage::UserKicked { id } => Self::UserKicked { id },
|
||||
crate::SystemMessage::UserLeft { id } => Self::UserLeft { id },
|
||||
crate::SystemMessage::UserRemove { id, by } => Self::UserRemove { id, by },
|
||||
crate::SystemMessage::MessagePinned { id, by } => Self::MessagePinned { id, by },
|
||||
crate::SystemMessage::MessageUnpinned { id, by } => Self::MessageUnpinned { id, by },
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1011,26 +1027,31 @@ impl crate::User {
|
||||
vec![]
|
||||
},
|
||||
badges: self.badges.unwrap_or_default() as u32,
|
||||
online: can_see_profile
|
||||
&& revolt_presence::is_online(&self.id).await
|
||||
&& !matches!(
|
||||
self.status,
|
||||
Some(crate::UserStatus {
|
||||
presence: Some(crate::Presence::Invisible),
|
||||
..
|
||||
})
|
||||
),
|
||||
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()),
|
||||
relationship,
|
||||
online: can_see_profile && revolt_presence::is_online(&self.id).await,
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert user object into user model assuming mutual connection
|
||||
///
|
||||
/// Relations will never be included, i.e. when we process ourselves
|
||||
pub fn into_known<'a, P>(self, perspective: P, is_online: bool) -> User
|
||||
where
|
||||
P: Into<Option<&'a crate::User>>,
|
||||
@@ -1066,40 +1087,57 @@ impl crate::User {
|
||||
discriminator: self.discriminator,
|
||||
display_name: self.display_name,
|
||||
avatar: self.avatar.map(|file| file.into()),
|
||||
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![]
|
||||
},
|
||||
relations: vec![],
|
||||
badges: self.badges.unwrap_or_default() as u32,
|
||||
online: can_see_profile
|
||||
&& is_online
|
||||
&& !matches!(
|
||||
self.status,
|
||||
Some(crate::UserStatus {
|
||||
presence: Some(crate::Presence::Invisible),
|
||||
..
|
||||
})
|
||||
),
|
||||
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()),
|
||||
relationship,
|
||||
online: can_see_profile && is_online,
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn into_self(self) -> User {
|
||||
/// Convert user object into user model without presence information
|
||||
pub fn into_known_static<'a>(self, is_online: bool) -> User {
|
||||
User {
|
||||
username: self.username,
|
||||
discriminator: self.discriminator,
|
||||
display_name: self.display_name,
|
||||
avatar: self.avatar.map(|file| file.into()),
|
||||
relations: vec![],
|
||||
badges: self.badges.unwrap_or_default() as u32,
|
||||
online: is_online
|
||||
&& !matches!(
|
||||
self.status,
|
||||
Some(crate::UserStatus {
|
||||
presence: Some(crate::Presence::Invisible),
|
||||
..
|
||||
})
|
||||
),
|
||||
status: self.status.map(|status| status.into()),
|
||||
flags: self.flags.unwrap_or_default() as u32,
|
||||
privileged: self.privileged,
|
||||
bot: self.bot.map(|bot| bot.into()),
|
||||
relationship: RelationshipStatus::None, // events client will populate this from cache
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn into_self(self, force_online: bool) -> User {
|
||||
User {
|
||||
username: self.username,
|
||||
discriminator: self.discriminator,
|
||||
@@ -1115,13 +1153,19 @@ impl crate::User {
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
badges: self.badges.unwrap_or_default() as u32,
|
||||
online: (force_online || revolt_presence::is_online(&self.id).await)
|
||||
&& !matches!(
|
||||
self.status,
|
||||
Some(crate::UserStatus {
|
||||
presence: Some(crate::Presence::Invisible),
|
||||
..
|
||||
})
|
||||
),
|
||||
status: self.status.map(|status| status.into()),
|
||||
profile: self.profile.map(|profile| profile.into()),
|
||||
flags: self.flags.unwrap_or_default() as u32,
|
||||
privileged: self.privileged,
|
||||
bot: self.bot.map(|bot| bot.into()),
|
||||
relationship: RelationshipStatus::User,
|
||||
online: revolt_presence::is_online(&self.id).await,
|
||||
id: self.id,
|
||||
}
|
||||
}
|
||||
@@ -1145,10 +1189,11 @@ impl From<User> for crate::User {
|
||||
relations: None,
|
||||
badges: Some(value.badges as i32),
|
||||
status: value.status.map(Into::into),
|
||||
profile: value.profile.map(Into::into),
|
||||
profile: None,
|
||||
flags: Some(value.flags as i32),
|
||||
privileged: value.privileged,
|
||||
bot: value.bot.map(Into::into),
|
||||
suspended_until: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1168,7 +1213,6 @@ impl From<crate::PartialUser> for PartialUser {
|
||||
}),
|
||||
badges: value.badges.map(|badges| badges as u32),
|
||||
status: value.status.map(|status| status.into()),
|
||||
profile: value.profile.map(|profile| profile.into()),
|
||||
flags: value.flags.map(|flags| flags as u32),
|
||||
privileged: value.privileged,
|
||||
bot: value.bot.map(|bot| bot.into()),
|
||||
@@ -1187,6 +1231,9 @@ impl From<FieldsUser> for crate::FieldsUser {
|
||||
FieldsUser::ProfileContent => crate::FieldsUser::ProfileContent,
|
||||
FieldsUser::StatusPresence => crate::FieldsUser::StatusPresence,
|
||||
FieldsUser::StatusText => crate::FieldsUser::StatusText,
|
||||
FieldsUser::DisplayName => crate::FieldsUser::DisplayName,
|
||||
|
||||
FieldsUser::Internal => crate::FieldsUser::None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1199,6 +1246,10 @@ impl From<crate::FieldsUser> for FieldsUser {
|
||||
crate::FieldsUser::ProfileContent => FieldsUser::ProfileContent,
|
||||
crate::FieldsUser::StatusPresence => FieldsUser::StatusPresence,
|
||||
crate::FieldsUser::StatusText => FieldsUser::StatusText,
|
||||
crate::FieldsUser::DisplayName => FieldsUser::DisplayName,
|
||||
|
||||
crate::FieldsUser::Suspension => FieldsUser::Internal,
|
||||
crate::FieldsUser::None => FieldsUser::Internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1301,3 +1352,18 @@ impl From<BotInformation> for crate::BotInformation {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::FieldsMessage> for FieldsMessage {
|
||||
fn from(value: crate::FieldsMessage) -> Self {
|
||||
match value {
|
||||
crate::FieldsMessage::Pinned => FieldsMessage::Pinned,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl From<FieldsMessage> for crate::FieldsMessage {
|
||||
fn from(value: FieldsMessage) -> Self {
|
||||
match value {
|
||||
FieldsMessage::Pinned => crate::FieldsMessage::Pinned,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
337
crates/core/database/src/util/bulk_permissions.rs
Normal file
337
crates/core/database/src/util/bulk_permissions.rs
Normal file
@@ -0,0 +1,337 @@
|
||||
use std::{collections::HashMap, hash::RandomState};
|
||||
|
||||
use revolt_permissions::{
|
||||
ChannelPermission, ChannelType, Override, OverrideField, PermissionValue, ALLOW_IN_TIMEOUT,
|
||||
DEFAULT_PERMISSION_DIRECT_MESSAGE,
|
||||
};
|
||||
|
||||
use crate::{Channel, Database, Member, Server, User};
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct BulkDatabasePermissionQuery<'a> {
|
||||
#[allow(dead_code)]
|
||||
database: &'a Database,
|
||||
|
||||
server: Server,
|
||||
channel: Option<Channel>,
|
||||
users: Option<Vec<User>>,
|
||||
members: Option<Vec<Member>>,
|
||||
|
||||
// In case the users or members are fetched as part of the permissions checking operation
|
||||
pub(crate) cached_users: Option<Vec<User>>,
|
||||
pub(crate) cached_members: Option<Vec<Member>>,
|
||||
|
||||
cached_member_perms: Option<HashMap<String, PermissionValue>>,
|
||||
}
|
||||
|
||||
impl<'z, 'x> BulkDatabasePermissionQuery<'x> {
|
||||
pub async fn members_can_see_channel(&'z mut self) -> HashMap<String, bool>
|
||||
where
|
||||
'z: 'x,
|
||||
{
|
||||
let member_perms = if self.cached_member_perms.is_some() {
|
||||
// This isn't done as an if let to prevent borrow checker errors with the mut self call when the perms aren't cached.
|
||||
let perms = self.cached_member_perms.as_ref().unwrap();
|
||||
perms
|
||||
.iter()
|
||||
.map(|(m, p)| {
|
||||
(
|
||||
m.clone(),
|
||||
p.has_channel_permission(ChannelPermission::ViewChannel),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
} else {
|
||||
calculate_members_permissions(self)
|
||||
.await
|
||||
.iter()
|
||||
.map(|(m, p)| {
|
||||
(
|
||||
m.clone(),
|
||||
p.has_channel_permission(ChannelPermission::ViewChannel),
|
||||
)
|
||||
})
|
||||
.collect()
|
||||
};
|
||||
member_perms
|
||||
}
|
||||
}
|
||||
|
||||
impl<'z> BulkDatabasePermissionQuery<'z> {
|
||||
pub fn new(database: &Database, server: Server) -> BulkDatabasePermissionQuery<'_> {
|
||||
BulkDatabasePermissionQuery {
|
||||
database,
|
||||
server,
|
||||
channel: None,
|
||||
users: None,
|
||||
members: None,
|
||||
cached_members: None,
|
||||
cached_users: None,
|
||||
cached_member_perms: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn from_server_id<'a>(
|
||||
db: &'a Database,
|
||||
server: &str,
|
||||
) -> BulkDatabasePermissionQuery<'a> {
|
||||
BulkDatabasePermissionQuery {
|
||||
database: db,
|
||||
server: db.fetch_server(server).await.unwrap(),
|
||||
channel: None,
|
||||
users: None,
|
||||
members: None,
|
||||
cached_members: None,
|
||||
cached_users: None,
|
||||
cached_member_perms: None,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn channel(self, channel: &'z Channel) -> BulkDatabasePermissionQuery {
|
||||
BulkDatabasePermissionQuery {
|
||||
channel: Some(channel.clone()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn members(self, members: &'z [Member]) -> BulkDatabasePermissionQuery {
|
||||
BulkDatabasePermissionQuery {
|
||||
members: Some(members.to_owned()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
pub fn users(self, users: &'z [User]) -> BulkDatabasePermissionQuery {
|
||||
BulkDatabasePermissionQuery {
|
||||
users: Some(users.to_owned()),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the default channel permissions
|
||||
/// Group channel defaults should be mapped to an allow-only override
|
||||
#[allow(dead_code)]
|
||||
async fn get_default_channel_permissions(&mut self) -> Override {
|
||||
if let Some(channel) = &self.channel {
|
||||
match channel {
|
||||
Channel::Group { permissions, .. } => Override {
|
||||
allow: permissions.unwrap_or(*DEFAULT_PERMISSION_DIRECT_MESSAGE as i64) as u64,
|
||||
deny: 0,
|
||||
},
|
||||
Channel::TextChannel {
|
||||
default_permissions,
|
||||
..
|
||||
}
|
||||
| Channel::VoiceChannel {
|
||||
default_permissions,
|
||||
..
|
||||
} => default_permissions.unwrap_or_default().into(),
|
||||
_ => Default::default(),
|
||||
}
|
||||
} else {
|
||||
Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn get_channel_type(&mut self) -> ChannelType {
|
||||
if let Some(channel) = &self.channel {
|
||||
match channel {
|
||||
Channel::DirectMessage { .. } => ChannelType::DirectMessage,
|
||||
Channel::Group { .. } => ChannelType::Group,
|
||||
Channel::SavedMessages { .. } => ChannelType::SavedMessages,
|
||||
Channel::TextChannel { .. } | Channel::VoiceChannel { .. } => {
|
||||
ChannelType::ServerChannel
|
||||
}
|
||||
}
|
||||
} else {
|
||||
ChannelType::Unknown
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the ordered role overrides (from lowest to highest) for this member in this channel
|
||||
#[allow(dead_code)]
|
||||
async fn get_channel_role_overrides(&mut self) -> &HashMap<String, OverrideField> {
|
||||
if let Some(channel) = &self.channel {
|
||||
match channel {
|
||||
Channel::TextChannel {
|
||||
role_permissions, ..
|
||||
}
|
||||
| Channel::VoiceChannel {
|
||||
role_permissions, ..
|
||||
} => role_permissions,
|
||||
_ => panic!("Not supported for non-server channels"),
|
||||
}
|
||||
} else {
|
||||
panic!("No channel added to query")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate members permissions in a server channel.
|
||||
async fn calculate_members_permissions<'a>(
|
||||
query: &'a mut BulkDatabasePermissionQuery<'a>,
|
||||
) -> HashMap<String, PermissionValue> {
|
||||
let mut resp = HashMap::new();
|
||||
|
||||
let (_, channel_role_permissions, channel_default_permissions) = match query
|
||||
.channel
|
||||
.as_ref()
|
||||
.expect("A channel must be assigned to calculate channel permissions")
|
||||
.clone()
|
||||
{
|
||||
Channel::TextChannel {
|
||||
id,
|
||||
role_permissions,
|
||||
default_permissions,
|
||||
..
|
||||
}
|
||||
| Channel::VoiceChannel {
|
||||
id,
|
||||
role_permissions,
|
||||
default_permissions,
|
||||
..
|
||||
} => (id, role_permissions, default_permissions),
|
||||
_ => panic!("Calculation of member permissions must be done on a server channel"),
|
||||
};
|
||||
|
||||
if query.users.is_none() {
|
||||
let ids: Vec<String> = query
|
||||
.members
|
||||
.as_ref()
|
||||
.expect("No users or members added to the query")
|
||||
.iter()
|
||||
.map(|m| m.id.user.clone())
|
||||
.collect();
|
||||
|
||||
query.cached_users = Some(
|
||||
query
|
||||
.database
|
||||
.fetch_users(&ids[..])
|
||||
.await
|
||||
.expect("Failed to get data from the db"),
|
||||
);
|
||||
|
||||
query.users = Some(query.cached_users.as_ref().unwrap().to_vec())
|
||||
}
|
||||
|
||||
let users = query.users.as_ref().unwrap();
|
||||
|
||||
if query.members.is_none() {
|
||||
let ids: Vec<String> = query
|
||||
.users
|
||||
.as_ref()
|
||||
.expect("No users or members added to the query")
|
||||
.iter()
|
||||
.map(|m| m.id.clone())
|
||||
.collect();
|
||||
|
||||
query.cached_members = Some(
|
||||
query
|
||||
.database
|
||||
.fetch_members(&query.server.id, &ids[..])
|
||||
.await
|
||||
.expect("Failed to get data from the db"),
|
||||
);
|
||||
query.members = Some(query.cached_members.as_ref().unwrap().to_vec())
|
||||
}
|
||||
|
||||
let members: HashMap<&String, &Member, RandomState> = HashMap::from_iter(
|
||||
query
|
||||
.members
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.map(|m| (&m.id.user, m)),
|
||||
);
|
||||
|
||||
for user in users {
|
||||
let member = members.get(&user.id);
|
||||
|
||||
// User isn't a part of the server
|
||||
if member.is_none() {
|
||||
resp.insert(user.id.clone(), 0_u64.into());
|
||||
continue;
|
||||
}
|
||||
|
||||
let member = *member.unwrap();
|
||||
|
||||
if user.privileged {
|
||||
resp.insert(
|
||||
user.id.clone(),
|
||||
PermissionValue::from(ChannelPermission::GrantAllSafe),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
if user.id == query.server.owner {
|
||||
resp.insert(
|
||||
user.id.clone(),
|
||||
PermissionValue::from(ChannelPermission::GrantAllSafe),
|
||||
);
|
||||
continue;
|
||||
}
|
||||
|
||||
// Get the user's server permissions
|
||||
let mut permission = calculate_server_permissions(&query.server, user, member);
|
||||
|
||||
if let Some(defaults) = channel_default_permissions {
|
||||
permission.apply(defaults.into());
|
||||
}
|
||||
|
||||
// Get the applicable role overrides
|
||||
let mut roles = channel_role_permissions
|
||||
.iter()
|
||||
.filter(|(id, _)| member.roles.contains(id))
|
||||
.filter_map(|(id, permission)| {
|
||||
query.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));
|
||||
let overrides = roles.into_iter().map(|(_, v)| v);
|
||||
|
||||
for role_override in overrides {
|
||||
permission.apply(role_override)
|
||||
}
|
||||
|
||||
resp.insert(user.id.clone(), permission);
|
||||
}
|
||||
|
||||
resp
|
||||
}
|
||||
|
||||
/// Calculates a member's server permissions
|
||||
fn calculate_server_permissions(server: &Server, user: &User, member: &Member) -> PermissionValue {
|
||||
if user.privileged || server.owner == user.id {
|
||||
return ChannelPermission::GrantAllSafe.into();
|
||||
}
|
||||
|
||||
let mut permissions: PermissionValue = server.default_permissions.into();
|
||||
|
||||
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));
|
||||
let role_overrides: Vec<Override> = roles.into_iter().map(|(_, v)| v).collect();
|
||||
|
||||
for role in role_overrides {
|
||||
permissions.apply(role);
|
||||
}
|
||||
|
||||
if member.in_timeout() {
|
||||
permissions.restrict(*ALLOW_IN_TIMEOUT);
|
||||
}
|
||||
|
||||
permissions
|
||||
}
|
||||
@@ -18,6 +18,10 @@ static TOKEN_CACHE: Lazy<Mutex<lru::LruCache<String, ()>>> =
|
||||
Lazy::new(|| Mutex::new(lru::LruCache::new(NonZeroUsize::new(1000).unwrap())));
|
||||
|
||||
impl IdempotencyKey {
|
||||
pub fn unchecked_from_string(key: String) -> Self {
|
||||
Self { key }
|
||||
}
|
||||
|
||||
// Backwards compatibility.
|
||||
// Issue #109
|
||||
pub async fn consume_nonce(&mut self, v: Option<String>) -> Result<()> {
|
||||
@@ -98,7 +102,7 @@ impl<'r> FromRequest<'r> for IdempotencyKey {
|
||||
.map(|k| k.to_string())
|
||||
{
|
||||
if key.len() > 64 {
|
||||
return Outcome::Failure((
|
||||
return Outcome::Error((
|
||||
Status::BadRequest,
|
||||
create_error!(FailedValidation {
|
||||
error: "idempotency key too long".to_string(),
|
||||
@@ -109,7 +113,7 @@ impl<'r> FromRequest<'r> for IdempotencyKey {
|
||||
let idempotency = IdempotencyKey { key };
|
||||
let mut cache = TOKEN_CACHE.lock().await;
|
||||
if cache.get(&idempotency.key).is_some() {
|
||||
return Outcome::Failure((Status::Conflict, create_error!(DuplicateNonce)));
|
||||
return Outcome::Error((Status::Conflict, create_error!(DuplicateNonce)));
|
||||
}
|
||||
|
||||
cache.put(idempotency.key.clone(), ());
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
pub mod bridge;
|
||||
pub mod bulk_permissions;
|
||||
pub mod idempotency;
|
||||
pub mod permissions;
|
||||
pub mod reference;
|
||||
|
||||
@@ -53,6 +53,12 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
if let Some(other_user) = &self.user {
|
||||
if self.perspective.id == other_user.id {
|
||||
return RelationshipStatus::User;
|
||||
} else if let Some(bot) = &other_user.bot {
|
||||
// For the purposes of permissions checks,
|
||||
// assume owner is the same as bot
|
||||
if self.perspective.id == bot.owner {
|
||||
return RelationshipStatus::User;
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(relations) = &self.perspective.relations {
|
||||
@@ -181,7 +187,7 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
|
||||
async fn do_we_have_publish_overwrites(&mut self) -> bool {
|
||||
if let Some(member) = &self.member {
|
||||
member.can_publish.unwrap_or(true)
|
||||
member.can_publish.unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
@@ -189,7 +195,7 @@ impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
|
||||
async fn do_we_have_receive_overwrites(&mut self) -> bool {
|
||||
if let Some(member) = &self.member {
|
||||
member.can_receive.unwrap_or(true)
|
||||
member.can_receive.unwrap_or(false)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
use std::str::FromStr;
|
||||
|
||||
use revolt_result::Result;
|
||||
#[cfg(feature = "rocket-impl")]
|
||||
use rocket::request::FromParam;
|
||||
@@ -44,9 +46,27 @@ impl Reference {
|
||||
db.fetch_channel(&self.id).await
|
||||
}
|
||||
|
||||
/// Fetch invite from Ref
|
||||
/// Fetch invite from Ref or create invite to server if discoverable
|
||||
pub async fn as_invite(&self, db: &Database) -> Result<Invite> {
|
||||
db.fetch_invite(&self.id).await
|
||||
if ulid::Ulid::from_str(&self.id).is_ok() {
|
||||
let server = self.as_server(db).await?;
|
||||
if !server.discoverable {
|
||||
return Err(create_error!(NotFound));
|
||||
}
|
||||
|
||||
Ok(Invite::Server {
|
||||
code: self.id.to_string(),
|
||||
server: server.id,
|
||||
creator: server.owner,
|
||||
channel: server
|
||||
.channels
|
||||
.into_iter()
|
||||
.next()
|
||||
.ok_or(create_error!(NotFound))?,
|
||||
})
|
||||
} else {
|
||||
db.fetch_invite(&self.id).await
|
||||
}
|
||||
}
|
||||
|
||||
/// Fetch message from Ref
|
||||
|
||||
Reference in New Issue
Block a user