-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
3 changed files
with
84 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
use anyhow::{Context, Result}; | ||
use chrono::{DateTime, Duration, Utc}; | ||
use sqlx::{prelude::*, query, query_as}; | ||
|
||
use crate::DbConn; | ||
|
||
#[derive(FromRow)] | ||
pub struct NotificationDAO { | ||
pub id: i64, | ||
|
||
pub kind: String, | ||
pub content: String, | ||
pub created_at: DateTime<Utc>, | ||
pub updated_at: DateTime<Utc>, | ||
} | ||
|
||
impl DbConn { | ||
pub async fn create_notification(&self, kind: &str, content: &str) -> Result<i64> { | ||
let res = query!( | ||
"INSERT INTO notifications (kind, content) VALUES (?, ?)", | ||
kind, | ||
content | ||
) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
Ok(res.last_insert_rowid()) | ||
} | ||
|
||
pub async fn mark_notification_readed(&self, id: i64, user_id: i64) -> Result<()> { | ||
query!( | ||
"INSERT INTO readed_notifications (notification_id, user_id) VALUES (?, ?)", | ||
id, | ||
user_id | ||
) | ||
.execute(&self.pool) | ||
.await?; | ||
|
||
Ok(()) | ||
} | ||
|
||
pub async fn list_notifications_within_7days( | ||
&self, | ||
user_id: i64, | ||
) -> Result<Vec<NotificationDAO>> { | ||
let user = self | ||
.get_user(user_id) | ||
.await? | ||
.context("User doesn't exist")?; | ||
let kind_clause = if user.is_admin { | ||
"kind = 'all_user' OR kind = 'admin'" | ||
} else { | ||
"kind = 'all_user'" | ||
}; | ||
let date_7days_ago = Utc::now() - Duration::days(7); | ||
let sql = format!( | ||
r#" | ||
SELECT notifications.id, notifications.created_at, notifications.updated_at, kind, content | ||
FROM notifications LEFT JOIN readed_notifications ON notifications.id = readed_notifications.notification_id | ||
WHERE ({kind_clause}) AND notifications.created_at > '{date_7days_ago}' AND readed_notifications.user_id IS NULL -- notification is not marked as readed | ||
"# | ||
); | ||
let notifications = query_as(&sql).fetch_all(&self.pool).await?; | ||
Ok(notifications) | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
mod tests { | ||
use crate::testutils; | ||
|
||
use super::*; | ||
|
||
/// Smoke test to ensure sql query is valid, actual functionality test shall happens at service level. | ||
#[tokio::test] | ||
async fn smoketest_list_notifications() { | ||
let db = DbConn::new_in_memory().await.unwrap(); | ||
let user1 = testutils::create_user(&db).await; | ||
let notifications = db.list_notifications_within_7days(user1).await.unwrap(); | ||
assert!(notifications.is_empty()) | ||
} | ||
} |