diff options
author | Tom Smeding <tom@tomsmeding.com> | 2025-01-20 23:08:11 +0100 |
---|---|---|
committer | Tom Smeding <tom@tomsmeding.com> | 2025-01-20 23:08:11 +0100 |
commit | c04ced6609a90ddebf15c6337c7761a0697a3497 (patch) | |
tree | bc8310665c30ef2c59c56bda3eea5d0b475f28db /server/src/db.rs | |
parent | 6dfa979b23c486005ef1185f0f0ca411fd235fd5 (diff) |
Diffstat (limited to 'server/src/db.rs')
-rw-r--r-- | server/src/db.rs | 68 |
1 files changed, 62 insertions, 6 deletions
diff --git a/server/src/db.rs b/server/src/db.rs index bad748d..9efb130 100644 --- a/server/src/db.rs +++ b/server/src/db.rs @@ -20,6 +20,7 @@ use rand::RngCore; use argon2::password_hash::rand_core::OsRng; use crate::constants::*; +use crate::path::Path; use crate::util::base64_encode; async fn initialise_schema(conn: &mut SqliteConnection) { @@ -32,7 +33,9 @@ async fn initialise_schema(conn: &mut SqliteConnection) { } } -pub async fn open() -> SqliteConnection { +pub type DB = Arc<Mutex<SqliteConnection>>; + +pub async fn open() -> DB { let opts = SqliteConnectOptions::new() .filename(DB_FILE_NAME) .create_if_missing(true) @@ -51,7 +54,7 @@ pub async fn open() -> SqliteConnection { Ok(row) => { let ver: i64 = row.get(0); if ver == DB_SCHEMA_VERSION { - conn + Arc::new(Mutex::new(conn)) } else { eprintln!("Error: Database schema version {ver} but application schema version {DB_SCHEMA_VERSION}"); process::exit(1); @@ -61,13 +64,11 @@ pub async fn open() -> SqliteConnection { eprintln!("Error: Failed querying database meta version: {err}"); eprintln!("Initialising schema."); initialise_schema(&mut conn).await; - conn + Arc::new(Mutex::new(conn)) }, } } -pub type DB = Arc<Mutex<SqliteConnection>>; - pub async fn register_account(db: DB, username: &str, passhash: &str) -> Result<(), String> { let mut conn = db.lock().await; match sqlx::query("insert into Users (username, passhash) values ($1, $2)") @@ -109,7 +110,7 @@ pub async fn create_login_token(db: DB, username: &str) -> Result<String, ()> { let mut conn = db.lock().await; let now = current_time(); let token = generate_login_token(); - match sqlx::query("insert into Logins (user, token, expire) values ($1, $2, $3)") + match sqlx::query("insert into Logins (user, token, expire) values ((select id from Users where username = $1), $2, $3)") .bind(username) .bind(&token) .bind(now + LOGIN_TOKEN_EXPIRE_SECS) @@ -162,3 +163,58 @@ pub async fn maybe_refresh_token(db: DB, token: &str) -> Result<(), String> { } } } + +#[derive(Copy, Clone)] +pub struct UserId { + id: i64, +} + +pub async fn check_login(db: DB, token: &str) -> Result<UserId, ()> { + let mut conn = db.lock().await; + match sqlx::query("select user from Logins where token = $1") + .bind(token) + .fetch_optional(conn.deref_mut()).await { + Ok(Some(row)) => Ok(UserId { id: row.get(0) }), + Ok(None) => Err(()), + Err(err) => { + eprintln!("check_login: err = {err}"); + Err(()) + } + } +} + +/// Returns ID of the file. +pub async fn file_lookup(db: DB, user: UserId, path: &Path<'_>) -> Option<i64> { + let mut conn = db.lock().await; + match sqlx::query("select id from Files where owner = $1 and path = $2") + .bind(user.id) + .bind(path.join()) + .fetch_optional(conn.deref_mut()).await { + Ok(Some(row)) => Some(row.get(0)), + Ok(None) => None, + Err(err) => { + eprintln!("file_exists: err = {err}"); + None + } + } +} + +/// Returns ID of created file. +pub async fn file_create_empty(db: DB, user: UserId, path: &Path<'_>) -> Result<i64, String> { + if let Some((parent, _)) = path.without_last() { + if file_lookup(db.clone(), user, &parent).await.is_none() { + return Err("Parent does not exist".to_string()); + } + } + + let mut conn = db.lock().await; + match sqlx::query("insert into Files (owner, path) values ($1, $2)") + .bind(user.id) + .bind(path.join()) + .execute(conn.deref_mut()).await { + Ok(res) => Ok(res.last_insert_rowid()), + Err(_) => { // let's assume it was a collision + Err("File already exists".to_string()) + } + } +} |