feat: impl traits to add, get and mark read notifications for sqlx

postgres
This commit is contained in:
realaravinth 2022-05-26 19:32:16 +05:30
parent e9921db55b
commit 44740535c2
No known key found for this signature in database
GPG key ID: AD9F0F08E855ED88
5 changed files with 143 additions and 24 deletions

View file

@ -0,0 +1,3 @@
-- Add migration script here
ALTER TABLE mcaptcha_notifications ALTER COLUMN heading TYPE varchar(100),
ALTER COLUMN heading SET NOT NULL;

View file

@ -0,0 +1,24 @@
-- gets all unread notifications a user has
SELECT
mcaptcha_notifications.id,
mcaptcha_notifications.heading,
mcaptcha_notifications.message,
mcaptcha_notifications.received,
mcaptcha_users.name
FROM
mcaptcha_notifications
INNER JOIN
mcaptcha_users
ON
mcaptcha_notifications.tx = mcaptcha_users.id
WHERE
mcaptcha_notifications.rx = (
SELECT
id
FROM
mcaptcha_users
WHERE
name = $1
)
AND
mcaptcha_notifications.read IS NULL;

View file

@ -637,30 +637,98 @@ impl MCDatabase for Database {
.map_err(|e| map_row_not_found_err(e, DBError::TrafficPatternNotFound))?;
Ok(())
}
/// create new notification
async fn create_notification(&self, p: &AddNotification) -> DBResult<()> {
let now = now_unix_time_stamp();
sqlx::query!(
"INSERT INTO mcaptcha_notifications (
heading, message, tx, rx, received)
VALUES (
$1, $2,
(SELECT ID FROM mcaptcha_users WHERE name = $3),
(SELECT ID FROM mcaptcha_users WHERE name = $4),
$5
);",
p.heading,
p.message,
p.from,
p.to,
now
)
.execute(&self.pool)
.await
.map_err(map_register_err)?;
Ok(())
}
/// get all unread notifications
async fn get_all_unread_notifications(
&self,
username: &str,
) -> DBResult<Vec<Notification>> {
let mut inner_notifications = sqlx::query_file_as!(
InnerNotification,
"./src/get_all_unread_notifications.sql",
&username
)
.fetch_all(&self.pool)
.await
.map_err(|e| map_row_not_found_err(e, DBError::AccountNotFound))?;
let mut notifications = Vec::with_capacity(inner_notifications.len());
inner_notifications
.drain(0..)
.for_each(|n| notifications.push(n.into()));
Ok(notifications)
}
/// mark a notification read
async fn mark_notification_read(&self, username: &str, id: i32) -> DBResult<()> {
sqlx::query_file_as!(
Notification,
"./src/mark_notification_read.sql",
id,
&username
)
.execute(&self.pool)
.await
.map_err(|e| map_row_not_found_err(e, DBError::NotificationNotFound))?;
Ok(())
}
}
fn now_unix_time_stamp() -> i64 {
OffsetDateTime::now_utc().unix_timestamp()
fn now_unix_time_stamp() -> OffsetDateTime {
OffsetDateTime::now_utc()
}
//
//#[allow(non_snake_case)]
//struct InnerGistComment {
// ID: i64,
// owner: String,
// comment: Option<String>,
// gist_public_id: String,
// created: i64,
//}
//
//impl From<InnerGistComment> for GistComment {
// fn from(g: InnerGistComment) -> Self {
// Self {
// id: g.ID,
// owner: g.owner,
// comment: g.comment.unwrap(),
// gist_public_id: g.gist_public_id,
// created: g.created,
// }
// }
//}
#[derive(Debug, Clone, Default, PartialEq)]
/// Represents notification
pub struct InnerNotification {
/// receiver name of the notification
pub name: Option<String>,
/// heading of the notification
pub heading: Option<String>,
/// message of the notification
pub message: Option<String>,
/// when notification was received
pub received: Option<OffsetDateTime>,
/// db assigned ID of the notification
pub id: Option<i32>,
}
impl From<InnerNotification> for Notification {
fn from(n: InnerNotification) -> Self {
Notification {
name: n.name,
heading: n.heading,
message: n.message,
received: n.received.map(|t| t.unix_timestamp()),
id: n.id,
}
}
}

View file

@ -0,0 +1,14 @@
-- mark a notification as read
UPDATE mcaptcha_notifications
SET read = TRUE
WHERE
mcaptcha_notifications.id = $1
AND
mcaptcha_notifications.rx = (
SELECT
id
FROM
mcaptcha_users
WHERE
name = $2
);

View file

@ -33,6 +33,9 @@ async fn everyting_works() {
const CAPTCHA_SECRET: &str = "postgrescaptchasecret";
const CAPTCHA_DESCRIPTION: &str = "postgrescaptchadescription";
const CAPTCHA_DURATION: i32 = 30;
// notification config
const HEADING: &str = "testing notifications get db postgres";
const MESSAGE: &str = "testing notifications get message db postgres";
// easy traffic pattern
const TRAFFIC_PATTERN: TrafficPattern = TrafficPattern {
@ -56,6 +59,13 @@ async fn everyting_works() {
},
];
const add_notification: AddNotification = AddNotification {
from: NAME,
to: NAME,
message: MESSAGE,
heading: HEADING,
};
let url = env::var("POSTGRES_DATABASE_URL").unwrap();
let pool_options = PgPoolOptions::new().max_connections(2);
let connection_options = ConnectionOptions::Fresh(Fresh { pool_options, url });
@ -74,5 +84,5 @@ async fn everyting_works() {
key: CAPTCHA_SECRET,
description: CAPTCHA_DESCRIPTION,
};
database_works(&db, &p, &c, &LEVELS, &TRAFFIC_PATTERN).await;
database_works(&db, &p, &c, &LEVELS, &TRAFFIC_PATTERN, &add_notification).await;
}