From 130669793dfb77b286a26a373378b4d1f2be837c Mon Sep 17 00:00:00 2001 From: Ashelyn Rose Date: Sat, 26 Oct 2024 02:20:32 -0400 Subject: Very basic rocket db state and session lookup (with hardcoded session id) --- src/api/guards/mod.rs | 1 + src/api/guards/session.rs | 25 ++++++++++++++ src/api/mod.rs | 2 ++ src/api/routes/mod.rs | 1 + src/api/routes/test.rs | 9 +++++ src/db/mod.rs | 1 + src/db/models/auth.rs | 84 +++++++++++++++++++++++++++++++++++++++++++++++ src/db/models/mod.rs | 1 + src/jobs/startup.rs | 27 ++++++++++----- src/main.rs | 21 ++++++++++-- 10 files changed, 162 insertions(+), 10 deletions(-) create mode 100644 src/api/guards/mod.rs create mode 100644 src/api/guards/session.rs create mode 100644 src/api/mod.rs create mode 100644 src/api/routes/mod.rs create mode 100644 src/api/routes/test.rs create mode 100644 src/db/mod.rs create mode 100644 src/db/models/auth.rs create mode 100644 src/db/models/mod.rs (limited to 'src') diff --git a/src/api/guards/mod.rs b/src/api/guards/mod.rs new file mode 100644 index 0000000..f52f1c4 --- /dev/null +++ b/src/api/guards/mod.rs @@ -0,0 +1 @@ +pub mod session; diff --git a/src/api/guards/session.rs b/src/api/guards/session.rs new file mode 100644 index 0000000..ccd40a2 --- /dev/null +++ b/src/api/guards/session.rs @@ -0,0 +1,25 @@ +use std::str::FromStr; + +use rocket::{http::Status, outcome::Outcome, request::{self, Request, FromRequest}}; +use sqlx::PgPool; +use uuid::Uuid; +use crate::db::models::auth::LoginSession; + + +#[rocket::async_trait] +impl<'r> FromRequest<'r> for LoginSession { + type Error = (); + + async fn from_request(req: &'r Request<'_>) -> request::Outcome { + // At the moment just always look up this one for initial testing + let hardcoded_uuid = "557621dd-b98e-409a-9ce7-25b5004caa42"; + + if let Some(db) = req.rocket().state::() { + if let Some(session) = LoginSession::lookup(&db, Uuid::from_str(hardcoded_uuid).unwrap()).await { + return Outcome::Success(session); + } + } + + Outcome::Error((Status::InternalServerError, ())) + } +} diff --git a/src/api/mod.rs b/src/api/mod.rs new file mode 100644 index 0000000..47e142d --- /dev/null +++ b/src/api/mod.rs @@ -0,0 +1,2 @@ +pub mod routes; +pub mod guards; diff --git a/src/api/routes/mod.rs b/src/api/routes/mod.rs new file mode 100644 index 0000000..7b788c2 --- /dev/null +++ b/src/api/routes/mod.rs @@ -0,0 +1 @@ +pub mod test; diff --git a/src/api/routes/test.rs b/src/api/routes/test.rs new file mode 100644 index 0000000..718c634 --- /dev/null +++ b/src/api/routes/test.rs @@ -0,0 +1,9 @@ +use rocket::get; +use rocket::serde::json::Json; + +use crate::db::models::auth::LoginSession; + +#[get("/test")] +pub fn testroute(session: LoginSession) -> Json { + Json(session) +} diff --git a/src/db/mod.rs b/src/db/mod.rs new file mode 100644 index 0000000..c446ac8 --- /dev/null +++ b/src/db/mod.rs @@ -0,0 +1 @@ +pub mod models; diff --git a/src/db/models/auth.rs b/src/db/models/auth.rs new file mode 100644 index 0000000..b4fa070 --- /dev/null +++ b/src/db/models/auth.rs @@ -0,0 +1,84 @@ +use rocket::serde::{self, Serialize}; +use uuid::Uuid; +use time::OffsetDateTime; +use sqlx::{postgres::types::PgInterval, Pool, Postgres}; + +#[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] +pub struct User { + uuid: Uuid, + email: String, + username: String, + display_name: Option, + password_hash: Option, + #[serde(with="time::serde::rfc3339")] + time_created: OffsetDateTime, + #[serde(with="time::serde::rfc3339::option")] + time_password_changed: Option, + #[serde(with="time::serde::rfc3339::option")] + time_email_confirmed: Option +} + +#[derive(Serialize, Debug)] +#[serde(crate = "rocket::serde")] +pub struct LoginSession { + uuid: Uuid, + #[serde(with="time::serde::rfc3339")] + time_created: OffsetDateTime, + #[serde(with="time::serde::rfc3339")] + time_last_active: OffsetDateTime, + #[serde(skip_serializing)] + duration: PgInterval, + #[serde(with="time::serde::rfc3339::option")] + time_logged_out: Option, + ip_address: String, + user_agent: String, + referer: String, + user: User +} + +impl LoginSession { + pub async fn lookup(connection: &Pool::, uuid: Uuid) -> Option { + joinrs::query_parsed!( + connection = connection, + query = r#" + select + login_session.*, + user_uuid, + user_display_name, + user_password_hash, + user_time_created, + user_time_password_changed, + user_time_email_confirmed, + user_username::text as username, + user_email::text as email + from phtx.login_session + left join phtx."user" + on login_session_user_uuid = user_uuid + where login_session_time_last_active + login_session_duration >= now() + and login_session_uuid = $1 + "#, + params = [uuid], + return_type = LoginSession { + uuid: login_session_uuid, + time_created: login_session_time_created, + time_last_active: login_session_time_last_active, + duration: login_session_duration, + time_logged_out: login_session_time_logged_out, + ip_address: login_session_ip_address, + user_agent: login_session_user_agent, + referer: login_session_referer, + user: User { + uuid: user_uuid, + email: email, + username: username, + display_name: user_display_name, + password_hash: user_password_hash, + time_created: user_time_created, + time_password_changed: user_time_password_changed, + time_email_confirmed: user_time_email_confirmed + } + } + ).ok() + } +} diff --git a/src/db/models/mod.rs b/src/db/models/mod.rs new file mode 100644 index 0000000..0e4a05d --- /dev/null +++ b/src/db/models/mod.rs @@ -0,0 +1 @@ +pub mod auth; diff --git a/src/jobs/startup.rs b/src/jobs/startup.rs index 05eaa94..6ca1849 100644 --- a/src/jobs/startup.rs +++ b/src/jobs/startup.rs @@ -1,16 +1,27 @@ use tokio::runtime; -use std::{fs, path::Path}; +use std::{fs, path::Path, thread}; +use tokio::sync::mpsc::channel; use sqlx::{migrate::Migrator, Connection, PgConnection, Row}; -pub fn run_startup_jobs() { - let runtime = runtime::Builder::new_current_thread() - .enable_all() - .build().unwrap(); +type JobResult = Result<(), ()>; - runtime.block_on(async { - migrate_db().await - }) +pub async fn run_startup_jobs() { + let (tx, mut rx) = channel::(1); + + thread::spawn(move || { + let runtime = runtime::Builder::new_current_thread() + .enable_all() + .build().unwrap(); + + runtime.block_on(async { + migrate_db().await; + + tx.send(Ok(())).await.unwrap() + }); + }); + + rx.recv().await; } async fn migrate_db() { diff --git a/src/main.rs b/src/main.rs index ba41b2d..01f6eed 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,6 +1,23 @@ +use rocket::routes; +use sqlx::PgPool; + mod jobs; +mod db; +mod api; -fn main() { +#[rocket::main] +async fn main() -> Result<(), rocket::Error> { println!("{}_{} starting up", env!("CARGO_PKG_NAME"), env!("CARGO_PKG_VERSION")); - jobs::startup::run_startup_jobs(); + + jobs::startup::run_startup_jobs().await; + + let db_pool = PgPool::connect("postgres://localhost/photoxide").await.unwrap(); + + let _rocket = rocket::build() + .manage(db_pool) + .mount("/", routes![api::routes::test::testroute]) + .launch() + .await?; + + Ok(()) } -- cgit 1.4.1