From e8de96b2d024f5777e54d4a33055404f715fc1f1 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Mon, 4 Aug 2025 22:51:05 +0200 Subject: [PATCH 01/12] feat: added audit logs table to the database --- .../2025-08-04-195527_add_audit_log/down.sql | 2 ++ .../2025-08-04-195527_add_audit_log/up.sql | 14 +++++++++++ src/schema.rs | 25 +++++++++++++++++++ 3 files changed, 41 insertions(+) create mode 100644 migrations/2025-08-04-195527_add_audit_log/down.sql create mode 100644 migrations/2025-08-04-195527_add_audit_log/up.sql diff --git a/migrations/2025-08-04-195527_add_audit_log/down.sql b/migrations/2025-08-04-195527_add_audit_log/down.sql new file mode 100644 index 0000000..f7c5a37 --- /dev/null +++ b/migrations/2025-08-04-195527_add_audit_log/down.sql @@ -0,0 +1,2 @@ +-- This file should undo anything in `up.sql` +DROP TABLE audit_logs; diff --git a/migrations/2025-08-04-195527_add_audit_log/up.sql b/migrations/2025-08-04-195527_add_audit_log/up.sql new file mode 100644 index 0000000..dbd923d --- /dev/null +++ b/migrations/2025-08-04-195527_add_audit_log/up.sql @@ -0,0 +1,14 @@ +-- Your SQL goes here +CREATE TABLE audit_logs ( + uuid UUID PRIMARY KEY NOT NULL, + guild_uuid UUID NOT NULL, + action_id INT2 NOT NULL, + by_uuid UUID NOT NULL REFERENCES guild_members(uuid), + channel_uuid UUID REFERENCES channels(uuid) DEFAULT NULL, + user_uuid UUID REFERENCES users(uuid) DEFAULT NULL, + message_uuid UUID REFERENCES messages(uuid) DEFAULT NULL, + role_uuid UUID REFERENCES roles(uuid) DEFAULT NULL, + audit_message VARCHAR(200) DEFAULT NULL, + changed_from VARCHAR(200) DEFAULT NULL, + changed_to VARCHAR(200) DEFAULT NULL +); diff --git a/src/schema.rs b/src/schema.rs index 88f6155..b0e27b8 100644 --- a/src/schema.rs +++ b/src/schema.rs @@ -11,6 +11,25 @@ diesel::table! { } } +diesel::table! { + audit_logs (uuid) { + uuid -> Uuid, + guild_uuid -> Uuid, + action_id -> Int2, + by_uuid -> Uuid, + channel_uuid -> Nullable, + user_uuid -> Nullable, + message_uuid -> Nullable, + role_uuid -> Nullable, + #[max_length = 200] + audit_message -> Nullable, + #[max_length = 200] + changed_from -> Nullable, + #[max_length = 200] + changed_to -> Nullable, + } +} + diesel::table! { channel_permissions (channel_uuid, role_uuid) { channel_uuid -> Uuid, @@ -163,6 +182,11 @@ diesel::table! { diesel::joinable!(access_tokens -> refresh_tokens (refresh_token)); diesel::joinable!(access_tokens -> users (uuid)); +diesel::joinable!(audit_logs -> channels (channel_uuid)); +diesel::joinable!(audit_logs -> guild_members (by_uuid)); +diesel::joinable!(audit_logs -> messages (message_uuid)); +diesel::joinable!(audit_logs -> roles (role_uuid)); +diesel::joinable!(audit_logs -> users (user_uuid)); diesel::joinable!(channel_permissions -> channels (channel_uuid)); diesel::joinable!(channel_permissions -> roles (role_uuid)); diesel::joinable!(channels -> guilds (guild_uuid)); @@ -182,6 +206,7 @@ diesel::joinable!(roles -> guilds (guild_uuid)); diesel::allow_tables_to_appear_in_same_query!( access_tokens, + audit_logs, channel_permissions, channels, friend_requests, From b49e5036be10ee64da8596ac1b0d6188c41ac6bf Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 09:58:37 +0200 Subject: [PATCH 02/12] feat: started on auditlog object --- src/objects/auditlog.rs | 63 +++++++++++++++++++++++++++++++++++++++++ src/objects/mod.rs | 2 ++ 2 files changed, 65 insertions(+) create mode 100644 src/objects/auditlog.rs diff --git a/src/objects/auditlog.rs b/src/objects/auditlog.rs new file mode 100644 index 0000000..d55fe06 --- /dev/null +++ b/src/objects/auditlog.rs @@ -0,0 +1,63 @@ +use uuid::Uuid; +use diesel::{insert_into, Insertable, Queryable, Selectable, SelectableHelper}; +use serde::{Deserialize, Serialize}; +use crate::{error::Error, schema::audit_logs, Conn}; +use diesel_async::RunQueryDsl; + + +#[derive(Insertable, Selectable, Queryable, Serialize, Deserialize, Clone)] +#[diesel(table_name = audit_logs)] +#[diesel(check_for_backend(diesel::pg::Pg))] +pub struct AuditLog { + + pub uuid: Uuid, + pub guild_uuid: Uuid, + pub action_id: i16, + pub by_uuid: Uuid, + pub channel_uuid: Option, + pub user_uuid: Option, + pub message_uuid: Option, + pub role_uuid: Option, + pub audit_message: Option, + pub changed_from: Option, + pub changed_to: Option, +} + + +impl AuditLog { + #[allow(clippy::new_ret_no_self)] + pub async fn new( + conn: &mut Conn, + guild_uuid: Uuid, + action_id: i16, + by_uuid: Uuid, + channel_uuid: Option, + user_uuid: Option, + message_uuid: Option, + role_uuid: Option, + audit_message: Option, + changed_from: Option, + changed_to: Option, + ) ->Result<(), Error> { + let audit_log = AuditLog { + uuid: Uuid::now_v7(), + guild_uuid, + action_id, + by_uuid, + channel_uuid, + user_uuid, + message_uuid, + role_uuid, + audit_message, + changed_from, + changed_to + }; + + insert_into(audit_logs::table) + .values(audit_log.clone()) + .execute(conn) + .await?; + + Ok(()) + } +} diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 3bcce9c..bedf442 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -19,6 +19,7 @@ mod message; mod password_reset_token; mod role; mod user; +mod auditlog; pub use bans::GuildBan; pub use channel::Channel; @@ -34,6 +35,7 @@ pub use password_reset_token::PasswordResetToken; pub use role::Permissions; pub use role::Role; pub use user::User; +pub use auditlog::AuditLog; use crate::error::Error; From e1d3a736874bc6e25a94c4214031b80a7f866e55 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 10:52:22 +0200 Subject: [PATCH 03/12] feat: finished auditlog object and added endpoint to get all auditlogs --- src/api/v1/guilds/uuid/auditlogs.rs | 37 ++++++++++++++++++++ src/api/v1/guilds/uuid/mod.rs | 3 ++ src/objects/auditlog.rs | 53 +++++++++++++++++++++++++++-- 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 src/api/v1/guilds/uuid/auditlogs.rs diff --git a/src/api/v1/guilds/uuid/auditlogs.rs b/src/api/v1/guilds/uuid/auditlogs.rs new file mode 100644 index 0000000..c8033e3 --- /dev/null +++ b/src/api/v1/guilds/uuid/auditlogs.rs @@ -0,0 +1,37 @@ +use std::sync::Arc; + +use ::uuid::Uuid; +use axum::{ + Extension, Json, + extract::{Path, Query, State}, + http::StatusCode, + response::IntoResponse, +}; + +use crate::{ + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, Member, PaginationRequest, Permissions}, utils::global_checks, AppState +}; + +pub async fn get( + State(app_state): State>, + Path(guild_uuid): Path, + Query(pagination): Query, + Extension(CurrentUser(uuid)): Extension>, +) -> Result { + let mut conn = app_state.pool.get().await?; + + global_checks(&mut conn, &app_state.config, uuid).await?; + + let caller = Member::check_membership(&mut conn, uuid, guild_uuid).await?; + caller.check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageGuild).await?; + + + let logs = AuditLog::fetch_page( + &mut conn, + guild_uuid, + pagination, + ) + .await?; + + Ok((StatusCode::OK, Json(logs))) +} diff --git a/src/api/v1/guilds/uuid/mod.rs b/src/api/v1/guilds/uuid/mod.rs index 53f469b..81d749a 100644 --- a/src/api/v1/guilds/uuid/mod.rs +++ b/src/api/v1/guilds/uuid/mod.rs @@ -17,6 +17,7 @@ mod channels; mod invites; mod members; mod roles; +mod auditlogs; use crate::{ AppState, @@ -46,6 +47,8 @@ pub fn router() -> Router> { // Bans .route("/bans", get(bans::get)) .route("/bans/{uuid}", delete(bans::unban)) + // Audit Logs + .route("/auditlogs", get(auditlogs::get)) } /// `GET /api/v1/guilds/{uuid}` DESCRIPTION diff --git a/src/objects/auditlog.rs b/src/objects/auditlog.rs index d55fe06..3b5ff6e 100644 --- a/src/objects/auditlog.rs +++ b/src/objects/auditlog.rs @@ -1,7 +1,7 @@ use uuid::Uuid; -use diesel::{insert_into, Insertable, Queryable, Selectable, SelectableHelper}; +use diesel::{insert_into, Insertable, QueryDsl, Queryable, Selectable, SelectableHelper, ExpressionMethods}; use serde::{Deserialize, Serialize}; -use crate::{error::Error, schema::audit_logs, Conn}; +use crate::{error::Error, objects::{load_or_empty, Pagination, PaginationRequest}, schema::audit_logs, Conn}; use diesel_async::RunQueryDsl; @@ -25,6 +25,55 @@ pub struct AuditLog { impl AuditLog { + pub async fn count(conn: &mut Conn, guild_uuid: Uuid) -> Result { + use audit_logs::dsl; + let count: i64 = dsl::audit_logs + .filter(dsl::guild_uuid.eq(guild_uuid)) + .count() + .get_result(conn) + .await?; + + Ok(count) + } + pub async fn fetch_page( + conn: &mut Conn, + guild_uuid: Uuid, + pagination: PaginationRequest, + ) -> Result, Error> { + + // TODO: Maybe add cache, but I do not know how + let per_page = pagination.per_page.unwrap_or(20); + let offset = (pagination.page - 1) * per_page; + + if !(10..=100).contains(&per_page) { + return Err(Error::BadRequest( + "Invalid amount per page requested".to_string(), + )); + } + + use audit_logs::dsl; + let logs: Vec = load_or_empty( + dsl::audit_logs + .filter(dsl::guild_uuid.eq(guild_uuid)) + .limit(per_page.into()) + .offset(offset as i64) + .select(AuditLog::as_select()) + .load(conn) + .await + )?; + + let pages = (AuditLog::count(conn, guild_uuid).await? as f32 / per_page as f32).ceil(); + + let paginated_logs = Pagination:: { + objects: logs.clone(), + amount: logs.len() as i32, + pages: pages as i32, + page: pagination.page, + }; + + Ok(paginated_logs) + } + #[allow(clippy::new_ret_no_self)] pub async fn new( conn: &mut Conn, From 2b9a44c4f0a8c703872bd6983809889a22723fae Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 10:54:24 +0200 Subject: [PATCH 04/12] style: cargo clippy --fix && cargo fmt --- src/api/v1/guilds/uuid/auditlogs.rs | 18 +++++------ src/api/v1/guilds/uuid/mod.rs | 2 +- src/objects/auditlog.rs | 49 +++++++++++++++-------------- src/objects/mod.rs | 4 +-- 4 files changed, 38 insertions(+), 35 deletions(-) diff --git a/src/api/v1/guilds/uuid/auditlogs.rs b/src/api/v1/guilds/uuid/auditlogs.rs index c8033e3..329e0c5 100644 --- a/src/api/v1/guilds/uuid/auditlogs.rs +++ b/src/api/v1/guilds/uuid/auditlogs.rs @@ -9,7 +9,11 @@ use axum::{ }; use crate::{ - api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, Member, PaginationRequest, Permissions}, utils::global_checks, AppState + AppState, + api::v1::auth::CurrentUser, + error::Error, + objects::{AuditLog, Member, PaginationRequest, Permissions}, + utils::global_checks, }; pub async fn get( @@ -23,15 +27,11 @@ pub async fn get( global_checks(&mut conn, &app_state.config, uuid).await?; let caller = Member::check_membership(&mut conn, uuid, guild_uuid).await?; - caller.check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageGuild).await?; - + caller + .check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageGuild) + .await?; - let logs = AuditLog::fetch_page( - &mut conn, - guild_uuid, - pagination, - ) - .await?; + let logs = AuditLog::fetch_page(&mut conn, guild_uuid, pagination).await?; Ok((StatusCode::OK, Json(logs))) } diff --git a/src/api/v1/guilds/uuid/mod.rs b/src/api/v1/guilds/uuid/mod.rs index 81d749a..6e57704 100644 --- a/src/api/v1/guilds/uuid/mod.rs +++ b/src/api/v1/guilds/uuid/mod.rs @@ -12,12 +12,12 @@ use axum::{ use bytes::Bytes; use uuid::Uuid; +mod auditlogs; mod bans; mod channels; mod invites; mod members; mod roles; -mod auditlogs; use crate::{ AppState, diff --git a/src/objects/auditlog.rs b/src/objects/auditlog.rs index 3b5ff6e..b5e58e9 100644 --- a/src/objects/auditlog.rs +++ b/src/objects/auditlog.rs @@ -1,29 +1,33 @@ -use uuid::Uuid; -use diesel::{insert_into, Insertable, QueryDsl, Queryable, Selectable, SelectableHelper, ExpressionMethods}; -use serde::{Deserialize, Serialize}; -use crate::{error::Error, objects::{load_or_empty, Pagination, PaginationRequest}, schema::audit_logs, Conn}; +use crate::{ + Conn, + error::Error, + objects::{Pagination, PaginationRequest, load_or_empty}, + schema::audit_logs, +}; +use diesel::{ + ExpressionMethods, Insertable, QueryDsl, Queryable, Selectable, SelectableHelper, insert_into, +}; use diesel_async::RunQueryDsl; - +use serde::{Deserialize, Serialize}; +use uuid::Uuid; #[derive(Insertable, Selectable, Queryable, Serialize, Deserialize, Clone)] #[diesel(table_name = audit_logs)] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct AuditLog { - - pub uuid: Uuid, - pub guild_uuid: Uuid, - pub action_id: i16, - pub by_uuid: Uuid, - pub channel_uuid: Option, - pub user_uuid: Option, - pub message_uuid: Option, - pub role_uuid: Option, - pub audit_message: Option, - pub changed_from: Option, - pub changed_to: Option, + pub uuid: Uuid, + pub guild_uuid: Uuid, + pub action_id: i16, + pub by_uuid: Uuid, + pub channel_uuid: Option, + pub user_uuid: Option, + pub message_uuid: Option, + pub role_uuid: Option, + pub audit_message: Option, + pub changed_from: Option, + pub changed_to: Option, } - impl AuditLog { pub async fn count(conn: &mut Conn, guild_uuid: Uuid) -> Result { use audit_logs::dsl; @@ -40,7 +44,6 @@ impl AuditLog { guild_uuid: Uuid, pagination: PaginationRequest, ) -> Result, Error> { - // TODO: Maybe add cache, but I do not know how let per_page = pagination.per_page.unwrap_or(20); let offset = (pagination.page - 1) * per_page; @@ -59,7 +62,7 @@ impl AuditLog { .offset(offset as i64) .select(AuditLog::as_select()) .load(conn) - .await + .await, )?; let pages = (AuditLog::count(conn, guild_uuid).await? as f32 / per_page as f32).ceil(); @@ -70,7 +73,7 @@ impl AuditLog { pages: pages as i32, page: pagination.page, }; - + Ok(paginated_logs) } @@ -87,7 +90,7 @@ impl AuditLog { audit_message: Option, changed_from: Option, changed_to: Option, - ) ->Result<(), Error> { + ) -> Result<(), Error> { let audit_log = AuditLog { uuid: Uuid::now_v7(), guild_uuid, @@ -99,7 +102,7 @@ impl AuditLog { role_uuid, audit_message, changed_from, - changed_to + changed_to, }; insert_into(audit_logs::table) diff --git a/src/objects/mod.rs b/src/objects/mod.rs index 3bef473..d82755e 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -7,6 +7,7 @@ use log::debug; use serde::{Deserialize, Serialize}; use uuid::Uuid; +mod auditlog; mod bans; mod channel; mod email_token; @@ -19,8 +20,8 @@ mod message; mod password_reset_token; mod role; mod user; -mod auditlog; +pub use auditlog::AuditLog; pub use bans::GuildBan; pub use channel::Channel; pub use email_token::EmailToken; @@ -35,7 +36,6 @@ pub use password_reset_token::PasswordResetToken; pub use role::Permissions; pub use role::Role; pub use user::User; -pub use auditlog::AuditLog; use crate::error::Error; From 95ef27c32db395adba854fcb290b0e405d061192 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:00:47 +0200 Subject: [PATCH 05/12] fix: spitt the new function, and added an AuditLogId Enum --- src/objects/auditlog.rs | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/objects/auditlog.rs b/src/objects/auditlog.rs index b5e58e9..d749a55 100644 --- a/src/objects/auditlog.rs +++ b/src/objects/auditlog.rs @@ -11,6 +11,29 @@ use diesel_async::RunQueryDsl; use serde::{Deserialize, Serialize}; use uuid::Uuid; +pub enum AuditLogId { + MessageDelete = 100, + MessageEdit = 101, + + ChannelCreate = 200, + ChannelDelete = 201, + ChannelUpdateName = 202, + ChannelUpdateDescripiton = 203, + + RoleCreate = 300, + RoleDelete = 301, + RoleUpdateName = 302, + RoleUpdatePermission = 303, + InviteCreate = 304, + InviteDelete = 305, + + MemberKick = 400, + MemberBan = 401, + MemberUnban = 402, + MemberUpdateNickname = 403, + MemberUpdateRoles = 404, +} + #[derive(Insertable, Selectable, Queryable, Serialize, Deserialize, Clone)] #[diesel(table_name = audit_logs)] #[diesel(check_for_backend(diesel::pg::Pg))] @@ -77,9 +100,7 @@ impl AuditLog { Ok(paginated_logs) } - #[allow(clippy::new_ret_no_self)] pub async fn new( - conn: &mut Conn, guild_uuid: Uuid, action_id: i16, by_uuid: Uuid, @@ -90,8 +111,8 @@ impl AuditLog { audit_message: Option, changed_from: Option, changed_to: Option, - ) -> Result<(), Error> { - let audit_log = AuditLog { + ) -> AuditLog{ + AuditLog { uuid: Uuid::now_v7(), guild_uuid, action_id, @@ -103,10 +124,12 @@ impl AuditLog { audit_message, changed_from, changed_to, - }; + } + } + pub async fn push(self, conn: &mut Conn) -> Result<(), Error>{ insert_into(audit_logs::table) - .values(audit_log.clone()) + .values(self.clone()) .execute(conn) .await?; From 9d6ec5286b1a67ca68320878b0ddab6b7145544a Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:01:17 +0200 Subject: [PATCH 06/12] feat: added audit log to channel delete --- src/api/v1/channels/uuid/mod.rs | 8 +++----- src/objects/channel.rs | 2 +- src/objects/mod.rs | 1 + 3 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/api/v1/channels/uuid/mod.rs b/src/api/v1/channels/uuid/mod.rs index f5566b3..6335bb1 100644 --- a/src/api/v1/channels/uuid/mod.rs +++ b/src/api/v1/channels/uuid/mod.rs @@ -6,11 +6,7 @@ pub mod socket; use std::sync::Arc; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{Channel, Member, Permissions}, - utils::global_checks, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, Channel, Member, Permissions}, utils::global_checks, AppState }; use axum::{ Extension, Json, @@ -55,7 +51,9 @@ pub async fn delete( .check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageChannel) .await?; + let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelDelete as i16, member.uuid, None, None, None, None, Some(channel.name.clone()), None, None).await; channel.delete(&mut conn, &app_state.cache_pool).await?; + log_entrie.push(&mut conn).await?; Ok(StatusCode::OK) } diff --git a/src/objects/channel.rs b/src/objects/channel.rs index 03a2cf6..48be7c8 100644 --- a/src/objects/channel.rs +++ b/src/objects/channel.rs @@ -52,7 +52,7 @@ impl ChannelBuilder { pub struct Channel { pub uuid: Uuid, pub guild_uuid: Uuid, - name: String, + pub name: String, description: Option, pub is_above: Option, pub permissions: Vec, diff --git a/src/objects/mod.rs b/src/objects/mod.rs index d82755e..29c96b3 100644 --- a/src/objects/mod.rs +++ b/src/objects/mod.rs @@ -22,6 +22,7 @@ mod role; mod user; pub use auditlog::AuditLog; +pub use auditlog::AuditLogId; pub use bans::GuildBan; pub use channel::Channel; pub use email_token::EmailToken; From d84b7cf126c49cd2444315b666bc3242b2c31244 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:07:17 +0200 Subject: [PATCH 07/12] feat: added audit log to channel create --- src/api/v1/guilds/uuid/channels.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/api/v1/guilds/uuid/channels.rs b/src/api/v1/guilds/uuid/channels.rs index 1cd7f78..ffb8f7e 100644 --- a/src/api/v1/guilds/uuid/channels.rs +++ b/src/api/v1/guilds/uuid/channels.rs @@ -10,11 +10,7 @@ use axum::{ use serde::Deserialize; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{Channel, Member, Permissions}, - utils::{CacheFns, global_checks, order_by_is_above}, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, Channel, Member, Permissions}, utils::{global_checks, order_by_is_above, CacheFns}, AppState }; #[derive(Deserialize)] @@ -83,5 +79,7 @@ pub async fn create( ) .await?; + AuditLog::new(guild_uuid, AuditLogId::ChannelCreate as i16, member.uuid, Some(channel.uuid), None, None, None, Some(channel.name.clone()), None, None).await.push(&mut conn).await?; + Ok((StatusCode::OK, Json(channel))) } From 362e4bc2e81bd9686053bd6103c79f2a27069161 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:21:48 +0200 Subject: [PATCH 08/12] feat: added audit log on channel update --- src/api/v1/channels/uuid/mod.rs | 4 ++++ src/objects/channel.rs | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/api/v1/channels/uuid/mod.rs b/src/api/v1/channels/uuid/mod.rs index 6335bb1..dde9479 100644 --- a/src/api/v1/channels/uuid/mod.rs +++ b/src/api/v1/channels/uuid/mod.rs @@ -115,12 +115,15 @@ pub async fn patch( .await?; if let Some(new_name) = &new_info.name { + let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateName as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.name.clone()), Some(new_name.clone())).await; channel .set_name(&mut conn, &app_state.cache_pool, new_name.to_string()) .await?; + log_entrie.push(&mut conn).await?; } if let Some(new_description) = &new_info.description { + let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateDescripiton as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.description.clone().unwrap_or("".to_string())), Some(new_description.clone())).await; channel .set_description( &mut conn, @@ -128,6 +131,7 @@ pub async fn patch( new_description.to_string(), ) .await?; + log_entrie.push(&mut conn).await?; } if let Some(new_is_above) = &new_info.is_above { diff --git a/src/objects/channel.rs b/src/objects/channel.rs index 48be7c8..dacc562 100644 --- a/src/objects/channel.rs +++ b/src/objects/channel.rs @@ -53,7 +53,7 @@ pub struct Channel { pub uuid: Uuid, pub guild_uuid: Uuid, pub name: String, - description: Option, + pub description: Option, pub is_above: Option, pub permissions: Vec, } From 55ef6ddde295ba3251394dc51df76425deca085d Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:30:39 +0200 Subject: [PATCH 09/12] feat: audit log on role creation --- src/api/v1/guilds/uuid/roles/mod.rs | 9 ++++----- src/objects/role.rs | 4 ++-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/api/v1/guilds/uuid/roles/mod.rs b/src/api/v1/guilds/uuid/roles/mod.rs index d3660ce..6b8ac58 100644 --- a/src/api/v1/guilds/uuid/roles/mod.rs +++ b/src/api/v1/guilds/uuid/roles/mod.rs @@ -10,11 +10,7 @@ use axum::{ use serde::Deserialize; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{Member, Permissions, Role}, - utils::{CacheFns, global_checks, order_by_is_above}, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, Member, Permissions, Role}, utils::{global_checks, order_by_is_above, CacheFns}, AppState }; pub mod uuid; @@ -71,7 +67,10 @@ pub async fn create( .check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageRole) .await?; + // TODO: roles permission let role = Role::new(&mut conn, guild_uuid, role_info.name.clone()).await?; + AuditLog::new(guild_uuid, AuditLogId::RoleCreate as i16, member.uuid, None, None, None, Some(role.uuid), Some(role_info.name.clone()) , None, None).await.push(&mut conn).await?; + Ok((StatusCode::OK, Json(role)).into_response()) } diff --git a/src/objects/role.rs b/src/objects/role.rs index cc71fb2..88749a8 100644 --- a/src/objects/role.rs +++ b/src/objects/role.rs @@ -21,9 +21,9 @@ use super::{HasIsAbove, HasUuid, load_or_empty, member::MemberBuilder}; #[diesel(primary_key(uuid))] #[diesel(check_for_backend(diesel::pg::Pg))] pub struct Role { - uuid: Uuid, + pub uuid: Uuid, guild_uuid: Uuid, - name: String, + pub name: String, color: i32, is_above: Option, pub permissions: i64, From dee248e02d852f60e198c580c4988c1608d698b4 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:36:27 +0200 Subject: [PATCH 10/12] feat: audid log on invite creation --- src/api/v1/guilds/uuid/invites/mod.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/src/api/v1/guilds/uuid/invites/mod.rs b/src/api/v1/guilds/uuid/invites/mod.rs index fa06f44..d5dda8a 100644 --- a/src/api/v1/guilds/uuid/invites/mod.rs +++ b/src/api/v1/guilds/uuid/invites/mod.rs @@ -10,11 +10,7 @@ use serde::Deserialize; use uuid::Uuid; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{Guild, Member, Permissions}, - utils::global_checks, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, Guild, Member, Permissions}, utils::global_checks, AppState }; #[derive(Deserialize)] @@ -62,5 +58,7 @@ pub async fn create( .create_invite(&mut conn, uuid, invite_request.custom_id.clone()) .await?; + AuditLog::new(guild_uuid, AuditLogId::InviteCreate as i16, member.uuid, None, None, None, None, Some(invite.id.clone()), None, None).await.push(&mut conn).await?; + Ok((StatusCode::OK, Json(invite))) } From 6afa78c8e84641d5b3fa1eefc19189e0aae6d750 Mon Sep 17 00:00:00 2001 From: BAaboe Date: Tue, 5 Aug 2025 12:46:17 +0200 Subject: [PATCH 11/12] audit log on ban and unban --- src/api/v1/guilds/uuid/bans.rs | 8 +++----- src/api/v1/members/uuid/ban.rs | 8 +++----- 2 files changed, 6 insertions(+), 10 deletions(-) diff --git a/src/api/v1/guilds/uuid/bans.rs b/src/api/v1/guilds/uuid/bans.rs index 2e31a59..490ad43 100644 --- a/src/api/v1/guilds/uuid/bans.rs +++ b/src/api/v1/guilds/uuid/bans.rs @@ -9,11 +9,7 @@ use axum::{ use uuid::Uuid; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{GuildBan, Member, Permissions}, - utils::global_checks, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, GuildBan, Member, Permissions}, utils::global_checks, AppState }; pub async fn get( @@ -51,7 +47,9 @@ pub async fn unban( let ban = GuildBan::fetch_one(&mut conn, guild_uuid, user_uuid).await?; + let log_entrie = AuditLog::new(guild_uuid, AuditLogId::MemberUnban as i16, caller.uuid, None, Some(ban.user_uuid), None, None, None, None, None).await; ban.unban(&mut conn).await?; + log_entrie.push(&mut conn).await?; Ok(StatusCode::OK) } diff --git a/src/api/v1/members/uuid/ban.rs b/src/api/v1/members/uuid/ban.rs index e828e69..18344da 100644 --- a/src/api/v1/members/uuid/ban.rs +++ b/src/api/v1/members/uuid/ban.rs @@ -9,11 +9,7 @@ use axum::{ use serde::Deserialize; use crate::{ - AppState, - api::v1::auth::CurrentUser, - error::Error, - objects::{Member, Permissions}, - utils::global_checks, + api::v1::auth::CurrentUser, error::Error, objects::{AuditLog, AuditLogId, Member, Permissions}, utils::global_checks, AppState }; use uuid::Uuid; @@ -42,7 +38,9 @@ pub async fn post( .check_permission(&mut conn, &app_state.cache_pool, Permissions::BanMember) .await?; + let log_entrie = AuditLog::new(member.guild_uuid, AuditLogId::MemberBan as i16, caller.uuid, None, Some(member.user_uuid), None, None, Some(payload.reason.clone()), None, None).await; member.ban(&mut conn, &payload.reason).await?; + log_entrie.push(&mut conn).await?; Ok(StatusCode::OK) } From e663c1bbae6d44d19519982d6106084412e94f2f Mon Sep 17 00:00:00 2001 From: BAaboe Date: Thu, 7 Aug 2025 23:32:22 +0200 Subject: [PATCH 12/12] style: spelling fix --- src/api/v1/channels/uuid/mod.rs | 12 ++++++------ src/api/v1/guilds/uuid/bans.rs | 4 ++-- src/api/v1/members/uuid/ban.rs | 4 ++-- src/api/v1/members/uuid/mod.rs | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/api/v1/channels/uuid/mod.rs b/src/api/v1/channels/uuid/mod.rs index dde9479..5b84de3 100644 --- a/src/api/v1/channels/uuid/mod.rs +++ b/src/api/v1/channels/uuid/mod.rs @@ -51,9 +51,9 @@ pub async fn delete( .check_permission(&mut conn, &app_state.cache_pool, Permissions::ManageChannel) .await?; - let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelDelete as i16, member.uuid, None, None, None, None, Some(channel.name.clone()), None, None).await; + let log_entry = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelDelete as i16, member.uuid, None, None, None, None, Some(channel.name.clone()), None, None).await; channel.delete(&mut conn, &app_state.cache_pool).await?; - log_entrie.push(&mut conn).await?; + log_entry.push(&mut conn).await?; Ok(StatusCode::OK) } @@ -115,15 +115,15 @@ pub async fn patch( .await?; if let Some(new_name) = &new_info.name { - let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateName as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.name.clone()), Some(new_name.clone())).await; + let log_entry = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateName as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.name.clone()), Some(new_name.clone())).await; channel .set_name(&mut conn, &app_state.cache_pool, new_name.to_string()) .await?; - log_entrie.push(&mut conn).await?; + log_entry.push(&mut conn).await?; } if let Some(new_description) = &new_info.description { - let log_entrie = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateDescripiton as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.description.clone().unwrap_or("".to_string())), Some(new_description.clone())).await; + let log_entry = AuditLog::new(channel.guild_uuid, AuditLogId::ChannelUpdateDescripiton as i16, member.uuid, Some(channel_uuid), None, None, None, None, Some(channel.description.clone().unwrap_or("".to_string())), Some(new_description.clone())).await; channel .set_description( &mut conn, @@ -131,7 +131,7 @@ pub async fn patch( new_description.to_string(), ) .await?; - log_entrie.push(&mut conn).await?; + log_entry.push(&mut conn).await?; } if let Some(new_is_above) = &new_info.is_above { diff --git a/src/api/v1/guilds/uuid/bans.rs b/src/api/v1/guilds/uuid/bans.rs index 490ad43..318d092 100644 --- a/src/api/v1/guilds/uuid/bans.rs +++ b/src/api/v1/guilds/uuid/bans.rs @@ -47,9 +47,9 @@ pub async fn unban( let ban = GuildBan::fetch_one(&mut conn, guild_uuid, user_uuid).await?; - let log_entrie = AuditLog::new(guild_uuid, AuditLogId::MemberUnban as i16, caller.uuid, None, Some(ban.user_uuid), None, None, None, None, None).await; + let log_entry = AuditLog::new(guild_uuid, AuditLogId::MemberUnban as i16, caller.uuid, None, Some(ban.user_uuid), None, None, None, None, None).await; ban.unban(&mut conn).await?; - log_entrie.push(&mut conn).await?; + log_entry.push(&mut conn).await?; Ok(StatusCode::OK) } diff --git a/src/api/v1/members/uuid/ban.rs b/src/api/v1/members/uuid/ban.rs index 18344da..589969d 100644 --- a/src/api/v1/members/uuid/ban.rs +++ b/src/api/v1/members/uuid/ban.rs @@ -38,9 +38,9 @@ pub async fn post( .check_permission(&mut conn, &app_state.cache_pool, Permissions::BanMember) .await?; - let log_entrie = AuditLog::new(member.guild_uuid, AuditLogId::MemberBan as i16, caller.uuid, None, Some(member.user_uuid), None, None, Some(payload.reason.clone()), None, None).await; + let log_entry = AuditLog::new(member.guild_uuid, AuditLogId::MemberBan as i16, caller.uuid, None, Some(member.user_uuid), None, None, Some(payload.reason.clone()), None, None).await; member.ban(&mut conn, &payload.reason).await?; - log_entrie.push(&mut conn).await?; + log_entry.push(&mut conn).await?; Ok(StatusCode::OK) } diff --git a/src/api/v1/members/uuid/mod.rs b/src/api/v1/members/uuid/mod.rs index 5bfd129..715e6e6 100644 --- a/src/api/v1/members/uuid/mod.rs +++ b/src/api/v1/members/uuid/mod.rs @@ -54,9 +54,9 @@ pub async fn delete( Member::fetch_one_with_uuid(&mut conn, &app_state.cache_pool, Some(&me), member_uuid) .await?; - let deleter = Member::check_membership(&mut conn, uuid, member.guild_uuid).await?; + let caller = Member::check_membership(&mut conn, uuid, member.guild_uuid).await?; - deleter + caller .check_permission(&mut conn, &app_state.cache_pool, Permissions::KickMember) .await?;