autopulse_database/
models.rs1use autopulse_utils::{generate_uuid, Rewrite};
2use chrono::NaiveDateTime;
3use diesel::prelude::*;
4use serde::Serialize;
5use std::{fmt::Display, str::FromStr};
6
7#[derive(Serialize, Clone, Copy, Debug, PartialEq, Eq)]
9pub enum ProcessStatus {
10 Pending,
11 Complete,
12 Retry,
13 Failed,
14}
15
16#[derive(Serialize)]
20pub enum FoundStatus {
21 Found,
22 NotFound,
23 HashMismatch,
24}
25
26impl Display for FoundStatus {
27 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
28 let status = match self {
29 Self::Found => "found",
30 Self::NotFound => "not_found",
31 Self::HashMismatch => "hash_mismatch",
32 };
33
34 write!(f, "{status}")
35 }
36}
37
38impl From<FoundStatus> for String {
39 fn from(val: FoundStatus) -> Self {
40 val.to_string()
41 }
42}
43
44impl From<ProcessStatus> for &'static str {
45 fn from(val: ProcessStatus) -> Self {
46 match val {
47 ProcessStatus::Pending => "pending",
48 ProcessStatus::Complete => "complete",
49 ProcessStatus::Retry => "retry",
50 ProcessStatus::Failed => "failed",
51 }
52 }
53}
54
55impl From<ProcessStatus> for String {
56 fn from(val: ProcessStatus) -> Self {
57 <&'static str>::from(val).to_string()
58 }
59}
60
61impl FromStr for ProcessStatus {
62 type Err = ();
63 fn from_str(s: &str) -> Result<Self, Self::Err> {
64 match s {
65 "pending" => Ok(Self::Pending),
66 "complete" => Ok(Self::Complete),
67 "retry" => Ok(Self::Retry),
68 "failed" => Ok(Self::Failed),
69 _ => Err(()),
70 }
71 }
72}
73
74#[derive(
78 Queryable, Selectable, Serialize, Clone, Debug, AsChangeset, Identifiable, Hash, Eq, PartialEq,
79)]
80#[diesel(table_name = crate::schema::scan_events)]
81pub struct ScanEvent {
82 pub id: String,
84
85 pub event_source: String,
87 pub event_timestamp: NaiveDateTime,
89
90 pub file_path: String,
92 pub file_hash: Option<String>,
94 pub process_status: String,
96 pub found_status: String,
98
99 pub failed_times: i32,
101 pub next_retry_at: Option<chrono::NaiveDateTime>,
103
104 pub targets_hit: String,
106
107 pub found_at: Option<chrono::NaiveDateTime>,
109 pub processed_at: Option<chrono::NaiveDateTime>,
111
112 pub created_at: NaiveDateTime,
114 pub updated_at: NaiveDateTime,
116
117 pub can_process: NaiveDateTime,
119}
120
121impl ScanEvent {
122 pub fn get_targets_hit(&self) -> Vec<String> {
123 self.targets_hit
124 .split(',')
125 .map(|s| s.to_string())
126 .filter(|s| !s.is_empty())
127 .collect()
128 }
129
130 pub fn add_target_hit(&mut self, target: &str) {
131 let mut targets = self.get_targets_hit();
132 targets.push(target.to_string());
133 targets.sort();
134 targets.dedup();
135 self.targets_hit = targets.join(",");
136 }
137
138 pub fn get_path(&self, rewrite: &Option<Rewrite>) -> String {
139 rewrite.as_ref().map_or_else(
140 || self.file_path.clone(),
141 |rewrite| rewrite.rewrite_path(self.file_path.clone()),
142 )
143 }
144}
145
146#[derive(Insertable)]
147#[diesel(table_name = crate::schema::scan_events)]
148#[doc(hidden)]
149pub struct NewScanEvent {
150 pub id: String,
151 pub event_source: String,
152
153 pub file_path: String,
154 pub file_hash: Option<String>,
155
156 pub found_status: String,
157 pub can_process: NaiveDateTime,
158}
159
160impl Default for NewScanEvent {
161 fn default() -> Self {
162 Self {
163 id: generate_uuid(),
164 event_source: "unknown".to_string(),
165 file_path: "unknown".to_string(),
166 file_hash: None,
167 found_status: FoundStatus::NotFound.into(),
168 can_process: chrono::Utc::now().naive_utc(),
169 }
170 }
171}
172
173#[derive(Queryable, Selectable, Insertable, Clone, Debug)]
175#[diesel(table_name = crate::schema::app_state)]
176pub struct AppState {
177 pub key: String,
178 pub value: Vec<u8>,
179 pub updated_at: NaiveDateTime,
180}