diff --git a/.env b/.env new file mode 100644 index 0000000..a223ac6 --- /dev/null +++ b/.env @@ -0,0 +1 @@ +DATABASE_URL=sqlite://sqlite.db diff --git a/src/db.rs b/src/db.rs index eadba3d..dd7d1b5 100644 --- a/src/db.rs +++ b/src/db.rs @@ -9,11 +9,20 @@ use crate::secrets::UserToken; // TODO: allow configuring this via envar const DB_URI_DEFAULT: &str = "sqlite://sqlite.db"; -const TABLE_USER_TOKENS: &str = "user_tokens"; +// TODO: check again if it's possible to pass this as a parameter to query! +// const TABLE_USER_TOKENS: &str = "user_tokens"; pub enum UserTokenEntry { - Valid(UserToken, time::Time, time::Time), - Invalid(UserToken, time::Time, time::Time), + Valid( + UserToken, + time::OffsetDateTime, + Option, + ), + Invalid( + UserToken, + time::OffsetDateTime, + Option, + ), } pub trait Database { @@ -47,8 +56,8 @@ impl SqliteDatabase { #[instrument] pub async fn init(&mut self) { - query(&format!( - "CREATE TABLE IF NOT EXISTS {TABLE_USER_TOKENS} ( + query!( + "CREATE TABLE IF NOT EXISTS user_tokens ( id INTEGER PRIMARY KEY AUTOINCREMENT, username VARCHAR(255) NOT NULL, token NCHAR(30) NOT NULL, @@ -56,7 +65,7 @@ impl SqliteDatabase { created DATETIME NOT NULL, last_used DATETIME )" - )) + ) .execute(&mut self.conn) .await .expect("Failed to initialize table user_tokens"); @@ -66,38 +75,49 @@ impl SqliteDatabase { impl Database for SqliteDatabase { #[instrument] async fn get_token(&mut self, username: &str) -> Result, sqlx::Error> { - let row: Option<(String, bool, time::Time, time::Time)> = query_as( + struct TokenRow { + token: String, + valid: bool, + created: time::OffsetDateTime, + last_used: Option, + } + let row = query_as!( + TokenRow, "SELECT token, valid, created, last_used FROM user_tokens - WHERE username = ? + WHERE username = $1 ORDER BY created DESC", + username ) - .bind(username) + // .bind(username) .fetch_optional(&mut self.conn) .await?; - Ok(row.map(|row| match row { - (token_str, true, created, last_used) => { - UserTokenEntry::Valid(UserToken::from(token_str), created, last_used) - } - - (token_str, false, created, last_used) => { - UserTokenEntry::Invalid(UserToken::from(token_str), created, last_used) - } - })) + Ok(row.map( + |TokenRow { + token, + valid, + created, + last_used, + }| match valid { + true => UserTokenEntry::Valid(UserToken::from(token), created, last_used), + false => UserTokenEntry::Invalid(UserToken::from(token), created, last_used), + }, + )) } #[instrument] async fn save_token(&mut self, username: &str, token: &UserToken) -> Result<(), sqlx::Error> { - query(&format!( - "INSERT INTO {TABLE_USER_TOKENS} + let token_inner = token.0.expose_secret(); + query!( + "INSERT INTO user_tokens (username, token, created, valid) VALUES - (?, ?, DATETIME('NOW'), TRUE) + ($1, $2, DATETIME('NOW'), TRUE) ", - )) - .bind(username) - .bind(token.0.expose_secret()) + username, + token_inner + ) .execute(&mut self.conn) .await?;