diff options
| author | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-14 19:34:59 +0300 |
|---|---|---|
| committer | Dawid Rycerz <dawid@rycerz.xyz> | 2025-07-14 19:34:59 +0300 |
| commit | 50ce8cb96b2b218751c2fc2a6b19372f51846acc (patch) | |
| tree | e2c634d2ce856062d527667d47815a05a53361c8 /src/notifications.rs | |
| parent | 0ab2e5ba2b0631b28b5b1405559237b3913c878f (diff) | |
feat: rewrite in rust
Diffstat (limited to 'src/notifications.rs')
| -rw-r--r-- | src/notifications.rs | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/src/notifications.rs b/src/notifications.rs new file mode 100644 index 0000000..fb49e97 --- /dev/null +++ b/src/notifications.rs @@ -0,0 +1,294 @@ +use serde::{Deserialize, Serialize}; +use sqlx::FromRow; + +#[derive(Debug, Serialize, Deserialize, FromRow, Clone, PartialEq)] +pub struct NtfySettings { + pub id: i64, + pub user_id: i64, + pub enabled: bool, + pub topic: String, + pub server_url: String, + pub priority: i32, + pub title_template: Option<String>, + pub message_template: Option<String>, +} + +#[derive(Debug, Serialize, Deserialize, FromRow, Clone, PartialEq)] +pub struct SmtpSettings { + pub id: i64, + pub user_id: i64, + pub enabled: bool, + pub email: String, + pub smtp_server: String, + pub smtp_port: i32, + pub username: Option<String>, + pub password: Option<String>, + pub use_tls: bool, + pub from_email: Option<String>, + pub from_name: Option<String>, + pub subject_template: Option<String>, + pub body_template: Option<String>, +} + +pub struct NtfySettingsRepository<'a> { + pub db: &'a sqlx::SqlitePool, +} + +impl<'a> NtfySettingsRepository<'a> { + pub async fn get_by_user(&self, user_id: i64) -> Result<Option<NtfySettings>, sqlx::Error> { + sqlx::query_as::<_, NtfySettings>( + "SELECT * FROM user_ntfy_settings WHERE user_id = ?" + ) + .bind(user_id) + .fetch_optional(self.db) + .await + } + + pub async fn create(&self, user_id: i64, enabled: bool, topic: String, server_url: String, priority: i32, title_template: Option<String>, message_template: Option<String>) -> Result<NtfySettings, sqlx::Error> { + sqlx::query_as::<_, NtfySettings>( + "INSERT INTO user_ntfy_settings (user_id, enabled, topic, server_url, priority, title_template, message_template) VALUES (?, ?, ?, ?, ?, ?, ?) RETURNING *" + ) + .bind(user_id) + .bind(enabled) + .bind(topic) + .bind(server_url) + .bind(priority) + .bind(title_template) + .bind(message_template) + .fetch_one(self.db) + .await + } + + pub async fn update(&self, id: i64, enabled: bool, topic: String, server_url: String, priority: i32, title_template: Option<String>, message_template: Option<String>) -> Result<NtfySettings, sqlx::Error> { + sqlx::query_as::<_, NtfySettings>( + "UPDATE user_ntfy_settings SET enabled = ?, topic = ?, server_url = ?, priority = ?, title_template = ?, message_template = ? WHERE id = ? RETURNING *" + ) + .bind(enabled) + .bind(topic) + .bind(server_url) + .bind(priority) + .bind(title_template) + .bind(message_template) + .bind(id) + .fetch_one(self.db) + .await + } + + pub async fn delete(&self, id: i64) -> Result<(), sqlx::Error> { + sqlx::query("DELETE FROM user_ntfy_settings WHERE id = ?") + .bind(id) + .execute(self.db) + .await?; + Ok(()) + } +} + +pub struct SmtpSettingsRepository<'a> { + pub db: &'a sqlx::SqlitePool, +} + +impl<'a> SmtpSettingsRepository<'a> { + pub async fn get_by_user(&self, user_id: i64) -> Result<Option<SmtpSettings>, sqlx::Error> { + sqlx::query_as::<_, SmtpSettings>( + "SELECT * FROM user_smtp_settings WHERE user_id = ?" + ) + .bind(user_id) + .fetch_optional(self.db) + .await + } + + pub async fn create(&self, user_id: i64, enabled: bool, email: String, smtp_server: String, smtp_port: i32, username: Option<String>, password: Option<String>, use_tls: bool, from_email: Option<String>, from_name: Option<String>, subject_template: Option<String>, body_template: Option<String>) -> Result<SmtpSettings, sqlx::Error> { + sqlx::query_as::<_, SmtpSettings>( + "INSERT INTO user_smtp_settings (user_id, enabled, email, smtp_server, smtp_port, username, password, use_tls, from_email, from_name, subject_template, body_template) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) RETURNING *" + ) + .bind(user_id) + .bind(enabled) + .bind(email) + .bind(smtp_server) + .bind(smtp_port) + .bind(username) + .bind(password) + .bind(use_tls) + .bind(from_email) + .bind(from_name) + .bind(subject_template) + .bind(body_template) + .fetch_one(self.db) + .await + } + + pub async fn update(&self, id: i64, enabled: bool, email: String, smtp_server: String, smtp_port: i32, username: Option<String>, password: Option<String>, use_tls: bool, from_email: Option<String>, from_name: Option<String>, subject_template: Option<String>, body_template: Option<String>) -> Result<SmtpSettings, sqlx::Error> { + sqlx::query_as::<_, SmtpSettings>( + "UPDATE user_smtp_settings SET enabled = ?, email = ?, smtp_server = ?, smtp_port = ?, username = ?, password = ?, use_tls = ?, from_email = ?, from_name = ?, subject_template = ?, body_template = ? WHERE id = ? RETURNING *" + ) + .bind(enabled) + .bind(email) + .bind(smtp_server) + .bind(smtp_port) + .bind(username) + .bind(password) + .bind(use_tls) + .bind(from_email) + .bind(from_name) + .bind(subject_template) + .bind(body_template) + .bind(id) + .fetch_one(self.db) + .await + } + + pub async fn delete(&self, id: i64) -> Result<(), sqlx::Error> { + sqlx::query("DELETE FROM user_smtp_settings WHERE id = ?") + .bind(id) + .execute(self.db) + .await?; + Ok(()) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use crate::users::{UserRepository, UserRole}; + use sqlx::{SqlitePool, Executor}; + use tokio; + + async fn setup_db() -> SqlitePool { + let pool = SqlitePool::connect(":memory:").await.unwrap(); + pool.execute( + "CREATE TABLE users ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id TEXT NOT NULL UNIQUE, + role TEXT NOT NULL DEFAULT 'user' + );" + ).await.unwrap(); + pool.execute( + "CREATE TABLE user_ntfy_settings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + enabled BOOLEAN NOT NULL DEFAULT 0, + topic TEXT NOT NULL, + server_url TEXT NOT NULL, + priority INTEGER NOT NULL DEFAULT 5, + title_template TEXT, + message_template TEXT, + FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE + );" + ).await.unwrap(); + pool.execute( + "CREATE TABLE user_smtp_settings ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + user_id INTEGER NOT NULL, + enabled BOOLEAN NOT NULL DEFAULT 0, + email TEXT NOT NULL, + smtp_server TEXT NOT NULL, + smtp_port INTEGER NOT NULL, + username TEXT, + password TEXT, + use_tls BOOLEAN NOT NULL DEFAULT 1, + from_email TEXT, + from_name TEXT DEFAULT 'Silmätaivas Alerts', + subject_template TEXT, + body_template TEXT, + FOREIGN KEY(user_id) REFERENCES users(id) ON DELETE CASCADE + );" + ).await.unwrap(); + pool + } + + async fn create_user(pool: &SqlitePool) -> i64 { + let repo = UserRepository { db: pool }; + let user = repo.create_user(None, Some(UserRole::User)).await.unwrap(); + user.id + } + + #[tokio::test] + async fn test_create_and_get_ntfy_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = NtfySettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "topic1".to_string(), "https://ntfy.sh".to_string(), 3, Some("title".to_string()), Some("msg".to_string())).await.unwrap(); + let fetched = repo.get_by_user(user_id).await.unwrap().unwrap(); + assert_eq!(fetched.topic, "topic1"); + assert_eq!(fetched.server_url, "https://ntfy.sh"); + assert_eq!(fetched.priority, 3); + assert_eq!(fetched.title_template, Some("title".to_string())); + assert_eq!(fetched.message_template, Some("msg".to_string())); + } + + #[tokio::test] + async fn test_update_ntfy_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = NtfySettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "topic1".to_string(), "https://ntfy.sh".to_string(), 3, None, None).await.unwrap(); + let updated = repo.update(settings.id, false, "topic2".to_string(), "https://ntfy2.sh".to_string(), 4, Some("t2".to_string()), Some("m2".to_string())).await.unwrap(); + assert_eq!(updated.enabled, false); + assert_eq!(updated.topic, "topic2"); + assert_eq!(updated.server_url, "https://ntfy2.sh"); + assert_eq!(updated.priority, 4); + assert_eq!(updated.title_template, Some("t2".to_string())); + assert_eq!(updated.message_template, Some("m2".to_string())); + } + + #[tokio::test] + async fn test_delete_ntfy_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = NtfySettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "topic1".to_string(), "https://ntfy.sh".to_string(), 3, None, None).await.unwrap(); + repo.delete(settings.id).await.unwrap(); + let fetched = repo.get_by_user(user_id).await.unwrap(); + assert!(fetched.is_none()); + } + + #[tokio::test] + async fn test_create_and_get_smtp_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = SmtpSettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "test@example.com".to_string(), "smtp.example.com".to_string(), 587, Some("user".to_string()), Some("pass".to_string()), true, Some("from@example.com".to_string()), Some("Alerts".to_string()), Some("subj".to_string()), Some("body".to_string())).await.unwrap(); + let fetched = repo.get_by_user(user_id).await.unwrap().unwrap(); + assert_eq!(fetched.email, "test@example.com"); + assert_eq!(fetched.smtp_server, "smtp.example.com"); + assert_eq!(fetched.smtp_port, 587); + assert_eq!(fetched.username, Some("user".to_string())); + assert_eq!(fetched.password, Some("pass".to_string())); + assert_eq!(fetched.use_tls, true); + assert_eq!(fetched.from_email, Some("from@example.com".to_string())); + assert_eq!(fetched.from_name, Some("Alerts".to_string())); + assert_eq!(fetched.subject_template, Some("subj".to_string())); + assert_eq!(fetched.body_template, Some("body".to_string())); + } + + #[tokio::test] + async fn test_update_smtp_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = SmtpSettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "test@example.com".to_string(), "smtp.example.com".to_string(), 587, None, None, true, None, None, None, None).await.unwrap(); + let updated = repo.update(settings.id, false, "other@example.com".to_string(), "smtp2.example.com".to_string(), 465, Some("u2".to_string()), Some("p2".to_string()), false, Some("f2@example.com".to_string()), Some("N2".to_string()), Some("s2".to_string()), Some("b2".to_string())).await.unwrap(); + assert_eq!(updated.enabled, false); + assert_eq!(updated.email, "other@example.com"); + assert_eq!(updated.smtp_server, "smtp2.example.com"); + assert_eq!(updated.smtp_port, 465); + assert_eq!(updated.username, Some("u2".to_string())); + assert_eq!(updated.password, Some("p2".to_string())); + assert_eq!(updated.use_tls, false); + assert_eq!(updated.from_email, Some("f2@example.com".to_string())); + assert_eq!(updated.from_name, Some("N2".to_string())); + assert_eq!(updated.subject_template, Some("s2".to_string())); + assert_eq!(updated.body_template, Some("b2".to_string())); + } + + #[tokio::test] + async fn test_delete_smtp_settings() { + let db = setup_db().await; + let user_id = create_user(&db).await; + let repo = SmtpSettingsRepository { db: &db }; + let settings = repo.create(user_id, true, "test@example.com".to_string(), "smtp.example.com".to_string(), 587, None, None, true, None, None, None, None).await.unwrap(); + repo.delete(settings.id).await.unwrap(); + let fetched = repo.get_by_user(user_id).await.unwrap(); + assert!(fetched.is_none()); + } +}
\ No newline at end of file |
