summaryrefslogtreecommitdiffstats
path: root/src/routes/user.rs
diff options
context:
space:
mode:
authorToby Vincent <tobyv@tobyvin.dev>2024-04-02 19:07:23 -0500
committerToby Vincent <tobyv@tobyvin.dev>2024-04-02 19:07:23 -0500
commit9034c74cd36cdf3615dd80dc975500d235cebfcc (patch)
treebc6cfdb3c70c790e45e36a1a3977cf88ce4337c2 /src/routes/user.rs
parentd3a09372b5b945a609cce5e28c4d4233e3b134e8 (diff)
refactor: move routes into individual modules
Diffstat (limited to 'src/routes/user.rs')
-rw-r--r--src/routes/user.rs106
1 files changed, 106 insertions, 0 deletions
diff --git a/src/routes/user.rs b/src/routes/user.rs
new file mode 100644
index 0000000..71ed9a0
--- /dev/null
+++ b/src/routes/user.rs
@@ -0,0 +1,106 @@
+use std::sync::Arc;
+
+use axum::{extract::State, response::IntoResponse, Json};
+use axum_extra::routing::TypedPath;
+use serde::Deserialize;
+
+use crate::{model::User, state::AppState, Error};
+
+#[derive(Debug, Deserialize, TypedPath)]
+#[typed_path("/api/user/:uuid")]
+pub struct UserUuid {
+ pub uuid: uuid::Uuid,
+}
+
+impl UserUuid {
+ /// Get a user with a specific `uuid`
+ #[tracing::instrument]
+ pub async fn get(self, State(state): State<Arc<AppState>>) -> impl IntoResponse {
+ sqlx::query_as!(User, "SELECT * FROM users WHERE uuid = $1", self.uuid)
+ .fetch_optional(&state.pool)
+ .await?
+ .ok_or_else(|| Error::UserNotFound)
+ .map(Json)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use super::*;
+
+ use axum::{
+ body::Body,
+ http::{Request, StatusCode},
+ };
+ use http_body_util::BodyExt;
+ use sqlx::PgPool;
+ use tower::ServiceExt;
+
+ use crate::init_router;
+
+ const JWT_SECRET: &str = "test-jwt-secret-token";
+ const JWT_MAX_AGE: time::Duration = time::Duration::HOUR;
+
+ #[sqlx::test]
+ async fn test_user_not_found(pool: PgPool) -> Result<(), Error> {
+ let state = Arc::new(AppState {
+ pool,
+ jwt_secret: JWT_SECRET.to_string(),
+ jwt_max_age: JWT_MAX_AGE,
+ });
+ let router = init_router(state.clone());
+
+ let user = User {
+ uuid: uuid::uuid!("4c14f795-86f0-4361-a02f-0edb966fb145"),
+ name: "Arthur Dent".to_string(),
+ email: "adent@earth.sol".to_string(),
+ ..Default::default()
+ };
+
+ let request = Request::builder()
+ .uri(format!("/api/user/{}", user.uuid))
+ .body(Body::empty())?;
+
+ let response = router.oneshot(request).await.unwrap();
+
+ assert_eq!(StatusCode::NOT_FOUND, response.status());
+
+ Ok(())
+ }
+
+ #[sqlx::test(fixtures(path = "../../fixtures", scripts("users")))]
+ async fn test_user_ok(pool: PgPool) -> Result<(), Error> {
+ let state = Arc::new(AppState {
+ pool,
+ jwt_secret: JWT_SECRET.to_string(),
+ jwt_max_age: JWT_MAX_AGE,
+ });
+ let router = init_router(state.clone());
+
+ let user = User {
+ uuid: uuid::uuid!("4c14f795-86f0-4361-a02f-0edb966fb145"),
+ name: "Arthur Dent".to_string(),
+ email: "adent@earth.sol".to_string(),
+ ..Default::default()
+ };
+
+ let request = Request::builder()
+ .uri(format!("/api/user/{}", user.uuid))
+ .body(Body::empty())?;
+
+ let response = router.oneshot(request).await.unwrap();
+
+ assert_eq!(StatusCode::OK, response.status());
+
+ let body_bytes = response.into_body().collect().await?.to_bytes();
+ let User {
+ uuid, name, email, ..
+ } = serde_json::from_slice(&body_bytes)?;
+
+ assert_eq!(user.uuid, uuid);
+ assert_eq!(user.name, name);
+ assert_eq!(user.email, email);
+
+ Ok(())
+ }
+}