Skip to content

Commit

Permalink
Start audit logging
Browse files Browse the repository at this point in the history
  • Loading branch information
randomairborne committed Jan 3, 2025
1 parent 0a6b6a7 commit 5b5e3c9
Show file tree
Hide file tree
Showing 7 changed files with 196 additions and 23 deletions.
14 changes: 8 additions & 6 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

13 changes: 13 additions & 0 deletions migrations/20250102220309_Audit_logging_for_XP_change_events.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
-- Add migration script here
CREATE TABLE audit_logs (
guild_id INT8 NOT NULL,
user_id INT8 NOT NULL,
moderator INT8 NOT NULL,
timestamp INT8 NOT NULL,
previous INT8 NOT NULL,
delta INT8 NOT NULL,
reset BOOLEAN NOT NULL,
set BOOLEAN NOT NULL
);

CREATE INDEX ON audit_logs(guild_id);
2 changes: 2 additions & 0 deletions xpd-common/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,7 @@ twilight-gateway = { version = "0.16.0-rc.1", default-features = false }
twilight-cache-inmemory = "0.16.0-rc.1"
twilight-model = "0.16.0-rc.1"

serde = { version = "1", features = ["derive"] }

# internal
simpleinterpolation = { workspace = true }
12 changes: 12 additions & 0 deletions xpd-common/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,18 @@ impl Display for GuildConfig {
}
}

#[derive(Clone, Copy, Debug, serde::Serialize, serde::Deserialize)]
pub struct AuditLogEvent {
pub guild_id: Id<GuildMarker>,
pub user_id: Id<UserMarker>,
pub moderator: Id<UserMarker>,
pub timestamp: i64,
pub previous: i64,
pub delta: i64,
pub reset: bool,
pub set: bool,
}

#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct UserStatus {
pub id: Id<UserMarker>,
Expand Down
82 changes: 76 additions & 6 deletions xpd-database/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ use twilight_model::id::{
Id,
};
use util::{db_to_id, id_to_db};
use xpd_common::{GuildConfig, RoleReward, UserStatus};
use xpd_common::{AuditLogEvent, GuildConfig, RoleReward, UserStatus};
pub async fn guild_rewards<
'a,
D: DerefMut<Target = PgConnection> + Send,
Expand Down Expand Up @@ -173,6 +173,76 @@ pub async fn set_cooldown<
Ok(output)
}

pub async fn add_audit_log_event<
'a,
D: DerefMut<Target = PgConnection> + Send,
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
>(
conn: A,
event: AuditLogEvent,
) -> Result<(), Error> {
let mut conn = conn.acquire().await?;
query!(
"INSERT INTO audit_logs \
(guild_id, user_id, moderator,
timestamp, previous, delta, reset, set)
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
id_to_db(event.guild_id),
id_to_db(event.user_id),
id_to_db(event.moderator),
event.timestamp,
event.previous,
event.delta,
event.reset,
event.set
)
.execute(conn.as_mut())
.await?;
Ok(())
}

pub async fn get_audit_log_events<
'a,
D: DerefMut<Target = PgConnection> + Send,
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
>(
conn: A,
guild_id: Id<GuildMarker>,
actions_on_user: Option<Id<UserMarker>>,
actions_by_moderator: Option<Id<UserMarker>>,
) -> Result<Vec<AuditLogEvent>, Error> {
let mut conn = conn.acquire().await?;
let mut stream = query!(
"SELECT user_id, moderator,
timestamp, previous, delta, reset, set
FROM audit_logs WHERE guild_id = $1",
id_to_db(guild_id)
)
.fetch(conn.as_mut());
let mut logs = Vec::new();
while let Some(row) = stream.next().await.transpose()? {
let user_id = db_to_id(row.user_id);
let moderator = db_to_id(row.moderator);
if actions_by_moderator.is_some_and(|requested_moderator| requested_moderator != moderator)
|| actions_on_user.is_some_and(|requested_user| requested_user != user_id)
{
continue;
}
let log = AuditLogEvent {
guild_id,
user_id,
moderator: db_to_id(row.moderator),
timestamp: row.timestamp,
previous: row.previous,
delta: row.delta,
reset: row.reset,
set: row.set,
};
logs.push(log);
}
Ok(logs)
}

pub async fn get_last_message<
'a,
D: DerefMut<Target = PgConnection> + Send,
Expand Down Expand Up @@ -217,16 +287,16 @@ pub async fn delete_levels_user_guild<
conn: A,
user: Id<UserMarker>,
guild: Id<GuildMarker>,
) -> Result<(), Error> {
) -> Result<i64, Error> {
let mut conn = conn.acquire().await?;
query!(
"DELETE FROM levels WHERE id = $1 AND guild = $2",
let output = query!(
"DELETE FROM levels WHERE id = $1 AND guild = $2 RETURNING xp",
id_to_db(user),
id_to_db(guild)
)
.execute(conn.as_mut())
.fetch_one(conn.as_mut())
.await?;
Ok(())
Ok(output.xp)
}

pub async fn count_with_higher_xp<
Expand Down
15 changes: 13 additions & 2 deletions xpd-slash/src/dispatch.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ use twilight_model::{
},
},
http::interaction::InteractionResponse,
id::{marker::GuildMarker, Id},
id::{
marker::{GuildMarker, InteractionMarker},
Id,
},
};
use xpd_common::MemberDisplayInfo;
use xpd_slash_defs::{
Expand All @@ -22,13 +25,15 @@ use xpd_slash_defs::{
};

use crate::{
experience::XpAuditData,
leaderboard::{process_message_component, process_modal_submit},
Error, SlashState, XpdSlashResponse,
};

#[derive(Clone, Debug)]
pub struct Respondable {
token: String,
id: Id<InteractionMarker>,
}

impl Respondable {
Expand All @@ -44,6 +49,7 @@ pub async fn process(
trace!(?interaction, "got interaction");
let respondable = Respondable {
token: interaction.token.clone(),
id: interaction.id,
};
let Some(data) = interaction.data else {
return Err(Error::NoInteractionData);
Expand Down Expand Up @@ -118,6 +124,7 @@ async fn process_app_cmd(
}
}

#[allow(clippy::too_many_lines)]
async fn process_slash_cmd(
data: CommandData,
guild_id: Option<Id<GuildMarker>>,
Expand Down Expand Up @@ -158,8 +165,12 @@ async fn process_slash_cmd(
}
"xp" => crate::experience::process_xp(
XpCommand::from_interaction(data.into())?,
guild_id.ok_or(Error::NoGuildId)?,
state,
guild_id.ok_or(Error::NoGuildId)?,
XpAuditData {
interaction: respondable.id,
invoker: invoker.id,
},
)
.await
.map(Into::into),
Expand Down
Loading

0 comments on commit 5b5e3c9

Please sign in to comment.