summaryrefslogtreecommitdiffstats
path: root/src/routes/user.rs
blob: 71ed9a0b049008b677d13f214c303ca3b95cd64e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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(())
    }
}