mirror of
https://github.com/rzuasti/oott.git
synced 2026-07-08 19:21:54 +02:00
Added notification read and insert from database
This commit is contained in:
+237
-19
@@ -1,6 +1,7 @@
|
||||
use crate::db;
|
||||
use crate::db::error::DbError;
|
||||
use log::debug;
|
||||
use log::{debug, error};
|
||||
use rusqlite::params;
|
||||
|
||||
use crate::model::notifications::Notification;
|
||||
|
||||
@@ -28,6 +29,55 @@ pub fn list() -> Result<Vec<Notification>, DbError> {
|
||||
Ok(notifications)
|
||||
}
|
||||
|
||||
pub fn insert(notification: Notification) -> Result<i64, DbError> {
|
||||
let conn = db::get_db_connection();
|
||||
|
||||
match conn.execute(
|
||||
"INSERT INTO notifications (created_on, notification_type, title, body, is_new) VALUES (?1, ?2, ?3, ?4, ?5)",
|
||||
params![notification.created_on, notification.notification_type, notification.title, notification.body, notification.is_new]) {
|
||||
Ok(_) => {
|
||||
debug!("Notification inserted into database: {}", notification);
|
||||
Ok(conn.last_insert_rowid())
|
||||
},
|
||||
Err(error) => {
|
||||
error!("Error inserting notification ({notification}) into database: {error}");
|
||||
Err(DbError::from(error))
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn read(id: i64) -> Option<Notification> {
|
||||
let conn = db::get_db_connection();
|
||||
|
||||
let result: Result<Notification, rusqlite::Error> = conn.query_one(
|
||||
"SELECT id, created_on, notification_type, title, body, is_new FROM notifications WHERE id=?1",
|
||||
params![id],
|
||||
|row| {
|
||||
Ok(Notification {
|
||||
id: row.get(0)?,
|
||||
created_on: row.get(1)?,
|
||||
notification_type: row.get(2)?,
|
||||
title: row.get(3)?,
|
||||
body: row.get(4)?,
|
||||
is_new: row.get(5)?,
|
||||
})
|
||||
},
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(value) => Some(value),
|
||||
Err(error) => {
|
||||
match error {
|
||||
rusqlite::Error::QueryReturnedNoRows => {
|
||||
debug!("No notification found for id={id}.")
|
||||
}
|
||||
_ => error!("Error reading notification from database: {error}"),
|
||||
};
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use chrono::{TimeZone, Utc};
|
||||
@@ -35,16 +85,184 @@ mod tests {
|
||||
use super::*;
|
||||
use crate::{model::notifications::NotificationType, tests_common};
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_insert_default() {
|
||||
tests_common::setup().await;
|
||||
|
||||
// Insert notification and read with returned ID
|
||||
let created_on = Utc::now();
|
||||
let inserted_id = insert(Notification::new(
|
||||
created_on,
|
||||
NotificationType::DeviceOnlineAfterTime,
|
||||
"New notification title".to_string(),
|
||||
"New notification body".to_string(),
|
||||
true,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
inserted_id >= 0,
|
||||
"Inserted notification id should be positive"
|
||||
);
|
||||
|
||||
// Validate all fields
|
||||
let inserted_notification = read(inserted_id).unwrap();
|
||||
assert_eq!(
|
||||
inserted_notification.notification_type,
|
||||
NotificationType::DeviceOnlineAfterTime,
|
||||
"Wrong notification type (should be DeviceOnlineAfterTime)"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.is_new, true,
|
||||
"Notification should be new"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.created_on, created_on,
|
||||
"Wrong created_on (should be ${created_on})"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.title, "New notification title",
|
||||
"Wrong title (should be 'New notification title')"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.body, "New notification body",
|
||||
"Wrong body (should be 'New notification body')"
|
||||
);
|
||||
|
||||
// Insert and validate notification without title nor body
|
||||
let created_on = Utc::now();
|
||||
let inserted_id = insert(Notification::new(
|
||||
created_on,
|
||||
NotificationType::Other,
|
||||
"".to_string(),
|
||||
"".to_string(),
|
||||
false,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
assert!(
|
||||
inserted_id >= 0,
|
||||
"Inserted notification id should be positive"
|
||||
);
|
||||
|
||||
// Validate all fields
|
||||
let inserted_notification = read(inserted_id).unwrap();
|
||||
assert_eq!(
|
||||
inserted_notification.notification_type,
|
||||
NotificationType::Other,
|
||||
"Wrong notification type (should be Other)"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.is_new, false,
|
||||
"Notification should not be new"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.created_on, created_on,
|
||||
"Wrong created_on (should be ${created_on})"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.title, "",
|
||||
"Wrong title (should be empty)"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.body, "",
|
||||
"Wrong body (should be empty)"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_read_default() {
|
||||
tests_common::setup().await;
|
||||
|
||||
// Read existing notification
|
||||
let notification_option = read(2);
|
||||
|
||||
// Notification should not be empty
|
||||
assert!(
|
||||
notification_option.is_some(),
|
||||
"Notification id=2 should be read"
|
||||
);
|
||||
|
||||
// Validate all fields
|
||||
let notification = notification_option.unwrap();
|
||||
assert_eq!(notification.id, 2, "Wrong notification id (should be 2)");
|
||||
assert_eq!(
|
||||
notification.notification_type,
|
||||
NotificationType::NewDeviceFound,
|
||||
"Wrong notification type (should be NewDeviceFound)"
|
||||
);
|
||||
assert_eq!(notification.is_new, false, "Notification should not be new");
|
||||
assert_eq!(
|
||||
notification.created_on,
|
||||
Utc.with_ymd_and_hms(2026, 1, 4, 8, 10, 13).unwrap(),
|
||||
"Wrong created_on (should be 2026-01-04 08:10:13)"
|
||||
);
|
||||
assert_eq!(
|
||||
notification.title, "Read new device found",
|
||||
"Wrong title (should be 'Read new device found')"
|
||||
);
|
||||
assert_eq!(
|
||||
notification.body, "Body read new device found",
|
||||
"Wrong body (should be 'Body read new device found')"
|
||||
);
|
||||
|
||||
// Read non-existant notification
|
||||
assert!(
|
||||
read(999999999).is_none(),
|
||||
"Notification id=999999999 should not exist"
|
||||
);
|
||||
|
||||
// Insert notification and read with returned ID
|
||||
let created_on = Utc::now();
|
||||
let inserted_id = insert(Notification::new(
|
||||
created_on,
|
||||
NotificationType::DeviceOnlineAfterTime,
|
||||
"New notification title".to_string(),
|
||||
"New notification body".to_string(),
|
||||
true,
|
||||
))
|
||||
.unwrap();
|
||||
|
||||
// Validate all fields
|
||||
let inserted_notification = read(inserted_id).unwrap();
|
||||
assert_eq!(
|
||||
inserted_notification.notification_type,
|
||||
NotificationType::DeviceOnlineAfterTime,
|
||||
"Wrong notification type (should be DeviceOnlineAfterTime)"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.is_new, true,
|
||||
"Notification should be new"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.created_on, created_on,
|
||||
"Wrong created_on (should be ${created_on})"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.title, "New notification title",
|
||||
"Wrong title (should be 'New notification title')"
|
||||
);
|
||||
assert_eq!(
|
||||
inserted_notification.body, "New notification body",
|
||||
"Wrong body (should be 'New notification body')"
|
||||
);
|
||||
|
||||
// Read non-existant notification
|
||||
assert!(
|
||||
read(999999999).is_none(),
|
||||
"Notification id=999999999 should not exist"
|
||||
);
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
async fn test_list_default() {
|
||||
tests_common::setup().await;
|
||||
let notifications = list().unwrap();
|
||||
|
||||
// There should be 3 unread notifications
|
||||
assert_eq!(
|
||||
notifications.len(),
|
||||
3,
|
||||
"There should be 3 notifications in the list"
|
||||
// There should be at least 3 unread notifications
|
||||
assert!(
|
||||
notifications.len() >= 3,
|
||||
"There should be at least 3 notifications in the list"
|
||||
);
|
||||
|
||||
// All notifications must be unread/new
|
||||
@@ -56,32 +274,32 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
// There should be only one of each type
|
||||
assert_eq!(
|
||||
1,
|
||||
// There should be at least one of each type
|
||||
assert!(
|
||||
notifications
|
||||
.iter()
|
||||
.filter(|notification| notification.notification_type == NotificationType::Other)
|
||||
.count(),
|
||||
"There should be only one notification of type Other"
|
||||
.count()
|
||||
>= 1,
|
||||
"There should be at least one notification of type Other"
|
||||
);
|
||||
assert_eq!(
|
||||
1,
|
||||
assert!(
|
||||
notifications
|
||||
.iter()
|
||||
.filter(|notification| notification.notification_type
|
||||
== NotificationType::DeviceOnlineAfterTime)
|
||||
.count(),
|
||||
"There should be only one notification of type Other"
|
||||
.count()
|
||||
>= 1,
|
||||
"There should be at least one notification of type DeviceOnlineAfterTime"
|
||||
);
|
||||
assert_eq!(
|
||||
1,
|
||||
assert!(
|
||||
notifications
|
||||
.iter()
|
||||
.filter(|notification| notification.notification_type
|
||||
== NotificationType::NewDeviceFound)
|
||||
.count(),
|
||||
"There should be only one notification of type Other"
|
||||
.count()
|
||||
>= 1,
|
||||
"There should be at least one notification of type Other"
|
||||
);
|
||||
|
||||
// Check date of notification 1
|
||||
|
||||
@@ -14,6 +14,25 @@ pub struct Notification {
|
||||
pub is_new: bool,
|
||||
}
|
||||
|
||||
impl Notification {
|
||||
pub fn new(
|
||||
created_on: DateTime<Utc>,
|
||||
notification_type: NotificationType,
|
||||
title: String,
|
||||
body: String,
|
||||
is_new: bool,
|
||||
) -> Self {
|
||||
Self {
|
||||
id: -1,
|
||||
created_on: created_on,
|
||||
notification_type: notification_type,
|
||||
title: title,
|
||||
body: body,
|
||||
is_new: is_new,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Notification {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
write!(
|
||||
@@ -30,7 +49,7 @@ impl PartialEq for Notification {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq)]
|
||||
pub enum NotificationType {
|
||||
NewDeviceFound,
|
||||
DeviceOnlineAfterTime,
|
||||
|
||||
Reference in New Issue
Block a user