Skip to content

Commit

Permalink
add notifications dao
Browse files Browse the repository at this point in the history
  • Loading branch information
wsxiaoys committed Dec 5, 2024
1 parent a02ff42 commit ad64d6d
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 1 deletion.
2 changes: 1 addition & 1 deletion ee/tabby-db/migrations/0039_add-notification-inbox.up.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ CREATE TABLE notifications (
created_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')),
updated_at TIMESTAMP NOT NULL DEFAULT(DATETIME('now')),

-- enum of ADMIN, ALL_USERS
-- enum of admin, all_user
kind VARCHAR(255) NOT NULL DEFAULT 'admin',

-- content of notification, in markdown format.
Expand Down
1 change: 1 addition & 0 deletions ee/tabby-db/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ mod user_events;
mod user_groups;
mod users;
mod web_documents;
mod notifications;

use anyhow::Result;
use sql_query_builder as sql;
Expand Down
82 changes: 82 additions & 0 deletions ee/tabby-db/src/notifications.rs
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())
}
}

0 comments on commit ad64d6d

Please sign in to comment.