summaryrefslogtreecommitdiff
path: root/server/src/db.rs
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2025-01-20 23:08:11 +0100
committerTom Smeding <tom@tomsmeding.com>2025-01-20 23:08:11 +0100
commitc04ced6609a90ddebf15c6337c7761a0697a3497 (patch)
treebc8310665c30ef2c59c56bda3eea5d0b475f28db /server/src/db.rs
parent6dfa979b23c486005ef1185f0f0ca411fd235fd5 (diff)
server: Create new empty filesHEADmaster
Diffstat (limited to 'server/src/db.rs')
-rw-r--r--server/src/db.rs68
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())
+ }
+ }
+}