summaryrefslogtreecommitdiff
path: root/src/notifications.rs
diff options
context:
space:
mode:
authorDawid Rycerz <dawid@rycerz.xyz>2025-07-14 19:34:59 +0300
committerDawid Rycerz <dawid@rycerz.xyz>2025-07-14 19:34:59 +0300
commit50ce8cb96b2b218751c2fc2a6b19372f51846acc (patch)
treee2c634d2ce856062d527667d47815a05a53361c8 /src/notifications.rs
parent0ab2e5ba2b0631b28b5b1405559237b3913c878f (diff)
feat: rewrite in rust
Diffstat (limited to 'src/notifications.rs')
-rw-r--r--src/notifications.rs294
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