mirror of
https://github.com/stoatchat/stoatchat.git
synced 2026-07-14 13:36:59 +00:00
feat(core): permissions query, finish bots impl
This commit is contained in:
@@ -2,9 +2,9 @@ use authifier::AuthifierEvent;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use revolt_models::v0::{
|
||||
Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsWebhook,
|
||||
MemberCompositeKey, PartialChannel, PartialMember, PartialRole, PartialServer, PartialWebhook,
|
||||
Server, UserSettings, Webhook,
|
||||
Channel, Emoji, FieldsChannel, FieldsMember, FieldsRole, FieldsServer, FieldsUser,
|
||||
FieldsWebhook, MemberCompositeKey, PartialChannel, PartialMember, PartialRole, PartialServer,
|
||||
PartialUser, PartialWebhook, Server, UserSettings, Webhook,
|
||||
};
|
||||
use revolt_result::Error;
|
||||
|
||||
@@ -145,7 +145,7 @@ pub enum EventV1 {
|
||||
/// Server role deleted
|
||||
ServerRoleDelete { id: String, role_id: String },
|
||||
|
||||
/*/// Update existing user
|
||||
/// Update existing user
|
||||
UserUpdate {
|
||||
id: String,
|
||||
data: PartialUser,
|
||||
@@ -153,7 +153,7 @@ pub enum EventV1 {
|
||||
event_id: Option<String>,
|
||||
},
|
||||
|
||||
/// Relationship with another user changed
|
||||
/*/// Relationship with another user changed
|
||||
UserRelationship {
|
||||
id: String,
|
||||
user: User,
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
use indexmap::{IndexMap, IndexSet};
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use revolt_models::v0::{Embed, MessageSort, MessageWebhook};
|
||||
use revolt_result::{create_error, Result};
|
||||
|
||||
use crate::File;
|
||||
use crate::{Database, File};
|
||||
|
||||
auto_derived_partial!(
|
||||
/// Message
|
||||
@@ -166,7 +167,17 @@ auto_derived!(
|
||||
);
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
impl Message {}
|
||||
impl Message {
|
||||
/// Send a message without any notifications
|
||||
pub async fn send_without_notifications(&mut self, db: &Database) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
|
||||
/// Send a message
|
||||
pub async fn send(&mut self) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Interactions {
|
||||
/// Validate interactions info is correct
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
use std::fmt;
|
||||
|
||||
use revolt_result::Result;
|
||||
use ulid::Ulid;
|
||||
|
||||
use crate::Database;
|
||||
|
||||
auto_derived!(
|
||||
/// Ratelimit Event
|
||||
pub struct RatelimitEvent {
|
||||
@@ -23,3 +28,20 @@ impl fmt::Display for RatelimitEventType {
|
||||
fmt::Debug::fmt(self, f)
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
impl RatelimitEvent {
|
||||
/// Create ratelimit event
|
||||
pub async fn create(
|
||||
db: &Database,
|
||||
target_id: String,
|
||||
event_type: RatelimitEventType,
|
||||
) -> Result<()> {
|
||||
db.insert_ratelimit_event(&RatelimitEvent {
|
||||
id: Ulid::new().to_string(),
|
||||
target_id,
|
||||
event_type,
|
||||
})
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
use iso8601_timestamp::Timestamp;
|
||||
use revolt_result::Result;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
|
||||
use crate::{Database, File, Server};
|
||||
use crate::{
|
||||
events::client::EventV1, util::permissions::DatabasePermissionQuery, Database, File, Server,
|
||||
User,
|
||||
};
|
||||
|
||||
auto_derived_partial!(
|
||||
/// Server Member
|
||||
@@ -57,7 +61,85 @@ auto_derived!(
|
||||
}
|
||||
);
|
||||
|
||||
#[allow(clippy::disallowed_methods)]
|
||||
impl Member {
|
||||
/// Create a new member in a server
|
||||
pub async fn create(
|
||||
db: &Database,
|
||||
server: &Server,
|
||||
user: &User,
|
||||
// channels: Option<Vec<Channel>>,
|
||||
//) -> Result<Vec<Channel>> {
|
||||
) -> Result<()> {
|
||||
if db.fetch_ban(&server.id, &user.id).await.is_ok() {
|
||||
return Err(create_error!(Banned));
|
||||
}
|
||||
|
||||
let member = Member {
|
||||
id: MemberCompositeKey {
|
||||
server: server.id.to_string(),
|
||||
user: user.id.to_string(),
|
||||
},
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
db.insert_member(&member).await?;
|
||||
|
||||
let mut channels = vec![];
|
||||
|
||||
if true {
|
||||
let query = DatabasePermissionQuery::new(db, user).server(server);
|
||||
let existing_channels = db.fetch_channels(&server.channels).await?;
|
||||
|
||||
for channel in existing_channels {
|
||||
let mut channel_query = query.clone().channel(&channel);
|
||||
|
||||
if calculate_channel_permissions(&mut channel_query)
|
||||
.await
|
||||
.has_channel_permission(ChannelPermission::ViewChannel)
|
||||
{
|
||||
channels.push(channel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EventV1::ServerMemberJoin {
|
||||
id: server.id.clone(),
|
||||
user: user.id.clone(),
|
||||
}
|
||||
.p(server.id.clone())
|
||||
.await;
|
||||
|
||||
EventV1::ServerCreate {
|
||||
id: server.id.clone(),
|
||||
server: server.clone().into(),
|
||||
channels: channels
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(|channel| channel.into())
|
||||
.collect(),
|
||||
}
|
||||
.private(user.id.clone())
|
||||
.await;
|
||||
|
||||
if let Some(_id) = server
|
||||
.system_messages
|
||||
.as_ref()
|
||||
.and_then(|x| x.user_joined.as_ref())
|
||||
{
|
||||
/* TODO: SystemMessage::UserJoined {
|
||||
id: user.id.clone(),
|
||||
}
|
||||
.into_message(id.to_string())
|
||||
.create_no_web_push(db, id, false)
|
||||
.await
|
||||
.ok(); */
|
||||
}
|
||||
|
||||
// Ok(channels)
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Update member data
|
||||
pub async fn update<'a>(
|
||||
&mut self,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use std::{collections::HashSet, time::Duration};
|
||||
|
||||
use crate::{Database, File, RatelimitEvent};
|
||||
use crate::{events::client::EventV1, Database, File, RatelimitEvent};
|
||||
|
||||
use once_cell::sync::Lazy;
|
||||
use rand::seq::SliceRandom;
|
||||
@@ -51,6 +51,15 @@ auto_derived_partial!(
|
||||
);
|
||||
|
||||
auto_derived!(
|
||||
/// Optional fields on user object
|
||||
pub enum FieldsUser {
|
||||
Avatar,
|
||||
StatusText,
|
||||
StatusPresence,
|
||||
ProfileContent,
|
||||
ProfileBackground,
|
||||
}
|
||||
|
||||
/// User's relationship with another user (or themselves)
|
||||
pub enum RelationshipStatus {
|
||||
None,
|
||||
@@ -108,15 +117,6 @@ auto_derived!(
|
||||
/// Id of the owner of this bot
|
||||
pub owner: String,
|
||||
}
|
||||
|
||||
/// Optional fields on user object
|
||||
pub enum FieldsUser {
|
||||
Avatar,
|
||||
StatusText,
|
||||
StatusPresence,
|
||||
ProfileContent,
|
||||
ProfileBackground,
|
||||
}
|
||||
);
|
||||
|
||||
pub static DISCRIMINATOR_SEARCH_SPACE: Lazy<HashSet<String>> = Lazy::new(|| {
|
||||
@@ -229,11 +229,11 @@ impl User {
|
||||
return Err(create_error!(DiscriminatorChangeRatelimited));
|
||||
}
|
||||
|
||||
db.insert_ratelimit_event(&RatelimitEvent {
|
||||
id: Ulid::new().to_string(),
|
||||
RatelimitEvent::create(
|
||||
db,
|
||||
target_id,
|
||||
event_type: crate::RatelimitEventType::DiscriminatorChange,
|
||||
})
|
||||
crate::RatelimitEventType::DiscriminatorChange,
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
@@ -245,6 +245,40 @@ impl User {
|
||||
.to_string())
|
||||
}
|
||||
|
||||
/// Update a user's username
|
||||
pub async fn update_username(&mut self, db: &Database, username: String) -> Result<()> {
|
||||
let username = User::validate_username(username)?;
|
||||
if self.username.to_lowercase() == username.to_lowercase() {
|
||||
self.update(
|
||||
db,
|
||||
PartialUser {
|
||||
username: Some(username),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
} else {
|
||||
self.update(
|
||||
db,
|
||||
PartialUser {
|
||||
discriminator: Some(
|
||||
User::find_discriminator(
|
||||
db,
|
||||
&username,
|
||||
Some((self.discriminator.to_string(), self.id.clone())),
|
||||
)
|
||||
.await?,
|
||||
),
|
||||
username: Some(username),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await
|
||||
}
|
||||
}
|
||||
|
||||
/// Check whether a username is already in use by another user
|
||||
#[allow(dead_code)]
|
||||
async fn is_username_taken(db: &Database, username: &str) -> Result<bool> {
|
||||
@@ -272,13 +306,14 @@ impl User {
|
||||
self.apply_options(partial.clone());
|
||||
db.update_user(&self.id, &partial, remove.clone()).await?;
|
||||
|
||||
/* // TODO: EventV1::UserUpdate {
|
||||
EventV1::UserUpdate {
|
||||
id: self.id.clone(),
|
||||
data: partial,
|
||||
clear: remove,
|
||||
data: partial.into(),
|
||||
clear: remove.into_iter().map(|v| v.into()).collect(),
|
||||
event_id: Some(Ulid::new().to_string()),
|
||||
}
|
||||
.p_user(self.id.clone(), db)
|
||||
.await; */
|
||||
.await;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -34,6 +34,24 @@ impl From<crate::Bot> for Bot {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FieldsBot> for crate::FieldsBot {
|
||||
fn from(value: FieldsBot) -> Self {
|
||||
match value {
|
||||
FieldsBot::InteractionsURL => crate::FieldsBot::InteractionsURL,
|
||||
FieldsBot::Token => crate::FieldsBot::Token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::FieldsBot> for FieldsBot {
|
||||
fn from(value: crate::FieldsBot) -> Self {
|
||||
match value {
|
||||
crate::FieldsBot::InteractionsURL => FieldsBot::InteractionsURL,
|
||||
crate::FieldsBot::Token => FieldsBot::Token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::Invite> for Invite {
|
||||
fn from(value: crate::Invite) -> Self {
|
||||
match value {
|
||||
@@ -622,8 +640,8 @@ impl crate::User {
|
||||
})
|
||||
.unwrap_or_default(),
|
||||
badges: self.badges.unwrap_or_default() as u32,
|
||||
status: None,
|
||||
profile: None,
|
||||
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()),
|
||||
@@ -634,6 +652,56 @@ impl crate::User {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::PartialUser> for PartialUser {
|
||||
fn from(value: crate::PartialUser) -> Self {
|
||||
PartialUser {
|
||||
username: value.username,
|
||||
discriminator: value.discriminator,
|
||||
display_name: value.display_name,
|
||||
avatar: value.avatar.map(|file| file.into()),
|
||||
relations: value.relations.map(|relationships| {
|
||||
relationships
|
||||
.into_iter()
|
||||
.map(|relationship| relationship.into())
|
||||
.collect()
|
||||
}),
|
||||
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()),
|
||||
relationship: None,
|
||||
online: None,
|
||||
id: value.id,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FieldsUser> for crate::FieldsUser {
|
||||
fn from(value: FieldsUser) -> Self {
|
||||
match value {
|
||||
FieldsUser::Avatar => crate::FieldsUser::Avatar,
|
||||
FieldsUser::ProfileBackground => crate::FieldsUser::ProfileBackground,
|
||||
FieldsUser::ProfileContent => crate::FieldsUser::ProfileContent,
|
||||
FieldsUser::StatusPresence => crate::FieldsUser::StatusPresence,
|
||||
FieldsUser::StatusText => crate::FieldsUser::StatusText,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::FieldsUser> for FieldsUser {
|
||||
fn from(value: crate::FieldsUser) -> Self {
|
||||
match value {
|
||||
crate::FieldsUser::Avatar => FieldsUser::Avatar,
|
||||
crate::FieldsUser::ProfileBackground => FieldsUser::ProfileBackground,
|
||||
crate::FieldsUser::ProfileContent => FieldsUser::ProfileContent,
|
||||
crate::FieldsUser::StatusPresence => FieldsUser::StatusPresence,
|
||||
crate::FieldsUser::StatusText => FieldsUser::StatusText,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<crate::RelationshipStatus> for RelationshipStatus {
|
||||
fn from(value: crate::RelationshipStatus) -> Self {
|
||||
match value {
|
||||
|
||||
@@ -4,18 +4,19 @@ use revolt_permissions::{
|
||||
calculate_user_permissions, ChannelType, Override, PermissionQuery, RelationshipStatus,
|
||||
};
|
||||
|
||||
use crate::{Database, User};
|
||||
use crate::{Channel, Database, Member, Server, User};
|
||||
|
||||
/// Permissions calculator
|
||||
pub struct PermissionCalculator<'a> {
|
||||
#[derive(Clone)]
|
||||
pub struct DatabasePermissionQuery<'a> {
|
||||
#[allow(dead_code)]
|
||||
database: &'a Database,
|
||||
|
||||
perspective: &'a User,
|
||||
user: Option<Cow<'a, User>>,
|
||||
// pub channel: Cow<'a, Channel>,
|
||||
// pub server: Cow<'a, Server>,
|
||||
// pub member: Cow<'a, Member>,
|
||||
channel: Option<Cow<'a, Channel>>,
|
||||
server: Option<Cow<'a, Server>>,
|
||||
member: Option<Cow<'a, Member>>,
|
||||
|
||||
// flag_known_relationship: Option<&'a RelationshipStatus>,
|
||||
cached_user_permission: Option<u32>,
|
||||
@@ -23,7 +24,7 @@ pub struct PermissionCalculator<'a> {
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl PermissionQuery for PermissionCalculator<'_> {
|
||||
impl PermissionQuery for DatabasePermissionQuery<'_> {
|
||||
// * For calculating user permission
|
||||
|
||||
/// Is our perspective user privileged?
|
||||
@@ -153,13 +154,16 @@ impl PermissionQuery for PermissionCalculator<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> PermissionCalculator<'a> {
|
||||
impl<'a> DatabasePermissionQuery<'a> {
|
||||
/// Create a new permission calculator
|
||||
pub fn new(database: &'a Database, perspective: &'a User) -> PermissionCalculator<'a> {
|
||||
PermissionCalculator {
|
||||
pub fn new(database: &'a Database, perspective: &'a User) -> DatabasePermissionQuery<'a> {
|
||||
DatabasePermissionQuery {
|
||||
database,
|
||||
perspective,
|
||||
user: None,
|
||||
channel: None,
|
||||
server: None,
|
||||
member: None,
|
||||
|
||||
cached_user_permission: None,
|
||||
cached_permission: None,
|
||||
@@ -167,7 +171,7 @@ impl<'a> PermissionCalculator<'a> {
|
||||
}
|
||||
|
||||
/// Calculate the user permission value
|
||||
pub async fn calc_user(mut self) -> PermissionCalculator<'a> {
|
||||
pub async fn calc_user(mut self) -> DatabasePermissionQuery<'a> {
|
||||
if self.cached_user_permission.is_some() {
|
||||
return self;
|
||||
}
|
||||
@@ -176,14 +180,14 @@ impl<'a> PermissionCalculator<'a> {
|
||||
panic!("Expected `PermissionCalculator.user to exist.");
|
||||
}
|
||||
|
||||
PermissionCalculator {
|
||||
DatabasePermissionQuery {
|
||||
cached_user_permission: Some(calculate_user_permissions(&mut self).await),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate the permission value
|
||||
pub async fn calc(self) -> PermissionCalculator<'a> {
|
||||
pub async fn calc(self) -> DatabasePermissionQuery<'a> {
|
||||
if self.cached_permission.is_some() {
|
||||
return self;
|
||||
}
|
||||
@@ -192,15 +196,39 @@ impl<'a> PermissionCalculator<'a> {
|
||||
}
|
||||
|
||||
/// Use user
|
||||
pub fn user(self, user: Cow<'a, User>) -> PermissionCalculator {
|
||||
PermissionCalculator {
|
||||
user: Some(user),
|
||||
pub fn user(self, user: &'a User) -> DatabasePermissionQuery {
|
||||
DatabasePermissionQuery {
|
||||
user: Some(Cow::Borrowed(user)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Use channel
|
||||
pub fn channel(self, channel: &'a Channel) -> DatabasePermissionQuery {
|
||||
DatabasePermissionQuery {
|
||||
channel: Some(Cow::Borrowed(channel)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Use server
|
||||
pub fn server(self, server: &'a Server) -> DatabasePermissionQuery {
|
||||
DatabasePermissionQuery {
|
||||
server: Some(Cow::Borrowed(server)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
|
||||
/// Use member
|
||||
pub fn member(self, member: &'a Member) -> DatabasePermissionQuery {
|
||||
DatabasePermissionQuery {
|
||||
member: Some(Cow::Borrowed(member)),
|
||||
..self
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Short-hand for creating a permission calculator
|
||||
pub fn perms<'a>(database: &'a Database, perspective: &'a User) -> PermissionCalculator<'a> {
|
||||
PermissionCalculator::new(database, perspective)
|
||||
pub fn perms<'a>(database: &'a Database, perspective: &'a User) -> DatabasePermissionQuery<'a> {
|
||||
DatabasePermissionQuery::new(database, perspective)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user