fix: squash audit log branch changes
Signed-off-by: Zomatree <me@zomatree.live>
This commit is contained in:
@@ -4,7 +4,7 @@ use revolt_database::{
|
||||
delete_voice_channel, is_in_voice_channel, remove_user_from_voice_channel,
|
||||
UserVoiceChannel, VoiceClient,
|
||||
},
|
||||
Channel, Database, PartialChannel, User, AMQP,
|
||||
AuditLogEntryAction, Channel, Database, PartialChannel, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -12,6 +12,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Close Channel
|
||||
///
|
||||
/// Deletes a server channel, leaves a group or closes a group.
|
||||
@@ -22,6 +24,7 @@ pub async fn delete(
|
||||
voice_client: &State<VoiceClient>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
options: v0::OptionsChannelDelete,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -63,10 +66,17 @@ pub async fn delete(
|
||||
remove_user_from_voice_channel(voice_client, &user_voice_channel, &user.id).await?;
|
||||
};
|
||||
}
|
||||
Channel::TextChannel { .. } => {
|
||||
Channel::TextChannel { name, server, .. } => {
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
channel.delete(db).await?;
|
||||
|
||||
AuditLogEntryAction::ChannelDelete {
|
||||
channel: channel.id().to_string(),
|
||||
name: name.clone(),
|
||||
}
|
||||
.insert(db, server.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
delete_voice_channel(voice_client, &UserVoiceChannel::from_channel(&channel)).await?;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{delete_voice_channel, UserVoiceChannel, VoiceClient},
|
||||
Channel, Database, File, PartialChannel, SystemMessage, User, AMQP,
|
||||
AuditLogEntryAction, Channel, Database, FieldsChannel, File, PartialChannel, SystemMessage,
|
||||
User, AMQP,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -9,6 +10,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Edit Channel
|
||||
///
|
||||
/// Edit a channel object by its id.
|
||||
@@ -19,6 +22,7 @@ pub async fn edit(
|
||||
voice_client: &State<VoiceClient>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataEditChannel>,
|
||||
) -> Result<Json<v0::Channel>> {
|
||||
@@ -91,6 +95,8 @@ pub async fn edit(
|
||||
.ok();
|
||||
}
|
||||
|
||||
let before_channel = channel.clone();
|
||||
|
||||
match &mut channel {
|
||||
Channel::Group {
|
||||
id,
|
||||
@@ -258,17 +264,33 @@ pub async fn edit(
|
||||
_ => return Err(create_error!(InvalidOperation)),
|
||||
};
|
||||
|
||||
channel
|
||||
.update(
|
||||
db,
|
||||
partial,
|
||||
data.remove.into_iter().map(|f| f.into()).collect(),
|
||||
)
|
||||
.await?;
|
||||
let remove = data
|
||||
.remove
|
||||
.into_iter()
|
||||
.map(|f| f.into())
|
||||
.collect::<Vec<FieldsChannel>>();
|
||||
|
||||
let before = if before_channel.server().is_some() {
|
||||
Some(before_channel.generate_diff(&partial, &remove))
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
channel.update(db, partial.clone(), remove).await?;
|
||||
|
||||
if channel.voice().is_none() {
|
||||
delete_voice_channel(voice_client, &UserVoiceChannel::from_channel(&channel)).await?;
|
||||
}
|
||||
|
||||
if let Some(before) = before {
|
||||
AuditLogEntryAction::ChannelEdit {
|
||||
channel: channel.id().to_string(),
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(db, channel.server().unwrap().to_string(), reason, user.id, None)
|
||||
.await;
|
||||
};
|
||||
|
||||
Ok(Json(channel.into()))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use revolt_database::{
|
||||
AMQP, Channel, Database, User, util::reference::Reference, voice::{UserVoiceChannel, VoiceClient, is_in_voice_channel, remove_user_from_voice_channel}
|
||||
util::reference::Reference,
|
||||
voice::{is_in_voice_channel, remove_user_from_voice_channel, UserVoiceChannel, VoiceClient},
|
||||
Channel, Database, User, AMQP,
|
||||
};
|
||||
use revolt_permissions::ChannelPermission;
|
||||
use revolt_result::{create_error, Result};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, Invite, User,
|
||||
AuditLogEntryAction, Database, Invite, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -8,6 +8,8 @@ use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Create Invite
|
||||
///
|
||||
/// Creates an invite to this channel.
|
||||
@@ -18,6 +20,7 @@ use rocket::{serde::json::Json, State};
|
||||
pub async fn create_invite(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
) -> Result<Json<v0::Invite>> {
|
||||
if user.bot.is_some() {
|
||||
@@ -30,8 +33,16 @@ pub async fn create_invite(
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::InviteOthers)?;
|
||||
|
||||
Invite::create_channel_invite(db, &user, &channel)
|
||||
.await
|
||||
.map(|invite| invite.into())
|
||||
.map(Json)
|
||||
let invite = Invite::create_channel_invite(db, &user, &channel).await?;
|
||||
|
||||
if let Some(server_id) = channel.server() {
|
||||
AuditLogEntryAction::InviteCreate {
|
||||
invite: invite.code().to_string(),
|
||||
channel: channel.id().to_string(),
|
||||
}
|
||||
.insert(db, server_id.to_string(), reason, user.id, None)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(Json(invite.into()))
|
||||
}
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::time::Duration;
|
||||
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, Message, User,
|
||||
AuditLogEntryAction, Database, Message, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -11,6 +11,8 @@ use rocket::{serde::json::Json, State};
|
||||
use rocket_empty::EmptyResponse;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Bulk Delete Messages
|
||||
///
|
||||
/// Delete multiple messages you've sent or one you have permission to delete.
|
||||
@@ -23,6 +25,7 @@ use validator::Validate;
|
||||
pub async fn bulk_delete_messages(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
options: Json<v0::OptionsBulkDelete>,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -51,7 +54,16 @@ pub async fn bulk_delete_messages(
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageMessages)?;
|
||||
|
||||
Message::bulk_delete(db, target.id, options.ids)
|
||||
.await
|
||||
.map(|_| EmptyResponse)
|
||||
Message::bulk_delete(db, target.id, options.ids.clone()).await?;
|
||||
|
||||
if let Some(server) = channel.server() {
|
||||
AuditLogEntryAction::MessageBulkDelete {
|
||||
channel: channel.id().to_string(),
|
||||
count: options.ids.len(),
|
||||
}
|
||||
.insert(db, server.to_string(), reason, user.id, None)
|
||||
.await;
|
||||
};
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, User,
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Delete Message
|
||||
///
|
||||
/// Delete a message you've sent or one you have permission to delete.
|
||||
@@ -15,18 +17,40 @@ use rocket_empty::EmptyResponse;
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
msg: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
let message = msg.as_message_in_channel(db, target.id).await?;
|
||||
|
||||
if message.author != user.id {
|
||||
let channel = if message.author != user.id {
|
||||
let channel = target.as_channel(db).await?;
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).channel(&channel);
|
||||
calculate_channel_permissions(&mut query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageMessages)?;
|
||||
}
|
||||
|
||||
message.delete(db).await.map(|_| EmptyResponse)
|
||||
Some(channel)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
message.delete(db).await?;
|
||||
|
||||
if let Some(server) = channel.and_then(|c| c.server().map(|s| s.to_string())) {
|
||||
AuditLogEntryAction::MessageDelete {
|
||||
author: message.author.clone(),
|
||||
channel: message.channel.clone(),
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server.to_string(),
|
||||
reason,
|
||||
user.id.clone(),
|
||||
Some(message.author),
|
||||
)
|
||||
.await;
|
||||
};
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, PartialMessage, SystemMessage, User, AMQP,
|
||||
AuditLogEntryAction, Channel, Database, PartialMessage, SystemMessage, User, AMQP,
|
||||
};
|
||||
use revolt_models::v0::MessageAuthor;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -8,6 +8,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Pins a message
|
||||
///
|
||||
/// Pins a message by its id.
|
||||
@@ -17,6 +19,7 @@ pub async fn message_pin(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
msg: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -65,6 +68,22 @@ pub async fn message_pin(
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(server_id) = channel.server() {
|
||||
AuditLogEntryAction::MessagePin {
|
||||
message: message.id.clone(),
|
||||
author: message.author.clone(),
|
||||
channel: message.channel.clone(),
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server_id.to_string(),
|
||||
reason,
|
||||
user.id,
|
||||
Some(message.author),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, FieldsMessage, PartialMessage, SystemMessage, User, AMQP,
|
||||
AuditLogEntryAction, Channel, Database, FieldsMessage, PartialMessage, SystemMessage, User,
|
||||
AMQP,
|
||||
};
|
||||
use revolt_models::v0::MessageAuthor;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
@@ -8,6 +9,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Unpins a message
|
||||
///
|
||||
/// Unpins a message by its id.
|
||||
@@ -17,6 +20,7 @@ pub async fn message_unpin(
|
||||
db: &State<Database>,
|
||||
amqp: &State<AMQP>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
msg: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -58,6 +62,22 @@ pub async fn message_unpin(
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(server_id) = channel.server() {
|
||||
AuditLogEntryAction::MessageUnpin {
|
||||
message: message.id.clone(),
|
||||
author: message.author.clone(),
|
||||
channel: message.channel.clone(),
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server_id.to_string(),
|
||||
reason,
|
||||
user.id,
|
||||
Some(message.author),
|
||||
)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,11 +1,17 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, voice::{sync_voice_permissions, VoiceClient}, Database, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission, Override};
|
||||
use revolt_permissions::{
|
||||
calculate_channel_permissions, ChannelPermission, Override, OverrideField,
|
||||
};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Set Role Permission
|
||||
///
|
||||
/// Sets permissions for the specified role in this channel.
|
||||
@@ -17,13 +23,15 @@ pub async fn set_role_permissions(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
role_id: String,
|
||||
data: Json<v0::DataSetRolePermissions>,
|
||||
) -> Result<Json<v0::Channel>> {
|
||||
let channel = target.as_channel(db).await?;
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).channel(&channel);
|
||||
let permissions: revolt_permissions::PermissionValue = calculate_channel_permissions(&mut query).await;
|
||||
let permissions: revolt_permissions::PermissionValue =
|
||||
calculate_channel_permissions(&mut query).await;
|
||||
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::ManagePermissions)?;
|
||||
|
||||
@@ -39,12 +47,23 @@ pub async fn set_role_permissions(
|
||||
.await?;
|
||||
|
||||
let mut new_channel = channel.clone();
|
||||
let override_field: OverrideField = data.permissions.clone().into();
|
||||
let server_id = server.id.clone();
|
||||
|
||||
new_channel
|
||||
.set_role_permission(db, &role_id, data.permissions.clone().into())
|
||||
.await?;
|
||||
|
||||
sync_voice_permissions(db, voice_client, &new_channel, Some(server), Some(&role_id)).await?;
|
||||
sync_voice_permissions(db, voice_client, &new_channel, Some(server), Some(&role_id))
|
||||
.await?;
|
||||
|
||||
AuditLogEntryAction::ChannelRolePermissionsEdit {
|
||||
channel: new_channel.id().to_string(),
|
||||
role: role_id,
|
||||
permissions: override_field,
|
||||
}
|
||||
.insert(db, server_id, reason, user.id, None)
|
||||
.await;
|
||||
|
||||
Ok(Json(new_channel.into()))
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, voice::{sync_voice_permissions, VoiceClient}, Channel, Database, PartialChannel, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
AuditLogEntryAction, Channel, Database, PartialChannel, User,
|
||||
};
|
||||
use revolt_models::v0::{self, DataDefaultChannelPermissions};
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Set Default Permission
|
||||
///
|
||||
/// Sets permissions for the default role in this channel.
|
||||
@@ -17,6 +21,7 @@ pub async fn set_default_channel_permissions(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataDefaultChannelPermissions>,
|
||||
) -> Result<Json<v0::Channel>> {
|
||||
@@ -46,6 +51,8 @@ pub async fn set_default_channel_permissions(
|
||||
}
|
||||
}
|
||||
Channel::TextChannel {
|
||||
id,
|
||||
server,
|
||||
default_permissions,
|
||||
..
|
||||
} => {
|
||||
@@ -54,16 +61,25 @@ pub async fn set_default_channel_permissions(
|
||||
.throw_permission_override(default_permissions.map(|x| x.into()), &field)
|
||||
.await?;
|
||||
|
||||
channel
|
||||
.update(
|
||||
db,
|
||||
PartialChannel {
|
||||
default_permissions: Some(field.into()),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await?;
|
||||
let partial = PartialChannel {
|
||||
default_permissions: Some(field.into()),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let id = id.clone();
|
||||
let server = server.clone();
|
||||
|
||||
let before = channel.generate_diff(&partial, &[]);
|
||||
|
||||
channel.update(db, partial.clone(), vec![]).await?;
|
||||
|
||||
AuditLogEntryAction::ChannelEdit {
|
||||
channel: id,
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(db, server, reason, user.id, None)
|
||||
.await;
|
||||
} else {
|
||||
return Err(create_error!(InvalidOperation));
|
||||
}
|
||||
@@ -73,7 +89,7 @@ pub async fn set_default_channel_permissions(
|
||||
|
||||
let server = match channel.server() {
|
||||
Some(server_id) => Some(Reference::from_unchecked(server_id).as_server(db).await?),
|
||||
None => None
|
||||
None => None,
|
||||
};
|
||||
|
||||
sync_voice_permissions(db, voice_client, &channel, server.as_ref(), None).await?;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Channel, Database, File, User, Webhook,
|
||||
AuditLogEntryAction, Channel, Database, File, User, Webhook,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{
|
||||
@@ -11,6 +11,8 @@ use rocket::{serde::json::Json, State};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Creates a webhook
|
||||
///
|
||||
/// Creates a webhook which 3rd party platforms can use to send messages
|
||||
@@ -19,6 +21,7 @@ use validator::Validate;
|
||||
pub async fn create_webhook(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
channel_id: Reference<'_>,
|
||||
data: Json<v0::CreateWebhookBody>,
|
||||
) -> Result<Json<v0::Webhook>> {
|
||||
@@ -51,7 +54,7 @@ pub async fn create_webhook(
|
||||
id: webhook_id,
|
||||
name: data.name,
|
||||
avatar,
|
||||
creator_id: user.id,
|
||||
creator_id: user.id.clone(),
|
||||
channel_id: channel.id().to_string(),
|
||||
permissions: *DEFAULT_WEBHOOK_PERMISSIONS,
|
||||
token: Some(nanoid::nanoid!(64)),
|
||||
@@ -59,5 +62,15 @@ pub async fn create_webhook(
|
||||
|
||||
webhook.create(db).await?;
|
||||
|
||||
if let Some(server_id) = channel.server() {
|
||||
AuditLogEntryAction::WebhookCreate {
|
||||
webhook: webhook.id.clone(),
|
||||
name: webhook.name.clone(),
|
||||
channel: webhook.channel_id.clone(),
|
||||
}
|
||||
.insert(db, server_id.to_string(), reason, user.id, None)
|
||||
.await;
|
||||
};
|
||||
|
||||
Ok(Json(webhook.into()))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{util::permissions::DatabasePermissionQuery, Database, Emoji, File, User};
|
||||
use revolt_database::{AuditLogEntryAction, Database, Emoji, File, User, util::permissions::DatabasePermissionQuery};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
@@ -7,6 +7,8 @@ use validator::Validate;
|
||||
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Create New Emoji
|
||||
///
|
||||
/// Create an emoji by its Autumn upload id.
|
||||
@@ -15,6 +17,7 @@ use rocket::{serde::json::Json, State};
|
||||
pub async fn create_emoji(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
emoji_id: String,
|
||||
data: Json<v0::DataCreateEmoji>,
|
||||
) -> Result<Json<v0::Emoji>> {
|
||||
@@ -55,8 +58,8 @@ pub async fn create_emoji(
|
||||
// Create the emoji object
|
||||
let emoji = Emoji {
|
||||
id: emoji_id,
|
||||
parent: data.parent.into(),
|
||||
creator_id: user.id,
|
||||
parent: data.parent.clone().into(),
|
||||
creator_id: user.id.clone(),
|
||||
name: data.name,
|
||||
animated: "image/gif" == &attachment.content_type,
|
||||
nsfw: data.nsfw,
|
||||
@@ -64,5 +67,12 @@ pub async fn create_emoji(
|
||||
|
||||
// Save emoji
|
||||
emoji.create(db).await?;
|
||||
|
||||
if let v0::EmojiParent::Server { id: server_id } = data.parent {
|
||||
AuditLogEntryAction::EmojiCreate { emoji: emoji.id.clone(), name: emoji.name.clone() }
|
||||
.insert(db, server_id, reason, user.id, None)
|
||||
.await;
|
||||
}
|
||||
|
||||
Ok(Json(emoji.into()))
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, EmojiParent, User,
|
||||
AuditLogEntryAction, Database, EmojiParent, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::Result;
|
||||
@@ -8,6 +8,8 @@ use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Delete Emoji
|
||||
///
|
||||
/// Delete an emoji by its id.
|
||||
@@ -16,6 +18,7 @@ use rocket_empty::EmptyResponse;
|
||||
pub async fn delete_emoji(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
emoji_id: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
// Fetch the emoji
|
||||
@@ -39,5 +42,16 @@ pub async fn delete_emoji(
|
||||
}
|
||||
|
||||
// Delete the emoji
|
||||
emoji.delete(db).await.map(|_| EmptyResponse)
|
||||
emoji.delete(db).await?;
|
||||
|
||||
if let EmojiParent::Server { id: server_id } = emoji.parent {
|
||||
AuditLogEntryAction::EmojiDelete {
|
||||
emoji: emoji.id,
|
||||
name: emoji.name,
|
||||
}
|
||||
.insert(db, server_id, reason, user.id, Some(emoji.creator_id))
|
||||
.await;
|
||||
};
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,35 +1,56 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, Invite, User,
|
||||
AuditLogEntryAction, Database, Invite, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Delete Invite
|
||||
///
|
||||
/// Delete an invite by its id.
|
||||
#[openapi(tag = "Invites")]
|
||||
#[delete("/<target>")]
|
||||
pub async fn delete(db: &State<Database>, user: User, target: Reference<'_>) -> Result<EmptyResponse> {
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
let invite = target.as_invite(db).await?;
|
||||
|
||||
if user.id == invite.creator() {
|
||||
db.delete_invite(invite.code()).await
|
||||
db.delete_invite(invite.code()).await?;
|
||||
} else {
|
||||
match invite {
|
||||
Invite::Server { code, server, .. } => {
|
||||
Invite::Server {
|
||||
code,
|
||||
server,
|
||||
channel,
|
||||
creator,
|
||||
..
|
||||
} => {
|
||||
let server = db.fetch_server(&server).await?;
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
|
||||
calculate_server_permissions(&mut query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageServer)?;
|
||||
|
||||
db.delete_invite(&code).await
|
||||
db.delete_invite(&code).await?;
|
||||
|
||||
AuditLogEntryAction::InviteDelete {
|
||||
invite: code,
|
||||
channel,
|
||||
}
|
||||
.insert(db, server.id, reason, user.id, Some(creator))
|
||||
.await;
|
||||
}
|
||||
_ => unreachable!(),
|
||||
}
|
||||
}
|
||||
.map(|_| EmptyResponse)
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
227
crates/delta/src/routes/servers/audit_log_query.rs
Normal file
227
crates/delta/src/routes/servers/audit_log_query.rs
Normal file
@@ -0,0 +1,227 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
AuditLogEntry, AuditLogQuery, Database, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
/// # Audit Log Query
|
||||
///
|
||||
/// Queries a server's audit logs.
|
||||
#[openapi(tag = "Audit Logs")]
|
||||
#[get("/<target>/audit_logs?<options..>")]
|
||||
pub async fn query(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
target: Reference<'_>,
|
||||
options: v0::OptionsAuditLogQuery,
|
||||
) -> Result<Json<v0::AuditLogQueryResponse>> {
|
||||
options.validate().map_err(|error| {
|
||||
create_error!(FailedValidation {
|
||||
error: error.to_string()
|
||||
})
|
||||
})?;
|
||||
|
||||
let server = target.as_server(db).await?;
|
||||
|
||||
let mut query = DatabasePermissionQuery::new(db, &user).server(&server);
|
||||
calculate_server_permissions(&mut query)
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ViewAuditLogs)?;
|
||||
|
||||
let v0::OptionsAuditLogQuery {
|
||||
user: user_filter,
|
||||
target,
|
||||
r#type,
|
||||
before,
|
||||
after,
|
||||
limit,
|
||||
} = options;
|
||||
|
||||
let audit_logs = db
|
||||
.get_server_audit_logs(
|
||||
&server.id,
|
||||
AuditLogQuery {
|
||||
user: user_filter,
|
||||
target,
|
||||
r#type,
|
||||
before,
|
||||
after,
|
||||
limit: limit.unwrap_or(50),
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
|
||||
let (users, members) = AuditLogEntry::with_users(db, &server.id, &user, &audit_logs).await?;
|
||||
|
||||
Ok(Json(v0::AuditLogQueryResponse {
|
||||
audit_logs: audit_logs.into_iter().map(Into::into).collect(),
|
||||
users,
|
||||
members,
|
||||
}))
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use revolt_database::{Member, Server};
|
||||
use revolt_models::v0;
|
||||
use rocket::http::{Header, Status};
|
||||
|
||||
use crate::util::test::TestHarness;
|
||||
|
||||
#[rocket::async_test]
|
||||
async fn audit_log_query() {
|
||||
let harness = TestHarness::new().await;
|
||||
let (_, session, user) = harness.new_user().await;
|
||||
let (server, channels) = Server::create(
|
||||
&harness.db,
|
||||
v0::DataCreateServer {
|
||||
name: "Test Server".to_string(),
|
||||
..Default::default()
|
||||
},
|
||||
&user,
|
||||
true,
|
||||
)
|
||||
.await
|
||||
.expect("Failed to create test server.");
|
||||
Member::create(&harness.db, &server, &user, None).await.unwrap();
|
||||
|
||||
let channel = &channels[0];
|
||||
|
||||
let status = harness
|
||||
.client
|
||||
.patch(format!("/channels/{}", channel.id()))
|
||||
.header(Header::new("X-Audit-Log-Reason", "Test Reason 1"))
|
||||
.header(Header::new("x-session-token", session.token.clone()))
|
||||
.json(&v0::DataEditChannel {
|
||||
description: Some("General chat channel.".to_string()),
|
||||
name: None,
|
||||
owner: None,
|
||||
icon: None,
|
||||
nsfw: None,
|
||||
archived: None,
|
||||
voice: None,
|
||||
slowmode: None,
|
||||
remove: Vec::new(),
|
||||
})
|
||||
.dispatch()
|
||||
.await
|
||||
.status();
|
||||
|
||||
assert_eq!(status, Status::Ok);
|
||||
|
||||
let status = harness
|
||||
.client
|
||||
.patch(format!("/channels/{}", channel.id()))
|
||||
.header(Header::new("X-Audit-Log-Reason", "Test Reason 2"))
|
||||
.header(Header::new("x-session-token", session.token.clone()))
|
||||
.json(&v0::DataEditChannel {
|
||||
description: Some("New description.".to_string()),
|
||||
name: None,
|
||||
owner: None,
|
||||
icon: None,
|
||||
nsfw: None,
|
||||
archived: None,
|
||||
voice: None,
|
||||
slowmode: None,
|
||||
remove: Vec::new(),
|
||||
})
|
||||
.dispatch()
|
||||
.await
|
||||
.status();
|
||||
|
||||
assert_eq!(status, Status::Ok);
|
||||
|
||||
let status = harness
|
||||
.client
|
||||
.delete(format!("/channels/{}", channel.id()))
|
||||
.header(Header::new("X-Audit-Log-Reason", "Test Reason 3"))
|
||||
.header(Header::new("x-session-token", session.token.clone()))
|
||||
.dispatch()
|
||||
.await
|
||||
.status();
|
||||
|
||||
assert_eq!(status, Status::NoContent);
|
||||
|
||||
let response = harness
|
||||
.client
|
||||
.get(format!(
|
||||
"/servers/{}/audit_logs?include_users=true",
|
||||
&server.id
|
||||
))
|
||||
.header(Header::new("x-session-token", session.token.clone()))
|
||||
.dispatch()
|
||||
.await
|
||||
.into_json::<v0::AuditLogQueryResponse>()
|
||||
.await
|
||||
.expect("Failed to deserialise audit_logs response");
|
||||
|
||||
let v0::AuditLogQueryResponse {
|
||||
audit_logs: entries,
|
||||
users,
|
||||
members,
|
||||
} = response;
|
||||
|
||||
assert_eq!(entries.len(), 3);
|
||||
assert_eq!(users.len(), 1);
|
||||
assert_eq!(members.len(), 1);
|
||||
|
||||
assert_eq!(&users[0].id, &user.id);
|
||||
|
||||
let entry = &entries[0];
|
||||
|
||||
assert_eq!(entry.reason.as_deref(), Some("Test Reason 3"));
|
||||
assert_eq!(&entry.server, &server.id);
|
||||
assert_eq!(&entry.user, &user.id);
|
||||
assert_eq!(
|
||||
&entry.action,
|
||||
&v0::AuditLogEntryAction::ChannelDelete {
|
||||
channel: channel.id().to_string(),
|
||||
name: "General".to_string()
|
||||
}
|
||||
);
|
||||
|
||||
let entry = &entries[1];
|
||||
|
||||
assert_eq!(entry.reason.as_deref(), Some("Test Reason 2"));
|
||||
assert_eq!(&entry.server, &server.id);
|
||||
assert_eq!(&entry.user, &user.id);
|
||||
assert_eq!(
|
||||
&entry.action,
|
||||
&v0::AuditLogEntryAction::ChannelEdit {
|
||||
channel: channel.id().to_string(),
|
||||
before: v0::PartialChannel {
|
||||
description: Some("General chat channel.".to_string()),
|
||||
..Default::default()
|
||||
},
|
||||
after: v0::PartialChannel {
|
||||
description: Some("New description.".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
let entry = &entries[2];
|
||||
|
||||
assert_eq!(entry.reason.as_deref(), Some("Test Reason 1"));
|
||||
assert_eq!(&entry.server, &server.id);
|
||||
assert_eq!(&entry.user, &user.id);
|
||||
assert_eq!(
|
||||
&entry.action,
|
||||
&v0::AuditLogEntryAction::ChannelEdit {
|
||||
channel: channel.id().to_string(),
|
||||
before: v0::PartialChannel {
|
||||
description: None,
|
||||
..Default::default()
|
||||
},
|
||||
after: v0::PartialChannel {
|
||||
description: Some("General chat channel.".to_string()),
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@ use revolt_database::{
|
||||
get_user_voice_channel_in_server, remove_user_from_voice_channel, UserVoiceChannel,
|
||||
VoiceClient,
|
||||
},
|
||||
Database, Message, RemovalIntention, ServerBan, User,
|
||||
AuditLogEntryAction, Database, Message, RemovalIntention, ServerBan, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use std::time::{Duration, SystemTime};
|
||||
@@ -16,6 +16,8 @@ use rocket::{serde::json::Json, State};
|
||||
use ulid::Ulid;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Ban User
|
||||
///
|
||||
/// Ban a user by their id.
|
||||
@@ -25,6 +27,7 @@ pub async fn ban(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
audit_log_reason: AuditLogReason,
|
||||
server: Reference<'_>,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataBanCreate>,
|
||||
@@ -85,8 +88,20 @@ pub async fn ban(
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
ServerBan::create(db, &server, target.id, data.reason)
|
||||
.await
|
||||
.map(Into::into)
|
||||
.map(Json)
|
||||
|
||||
let ban = ServerBan::create(db, &server, target.id, data.reason.clone()).await?;
|
||||
|
||||
AuditLogEntryAction::BanCreate {
|
||||
user: target.id.to_string(),
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server.id,
|
||||
audit_log_reason.0.or(data.reason),
|
||||
user.id,
|
||||
Some(target.id.to_string()),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(Json(ban.into()))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, User,
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Unban user
|
||||
///
|
||||
/// Remove a user's ban.
|
||||
@@ -15,6 +17,7 @@ use rocket_empty::EmptyResponse;
|
||||
pub async fn unban(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
server: Reference<'_>,
|
||||
target: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -25,5 +28,13 @@ pub async fn unban(
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::BanMembers)?;
|
||||
|
||||
let ban = target.as_ban(db, &server.id).await?;
|
||||
db.delete_ban(&ban.id).await.map(|_| EmptyResponse)
|
||||
db.delete_ban(&ban.id).await?;
|
||||
|
||||
AuditLogEntryAction::BanDelete {
|
||||
user: target.id.to_string(),
|
||||
}
|
||||
.insert(db, server.id, reason, user.id, Some(target.id.to_string()))
|
||||
.await;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use revolt_database::util::permissions::DatabasePermissionQuery;
|
||||
use revolt_database::AuditLogEntryAction;
|
||||
use revolt_database::{util::reference::Reference, Channel, Database, User};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
@@ -8,6 +9,8 @@ use rocket::serde::json::Json;
|
||||
use rocket::State;
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Create Channel
|
||||
///
|
||||
/// Create a new Text or Voice channel.
|
||||
@@ -16,6 +19,7 @@ use validator::Validate;
|
||||
pub async fn create_server_channel(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
server: Reference<'_>,
|
||||
data: Json<v0::DataCreateServerChannel>,
|
||||
) -> Result<Json<v0::Channel>> {
|
||||
@@ -32,8 +36,16 @@ pub async fn create_server_channel(
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageChannel)?;
|
||||
|
||||
Channel::create_server_channel(db, &mut server, data, true)
|
||||
.await
|
||||
.map(|channel| channel.into())
|
||||
.map(Json)
|
||||
let channel_name = data.name.clone();
|
||||
|
||||
let channel = Channel::create_server_channel(db, &mut server, data, true).await?;
|
||||
|
||||
AuditLogEntryAction::ChannelCreate {
|
||||
channel: channel.id().to_string(),
|
||||
name: channel_name,
|
||||
}
|
||||
.insert(db, server.id, reason, user.id, None)
|
||||
.await;
|
||||
|
||||
Ok(Json(channel.into()))
|
||||
}
|
||||
|
||||
@@ -11,15 +11,19 @@ use revolt_database::{
|
||||
set_user_moved_from_voice, set_user_moved_to_voice, sync_user_voice_permissions,
|
||||
UserVoiceChannel, VoiceClient,
|
||||
},
|
||||
Database, File, PartialMember, User,
|
||||
AuditLogEntryAction, Database, FieldsMember, File, PartialMember, User,
|
||||
};
|
||||
use revolt_models::v0::{self, FieldsMember};
|
||||
use revolt_models::v0;
|
||||
|
||||
use revolt_permissions::{calculate_channel_permissions, calculate_server_permissions, ChannelPermission, UserPermission};
|
||||
use revolt_permissions::{
|
||||
calculate_channel_permissions, calculate_server_permissions, ChannelPermission, UserPermission,
|
||||
};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{form::validate::Contains, serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Edit Member
|
||||
///
|
||||
/// Edit a member by their id.
|
||||
@@ -29,6 +33,7 @@ pub async fn edit(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
server_id: Reference<'_>,
|
||||
member_id: Reference<'_>,
|
||||
data: Json<v0::DataMemberEdit>,
|
||||
@@ -70,7 +75,7 @@ pub async fn edit(
|
||||
} else if data.remove.contains(&v0::FieldsMember::Avatar) {
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::RemoveAvatars)?;
|
||||
} else {
|
||||
return Err(create_error!(InvalidOperation))
|
||||
return Err(create_error!(InvalidOperation));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,11 +105,11 @@ pub async fn edit(
|
||||
permissions.throw_if_lacking_channel_permission(ChannelPermission::DeafenMembers)?;
|
||||
}
|
||||
|
||||
if data.voice_channel.is_some() && data.remove.contains(&FieldsMember::VoiceChannel) {
|
||||
if data.voice_channel.is_some() && data.remove.contains(&v0::FieldsMember::VoiceChannel) {
|
||||
return Err(create_error!(InvalidOperation));
|
||||
}
|
||||
|
||||
if data.voice_channel.is_some() || data.remove.contains(&FieldsMember::VoiceChannel) {
|
||||
if data.voice_channel.is_some() || data.remove.contains(&v0::FieldsMember::VoiceChannel) {
|
||||
if !voice_client.is_enabled() {
|
||||
return Err(create_error!(LiveKitUnavailable));
|
||||
};
|
||||
@@ -126,7 +131,8 @@ pub async fn edit(
|
||||
Err(create_error!(UnknownChannel))?
|
||||
}
|
||||
|
||||
let channel_permissions = calculate_channel_permissions(&mut query.clone().channel(&channel)).await;
|
||||
let channel_permissions =
|
||||
calculate_channel_permissions(&mut query.clone().channel(&channel)).await;
|
||||
channel_permissions.throw_if_lacking_channel_permission(ChannelPermission::Connect)?;
|
||||
|
||||
if get_user_voice_channel_in_server(&target_user.id, &server.id)
|
||||
@@ -202,9 +208,28 @@ pub async fn edit(
|
||||
partial.avatar = Some(File::use_user_avatar(db, &avatar, &user.id, &user.id).await?);
|
||||
}
|
||||
|
||||
member
|
||||
.update(db, partial, remove.clone().into_iter().map(Into::into).collect())
|
||||
.await?;
|
||||
let remove = remove
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<FieldsMember>>();
|
||||
|
||||
let before = member.generate_diff(&partial, &remove);
|
||||
|
||||
member.update(db, partial.clone(), remove.clone()).await?;
|
||||
|
||||
AuditLogEntryAction::MemberEdit {
|
||||
user: member.id.user.clone(),
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server.id.clone(),
|
||||
reason,
|
||||
user.id.clone(),
|
||||
Some(member.id.user.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Some(new_voice_channel) = new_voice_channel {
|
||||
if let Some(channel) = get_user_voice_channel_in_server(&target_user.id, &server.id).await?
|
||||
@@ -256,7 +281,11 @@ pub async fn edit(
|
||||
.private(target_user.id.clone())
|
||||
.await;
|
||||
};
|
||||
} else if can_publish.is_some() || can_receive.is_some() || remove.contains(FieldsMember::CanPublish) || remove.contains(FieldsMember::CanReceive) {
|
||||
} else if can_publish.is_some()
|
||||
|| can_receive.is_some()
|
||||
|| remove.contains(FieldsMember::CanPublish)
|
||||
|| remove.contains(FieldsMember::CanReceive)
|
||||
{
|
||||
if let Some(channel) = get_user_voice_channel_in_server(&target_user.id, &server.id).await?
|
||||
{
|
||||
let node = get_channel_node(&channel).await?.unwrap();
|
||||
|
||||
@@ -4,13 +4,15 @@ use revolt_database::{
|
||||
get_user_voice_channel_in_server, remove_user_from_voice_channel, UserVoiceChannel,
|
||||
VoiceClient,
|
||||
},
|
||||
Database, RemovalIntention, User,
|
||||
AuditLogEntryAction, Database, RemovalIntention, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Kick Member
|
||||
///
|
||||
/// Removes a member from the server.
|
||||
@@ -20,6 +22,7 @@ pub async fn kick(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
server_id: Reference<'_>,
|
||||
member_id: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
@@ -49,6 +52,18 @@ pub async fn kick(
|
||||
.remove(db, &server, RemovalIntention::Kick, false)
|
||||
.await?;
|
||||
|
||||
AuditLogEntryAction::MemberKick {
|
||||
user: member.id.user.clone(),
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
server.id.clone(),
|
||||
reason,
|
||||
user.id,
|
||||
Some(member.id.user.clone()),
|
||||
)
|
||||
.await;
|
||||
|
||||
if let Some(channel_id) = get_user_voice_channel_in_server(member_id.id, &server.id).await? {
|
||||
remove_user_from_voice_channel(
|
||||
voice_client,
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
use revolt_rocket_okapi::revolt_okapi::openapi3::OpenApi;
|
||||
use rocket::Route;
|
||||
|
||||
mod audit_log_query;
|
||||
mod ban_create;
|
||||
mod ban_list;
|
||||
mod ban_remove;
|
||||
@@ -49,6 +50,7 @@ pub fn routes() -> (Vec<Route>, OpenApi) {
|
||||
permissions_set::set_role_permission,
|
||||
permissions_set_default::set_default_server_permissions,
|
||||
emoji_list::list_emoji,
|
||||
roles_edit_positions::edit_role_ranks
|
||||
roles_edit_positions::edit_role_ranks,
|
||||
audit_log_query::query,
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,13 +1,17 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
Database, User,
|
||||
AuditLogEntryAction, Database, PartialRole, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission, Override};
|
||||
use revolt_permissions::{
|
||||
calculate_server_permissions, ChannelPermission, Override, OverrideField,
|
||||
};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Set Role Permission
|
||||
///
|
||||
/// Sets permissions for the specified role in the server.
|
||||
@@ -17,6 +21,7 @@ pub async fn set_role_permission(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
role_id: String,
|
||||
data: Json<v0::DataSetServerRolePermission>,
|
||||
@@ -42,20 +47,36 @@ pub async fn set_role_permission(
|
||||
}
|
||||
|
||||
// Ensure we have access to grant these permissions forwards
|
||||
let current_value: Override = current_value.into();
|
||||
let current_override: Override = current_value.into();
|
||||
permissions
|
||||
.throw_permission_override(current_value, &data.permissions)
|
||||
.throw_permission_override(current_override, &data.permissions)
|
||||
.await?;
|
||||
|
||||
let override_field: OverrideField = data.permissions.into();
|
||||
|
||||
server
|
||||
.set_role_permission(db, &role_id, data.permissions.into())
|
||||
.set_role_permission(db, &role_id, override_field)
|
||||
.await?;
|
||||
|
||||
AuditLogEntryAction::RoleEdit {
|
||||
role: role_id.clone(),
|
||||
before: PartialRole {
|
||||
permissions: Some(current_value),
|
||||
..Default::default()
|
||||
},
|
||||
after: PartialRole {
|
||||
permissions: Some(override_field),
|
||||
..Default::default()
|
||||
},
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
for channel_id in &server.channels {
|
||||
let channel = Reference::from_unchecked(channel_id).as_channel(db).await?;
|
||||
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), Some(&role_id)).await?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, voice::{sync_voice_permissions, VoiceClient}, Database, PartialServer, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
AuditLogEntryAction, Database, PartialServer, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{
|
||||
@@ -8,6 +10,8 @@ use revolt_permissions::{
|
||||
use revolt_result::Result;
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Set Default Permission
|
||||
///
|
||||
/// Sets permissions for the default role in this server.
|
||||
@@ -17,6 +21,7 @@ pub async fn set_default_server_permissions(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<DataPermissionsValue>,
|
||||
) -> Result<Json<v0::Server>> {
|
||||
@@ -39,22 +44,27 @@ pub async fn set_default_server_permissions(
|
||||
)
|
||||
.await?;
|
||||
|
||||
server
|
||||
.update(
|
||||
db,
|
||||
PartialServer {
|
||||
default_permissions: Some(data.permissions as i64),
|
||||
..Default::default()
|
||||
},
|
||||
vec![],
|
||||
)
|
||||
.await?;
|
||||
let partial = PartialServer {
|
||||
default_permissions: Some(data.permissions as i64),
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let before = server.generate_diff(&partial, &[]);
|
||||
|
||||
server.update(db, partial.clone(), vec![]).await?;
|
||||
|
||||
AuditLogEntryAction::ServerEdit {
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
for channel_id in &server.channels {
|
||||
let channel = Reference::from_unchecked(channel_id).as_channel(db).await?;
|
||||
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), None).await?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use revolt_config::config;
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, Role, User,
|
||||
AuditLogEntryAction, Database, Role, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
@@ -9,6 +9,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Create Role
|
||||
///
|
||||
/// Creates a new server role.
|
||||
@@ -17,6 +19,7 @@ use validator::Validate;
|
||||
pub async fn create(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataCreateRole>,
|
||||
) -> Result<Json<v0::NewRoleResponse>> {
|
||||
@@ -42,6 +45,13 @@ pub async fn create(
|
||||
|
||||
let role = Role::create(db, &server, data.name).await?;
|
||||
|
||||
AuditLogEntryAction::RoleCreate {
|
||||
role: role.id.clone(),
|
||||
name: role.name.clone(),
|
||||
}
|
||||
.insert(db, server.id, reason, user.id, None)
|
||||
.await;
|
||||
|
||||
Ok(Json(v0::NewRoleResponse {
|
||||
id: role.id.clone(),
|
||||
role: role.into(),
|
||||
|
||||
@@ -1,13 +1,15 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
Database, User,
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Delete Role
|
||||
///
|
||||
/// Delete a server role by its id.
|
||||
@@ -16,6 +18,7 @@ use rocket_empty::EmptyResponse;
|
||||
pub async fn delete(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
role_id: String,
|
||||
voice_client: &State<VoiceClient>,
|
||||
@@ -39,6 +42,13 @@ pub async fn delete(
|
||||
|
||||
role.delete(db, &server.id).await?;
|
||||
|
||||
AuditLogEntryAction::RoleDelete {
|
||||
role: role_id.clone(),
|
||||
name: role.name,
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
for channel_id in &server.channels {
|
||||
let channel = Reference::from_unchecked(channel_id).as_channel(db).await?;
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
Database, PartialRole, User
|
||||
AuditLogEntryAction, Database, FieldsRole, PartialRole, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
@@ -9,6 +9,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Edit Role
|
||||
///
|
||||
/// Edit a role by its id.
|
||||
@@ -18,6 +20,7 @@ pub async fn edit(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
role_id: String,
|
||||
data: Json<v0::DataEditRole>,
|
||||
@@ -58,19 +61,30 @@ pub async fn edit(
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
role.update(
|
||||
db,
|
||||
&server.id,
|
||||
partial,
|
||||
remove.into_iter().map(Into::into).collect(),
|
||||
)
|
||||
.await?;
|
||||
let remove = remove
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<FieldsRole>>();
|
||||
|
||||
let before = role.generate_diff(&partial, &remove);
|
||||
|
||||
role.update(db, &server.id, partial.clone(), remove)
|
||||
.await?;
|
||||
|
||||
AuditLogEntryAction::RoleEdit {
|
||||
role: role_id.clone(),
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
for channel_id in &server.channels {
|
||||
let channel = Reference::from_unchecked(channel_id).as_channel(db).await?;
|
||||
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), Some(&role_id)).await?;
|
||||
};
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), Some(&role_id))
|
||||
.await?;
|
||||
}
|
||||
|
||||
Ok(Json(role.into()))
|
||||
} else {
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference}, voice::{sync_voice_permissions, VoiceClient}, Database, User
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
voice::{sync_voice_permissions, VoiceClient},
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, State};
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Edits server roles ranks
|
||||
///
|
||||
/// Edit's server role's ranks.
|
||||
@@ -15,6 +19,7 @@ pub async fn edit_role_ranks(
|
||||
db: &State<Database>,
|
||||
voice_client: &State<VoiceClient>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataEditRoleRanks>,
|
||||
) -> Result<Json<v0::Server>> {
|
||||
@@ -68,13 +73,20 @@ pub async fn edit_role_ranks(
|
||||
}
|
||||
}
|
||||
|
||||
server.set_role_ordering(db, new_order).await?;
|
||||
server.set_role_ordering(db, new_order.clone()).await?;
|
||||
|
||||
AuditLogEntryAction::RolesReorder {
|
||||
before: existing_order,
|
||||
after: new_order,
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
for channel_id in &server.channels {
|
||||
let channel = Reference::from_unchecked(channel_id).as_channel(db).await?;
|
||||
|
||||
sync_voice_permissions(db, voice_client, &channel, Some(&server), None).await?;
|
||||
};
|
||||
}
|
||||
|
||||
Ok(Json(server.into()))
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use std::collections::HashSet;
|
||||
use authifier::models::{totp::Totp, Account, ValidatedTicket};
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, File, PartialServer, User,
|
||||
AuditLogEntryAction, Database, FieldsServer, File, PartialServer, User,
|
||||
};
|
||||
use revolt_models::v0;
|
||||
use revolt_permissions::{calculate_server_permissions, ChannelPermission};
|
||||
@@ -11,6 +11,8 @@ use revolt_result::{create_error, Result};
|
||||
use rocket::{serde::json::Json, Request, State};
|
||||
use validator::Validate;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Edit Server
|
||||
///
|
||||
/// Edit a server by its id.
|
||||
@@ -20,6 +22,7 @@ pub async fn edit(
|
||||
db: &State<Database>,
|
||||
account: Account,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
target: Reference<'_>,
|
||||
data: Json<v0::DataEditServer>,
|
||||
validated_ticket: Option<ValidatedTicket>,
|
||||
@@ -178,9 +181,21 @@ pub async fn edit(
|
||||
partial.owner = Some(server.owner.clone());
|
||||
}
|
||||
|
||||
server
|
||||
.update(db, partial, remove.into_iter().map(Into::into).collect())
|
||||
.await?;
|
||||
let remove = remove
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect::<Vec<FieldsServer>>();
|
||||
|
||||
let before = server.generate_diff(&partial, &remove);
|
||||
|
||||
server.update(db, partial.clone(), remove).await?;
|
||||
|
||||
AuditLogEntryAction::ServerEdit {
|
||||
before,
|
||||
after: partial,
|
||||
}
|
||||
.insert(db, server.id.clone(), reason, user.id, None)
|
||||
.await;
|
||||
|
||||
Ok(Json(server.into()))
|
||||
}
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
use revolt_database::{
|
||||
util::{permissions::DatabasePermissionQuery, reference::Reference},
|
||||
Database, User,
|
||||
AuditLogEntryAction, Database, User,
|
||||
};
|
||||
use revolt_permissions::{calculate_channel_permissions, ChannelPermission};
|
||||
use revolt_result::Result;
|
||||
use rocket::State;
|
||||
use rocket_empty::EmptyResponse;
|
||||
|
||||
use crate::util::audit_log_reason::AuditLogReason;
|
||||
|
||||
/// # Deletes a webhook
|
||||
///
|
||||
/// Deletes a webhook
|
||||
@@ -15,6 +17,7 @@ use rocket_empty::EmptyResponse;
|
||||
pub async fn webhook_delete(
|
||||
db: &State<Database>,
|
||||
user: User,
|
||||
reason: AuditLogReason,
|
||||
webhook_id: Reference<'_>,
|
||||
) -> Result<EmptyResponse> {
|
||||
let webhook = webhook_id.as_webhook(db).await?;
|
||||
@@ -25,5 +28,24 @@ pub async fn webhook_delete(
|
||||
.await
|
||||
.throw_if_lacking_channel_permission(ChannelPermission::ManageWebhooks)?;
|
||||
|
||||
webhook.delete(db).await.map(|_| EmptyResponse)
|
||||
webhook.delete(db).await?;
|
||||
|
||||
AuditLogEntryAction::WebhookDelete {
|
||||
webhook: webhook.id,
|
||||
name: webhook.name,
|
||||
channel: webhook.channel_id,
|
||||
}
|
||||
.insert(
|
||||
db,
|
||||
channel
|
||||
.server()
|
||||
.expect("Webhook created on non server channel")
|
||||
.to_string(),
|
||||
reason,
|
||||
user.id,
|
||||
Some(webhook.creator_id),
|
||||
)
|
||||
.await;
|
||||
|
||||
Ok(EmptyResponse)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user