Skip to content

Commit 920c60e

Browse files
Complete fancier audit logging, reimplement ban data deletion
1 parent 99f91c2 commit 920c60e

File tree

8 files changed

+171
-91
lines changed

8 files changed

+171
-91
lines changed

Cargo.lock

Lines changed: 22 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

migrations/20250224222943_audit_log_types.sql

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,10 @@ CREATE TABLE new_audit_logs (
66
timestamp INT8 NOT NULL,
77
previous INT8 NOT NULL,
88
delta INT8 NOT NULL,
9-
kind INT8 NOT NULL,
9+
kind INT8 NOT NULL
1010
);
11-
CREATE TABLE new_audit_logs AS
12-
SELECT guild_id as guild, user_id as target, moderator, timestamp, previous, delta,
11+
12+
INSERT INTO new_audit_logs SELECT guild_id as guild, user_id as target, moderator, timestamp, previous, delta,
1313
CASE
1414
/* set */
1515
WHEN set THEN 2

xpd-common/Cargo.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ twilight-gateway = { version = "0.16", default-features = false }
1616
twilight-cache-inmemory = "0.16"
1717
twilight-model = "0.16"
1818

19+
# serialize / deserialize
1920
serde = { version = "1", features = ["derive"] }
21+
serde_repr = "0.1"
22+
23+
# convert enums to numbers
24+
strum = "0.27"
25+
strum_macros = "0.27"
2026

2127
# internal
2228
simpleinterpolation = { workspace = true }

xpd-common/src/lib.rs

Lines changed: 39 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use std::{
66
};
77

88
use simpleinterpolation::Interpolation;
9+
use strum_macros::FromRepr;
910
use twilight_cache_inmemory::ResourceType;
1011
use twilight_gateway::EventTypeFlags;
1112
use twilight_model::{
@@ -198,14 +199,48 @@ impl Display for GuildConfig {
198199

199200
#[derive(Clone, Copy, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
200201
pub struct AuditLogEvent {
201-
pub guild_id: Id<GuildMarker>,
202-
pub user_id: Id<UserMarker>,
202+
pub guild: Id<GuildMarker>,
203+
pub target: Id<UserMarker>,
203204
pub moderator: Id<UserMarker>,
204205
pub timestamp: i64,
205206
pub previous: i64,
206207
pub delta: i64,
207-
pub reset: bool,
208-
pub set: bool,
208+
pub kind: AuditLogEventKind,
209+
}
210+
211+
#[derive(
212+
Clone,
213+
Copy,
214+
Debug,
215+
PartialEq,
216+
Eq,
217+
serde_repr::Serialize_repr,
218+
serde_repr::Deserialize_repr,
219+
FromRepr,
220+
)]
221+
#[non_exhaustive]
222+
#[repr(i16)]
223+
pub enum AuditLogEventKind {
224+
AddSub = 0,
225+
Reset = 1,
226+
Set = 2,
227+
KickReset = 3,
228+
BanReset = 4,
229+
}
230+
231+
impl AuditLogEventKind {
232+
#[must_use]
233+
pub fn from_i64(t: i64) -> Option<Self> {
234+
let Ok(disc) = t.try_into() else {
235+
return None;
236+
};
237+
Self::from_repr(disc)
238+
}
239+
240+
#[must_use]
241+
pub const fn to_i64(self) -> i64 {
242+
self as i64
243+
}
209244
}
210245

211246
#[derive(Debug, Copy, Clone, Eq, PartialEq)]

xpd-database/src/lib.rs

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ use twilight_model::id::{
2323
marker::{ChannelMarker, GenericMarker, GuildMarker, RoleMarker, UserMarker},
2424
};
2525
use util::{db_to_id, id_to_db};
26-
use xpd_common::{AuditLogEvent, GuildConfig, RoleReward, UserInGuild, UserStatus};
26+
use xpd_common::{AuditLogEvent, AuditLogEventKind, GuildConfig, RoleReward, UserInGuild, UserStatus};
2727
pub async fn guild_rewards<
2828
'a,
2929
D: DerefMut<Target = PgConnection> + Send,
@@ -187,17 +187,16 @@ pub async fn add_audit_log_event<
187187
let mut conn = conn.acquire().await?;
188188
query!(
189189
"INSERT INTO audit_logs \
190-
(guild_id, user_id, moderator,
191-
timestamp, previous, delta, reset, set)
192-
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)",
193-
id_to_db(event.guild_id),
194-
id_to_db(event.user_id),
190+
(guild, target, moderator,
191+
timestamp, previous, delta, kind)
192+
VALUES ($1, $2, $3, $4, $5, $6, $7)",
193+
id_to_db(event.guild),
194+
id_to_db(event.target),
195195
id_to_db(event.moderator),
196196
event.timestamp,
197197
event.previous,
198198
event.delta,
199-
event.reset,
200-
event.set
199+
event.kind.to_i64(),
201200
)
202201
.execute(conn.as_mut())
203202
.await?;
@@ -210,36 +209,35 @@ pub async fn get_audit_log_events<
210209
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
211210
>(
212211
conn: A,
213-
guild_id: Id<GuildMarker>,
212+
guild: Id<GuildMarker>,
214213
actions_on_user: Option<Id<UserMarker>>,
215214
actions_by_moderator: Option<Id<UserMarker>>,
216215
) -> Result<Vec<AuditLogEvent>, Error> {
217216
let mut conn = conn.acquire().await?;
218217
let mut stream = query!(
219-
"SELECT user_id, moderator,
220-
timestamp, previous, delta, reset, set
221-
FROM audit_logs WHERE guild_id = $1",
222-
id_to_db(guild_id)
218+
"SELECT target, moderator,
219+
timestamp, previous, delta, kind
220+
FROM audit_logs WHERE guild = $1",
221+
id_to_db(guild)
223222
)
224223
.fetch(conn.as_mut());
225224
let mut logs = Vec::new();
226225
while let Some(row) = stream.next().await.transpose()? {
227-
let user_id = db_to_id(row.user_id);
226+
let target = db_to_id(row.target);
228227
let moderator = db_to_id(row.moderator);
229228
if actions_by_moderator.is_some_and(|requested_moderator| requested_moderator != moderator)
230-
|| actions_on_user.is_some_and(|requested_user| requested_user != user_id)
229+
|| actions_on_user.is_some_and(|requested_user| requested_user != target)
231230
{
232231
continue;
233232
}
234233
let log = AuditLogEvent {
235-
guild_id,
236-
user_id,
234+
guild,
235+
target,
237236
moderator: db_to_id(row.moderator),
238237
timestamp: row.timestamp,
239238
previous: row.previous,
240239
delta: row.delta,
241-
reset: row.reset,
242-
set: row.set,
240+
kind: AuditLogEventKind::from_i64(row.kind).ok_or(Error::UnknownAuditLogEventKind)?,
243241
};
244242
logs.push(log);
245243
}
@@ -252,12 +250,12 @@ pub async fn delete_audit_log_events_guild<
252250
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
253251
>(
254252
conn: A,
255-
guild_id: Id<GuildMarker>,
253+
guild: Id<GuildMarker>,
256254
) -> Result<(), Error> {
257255
let mut conn = conn.acquire().await?;
258256
query!(
259-
"DELETE FROM audit_logs WHERE guild_id = $1",
260-
id_to_db(guild_id)
257+
"DELETE FROM audit_logs WHERE guild = $1",
258+
id_to_db(guild)
261259
)
262260
.execute(conn.as_mut())
263261
.await?;
@@ -270,12 +268,12 @@ pub async fn delete_audit_log_events_user<
270268
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
271269
>(
272270
conn: A,
273-
user_id: Id<UserMarker>,
271+
target: Id<UserMarker>,
274272
) -> Result<(), Error> {
275273
let mut conn = conn.acquire().await?;
276274
query!(
277-
"DELETE FROM audit_logs WHERE user_id = $1",
278-
id_to_db(user_id)
275+
"DELETE FROM audit_logs WHERE target = $1",
276+
id_to_db(target)
279277
)
280278
.execute(conn.as_mut())
281279
.await?;
@@ -288,14 +286,14 @@ pub async fn delete_audit_log_events_user_guild<
288286
A: Acquire<'a, Database = Postgres, Connection = D> + Send,
289287
>(
290288
conn: A,
291-
user_id: Id<UserMarker>,
292-
guild_id: Id<GuildMarker>,
289+
target: Id<UserMarker>,
290+
guild: Id<GuildMarker>,
293291
) -> Result<(), Error> {
294292
let mut conn = conn.acquire().await?;
295293
query!(
296-
"DELETE FROM audit_logs WHERE user_id = $1 AND guild_id = $2",
297-
id_to_db(user_id),
298-
id_to_db(guild_id)
294+
"DELETE FROM audit_logs WHERE target = $1 AND guild = $2",
295+
id_to_db(target),
296+
id_to_db(guild)
299297
)
300298
.execute(conn.as_mut())
301299
.await?;
@@ -1091,6 +1089,7 @@ pub enum Error {
10911089
Database(sqlx::Error),
10921090
Interpolation(simpleinterpolation::ParseError),
10931091
UnspecifiedDelete,
1092+
UnknownAuditLogEventKind,
10941093
}
10951094

10961095
impl Display for Error {
@@ -1099,6 +1098,7 @@ impl Display for Error {
10991098
Self::Database(de) => write!(f, "{de}"),
11001099
Self::Interpolation(ie) => write!(f, "{ie}"),
11011100
Self::UnspecifiedDelete => f.write_str("No constraints specified to delete by."),
1101+
Self::UnknownAuditLogEventKind => f.write_str("Unknown audit log event kind")
11021102
}
11031103
}
11041104
}

xpd-database/src/test.rs

Lines changed: 19 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
use sqlx::PgPool;
22
use twilight_model::id::Id;
3+
use xpd_common::AuditLogEventKind;
34

45
use crate::*;
56

@@ -37,14 +38,13 @@ async fn find_deletes_returns_correctly(db: PgPool) -> Result<(), Box<dyn std::e
3738
#[sqlx::test(migrations = "../migrations/")]
3839
async fn audit_log_refetch(db: PgPool) -> Result<(), Box<dyn std::error::Error>> {
3940
let original_event = AuditLogEvent {
40-
guild_id: Id::new(1),
41-
user_id: Id::new(2),
41+
guild: Id::new(1),
42+
target: Id::new(2),
4243
moderator: Id::new(3),
4344
timestamp: 50,
4445
previous: 100,
4546
delta: -100,
46-
reset: true,
47-
set: false,
47+
kind: AuditLogEventKind::Reset,
4848
};
4949
add_audit_log_event(&db, original_event).await?;
5050
let roundtripped_event = get_audit_log_events(&db, Id::new(1), None, None).await?;
@@ -56,24 +56,22 @@ async fn audit_log_refetch(db: PgPool) -> Result<(), Box<dyn std::error::Error>>
5656
async fn audit_log_multi(db: PgPool) -> Result<(), Box<dyn std::error::Error>> {
5757
let original_events = vec![
5858
AuditLogEvent {
59-
guild_id: Id::new(1),
60-
user_id: Id::new(2),
59+
guild: Id::new(1),
60+
target: Id::new(2),
6161
moderator: Id::new(3),
6262
timestamp: 50,
6363
previous: 100,
6464
delta: -100,
65-
reset: true,
66-
set: false,
65+
kind: AuditLogEventKind::Reset
6766
},
6867
AuditLogEvent {
69-
guild_id: Id::new(1),
70-
user_id: Id::new(4),
68+
guild: Id::new(1),
69+
target: Id::new(4),
7170
moderator: Id::new(5),
7271
timestamp: 591,
7372
previous: 15,
7473
delta: 50,
75-
reset: false,
76-
set: true,
74+
kind: AuditLogEventKind::Set
7775
},
7876
];
7977
for event in &original_events {
@@ -92,34 +90,31 @@ async fn audit_log_multi(db: PgPool) -> Result<(), Box<dyn std::error::Error>> {
9290
async fn audit_logs_deleted_guild(db: PgPool) -> Result<(), Box<dyn std::error::Error>> {
9391
let original_events = vec![
9492
AuditLogEvent {
95-
guild_id: Id::new(1),
96-
user_id: Id::new(2),
93+
guild: Id::new(1),
94+
target: Id::new(2),
9795
moderator: Id::new(3),
9896
timestamp: 50,
9997
previous: 100,
10098
delta: -100,
101-
reset: false,
102-
set: false,
99+
kind: AuditLogEventKind::AddSub
103100
},
104101
AuditLogEvent {
105-
guild_id: Id::new(1),
106-
user_id: Id::new(4),
102+
guild: Id::new(1),
103+
target: Id::new(4),
107104
moderator: Id::new(5),
108105
timestamp: 591,
109106
previous: 15,
110107
delta: 50,
111-
reset: false,
112-
set: false,
108+
kind: AuditLogEventKind::AddSub
113109
},
114110
AuditLogEvent {
115-
guild_id: Id::new(2),
116-
user_id: Id::new(4),
111+
guild: Id::new(2),
112+
target: Id::new(4),
117113
moderator: Id::new(5),
118114
timestamp: 595,
119115
previous: 100,
120116
delta: 50,
121-
reset: false,
122-
set: true,
117+
kind: AuditLogEventKind::Set
123118
},
124119
];
125120
for event in &original_events {

0 commit comments

Comments
 (0)