1use mxr_core::AccountId;
2use sqlx::Row;
3
4pub struct EventLogEntry {
5 pub id: i64,
6 pub timestamp: i64,
7 pub level: String,
8 pub category: String,
9 pub account_id: Option<AccountId>,
10 pub message_id: Option<String>,
11 pub rule_id: Option<String>,
12 pub summary: String,
13 pub details: Option<String>,
14}
15
16impl super::Store {
17 pub async fn insert_event_refs(
18 &self,
19 level: &str,
20 category: &str,
21 summary: &str,
22 account_id: Option<&AccountId>,
23 message_id: Option<&str>,
24 rule_id: Option<&str>,
25 details: Option<&str>,
26 ) -> Result<(), sqlx::Error> {
27 let now = chrono::Utc::now().timestamp();
28 let aid = account_id.map(|a| a.as_str());
29 sqlx::query(
30 "INSERT INTO event_log (
31 timestamp,
32 level,
33 category,
34 account_id,
35 message_id,
36 rule_id,
37 summary,
38 details
39 ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
40 )
41 .bind(now)
42 .bind(level)
43 .bind(category)
44 .bind(aid)
45 .bind(message_id)
46 .bind(rule_id)
47 .bind(summary)
48 .bind(details)
49 .execute(self.writer())
50 .await?;
51 Ok(())
52 }
53
54 pub async fn insert_event(
55 &self,
56 level: &str,
57 category: &str,
58 summary: &str,
59 account_id: Option<&AccountId>,
60 details: Option<&str>,
61 ) -> Result<(), sqlx::Error> {
62 self.insert_event_refs(level, category, summary, account_id, None, None, details)
63 .await
64 }
65
66 pub async fn list_events(
68 &self,
69 limit: u32,
70 level: Option<&str>,
71 category: Option<&str>,
72 ) -> Result<Vec<EventLogEntry>, sqlx::Error> {
73 let mut sql = String::from("SELECT * FROM event_log WHERE 1=1");
74 if level.is_some() {
75 sql.push_str(" AND level = ?");
76 }
77 if category.is_some() {
78 sql.push_str(" AND category = ?");
79 }
80 sql.push_str(" ORDER BY timestamp DESC LIMIT ?");
81
82 let mut query = sqlx::query(&sql);
83 if let Some(l) = level {
84 query = query.bind(l);
85 }
86 if let Some(c) = category {
87 query = query.bind(c);
88 }
89 query = query.bind(limit);
90
91 let rows = query.fetch_all(self.reader()).await?;
92
93 Ok(rows
94 .iter()
95 .map(|r| {
96 let aid: Option<String> = r.get("account_id");
97 EventLogEntry {
98 id: r.get("id"),
99 timestamp: r.get("timestamp"),
100 level: r.get("level"),
101 category: r.get("category"),
102 account_id: aid
103 .map(|s| AccountId::from_uuid(uuid::Uuid::parse_str(&s).unwrap())),
104 message_id: r.get("message_id"),
105 rule_id: r.get("rule_id"),
106 summary: r.get("summary"),
107 details: r.get("details"),
108 }
109 })
110 .collect())
111 }
112
113 pub async fn prune_events_before(&self, cutoff_timestamp: i64) -> Result<u64, sqlx::Error> {
114 let result = sqlx::query("DELETE FROM event_log WHERE timestamp < ?")
115 .bind(cutoff_timestamp)
116 .execute(self.writer())
117 .await?;
118 Ok(result.rows_affected())
119 }
120}