api.rs

  1use crate::{
  2    db::{Db, User, UserId},
  3    AppState, Result,
  4};
  5use anyhow::anyhow;
  6use axum::{
  7    body::Body,
  8    extract::Path,
  9    http::{Request, StatusCode},
 10    response::{IntoResponse, Response},
 11    routing::{get, put},
 12    Json, Router,
 13};
 14use serde::Deserialize;
 15use std::sync::Arc;
 16
 17pub fn add_routes(router: Router<Body>, app: Arc<AppState>) -> Router<Body> {
 18    router
 19        .route("/users", {
 20            let app = app.clone();
 21            get(move |req| get_users(req, app))
 22        })
 23        .route("/users", {
 24            let app = app.clone();
 25            get(move |params| create_user(params, app))
 26        })
 27        .route("/users/:id", {
 28            let app = app.clone();
 29            put(move |user_id, params| update_user(user_id, params, app))
 30        })
 31}
 32
 33// pub fn add_routes(app: &mut tide::Server<Arc<AppState>>) {
 34//     app.at("/users").get(get_users);
 35//     app.at("/users").post(create_user);
 36//     app.at("/users/:id").put(update_user);
 37//     app.at("/users/:id").delete(destroy_user);
 38//     app.at("/users/:github_login").get(get_user);
 39//     app.at("/users/:github_login/access_tokens")
 40//         .post(create_access_token);
 41// }
 42
 43async fn get_users(request: Request<Body>, app: Arc<AppState>) -> Result<Json<Vec<User>>> {
 44    // request.require_token().await?;
 45
 46    let users = app.db.get_all_users().await?;
 47    Ok(Json(users))
 48}
 49
 50#[derive(Deserialize)]
 51struct CreateUser {
 52    github_login: String,
 53    admin: bool,
 54}
 55
 56async fn create_user(Json(params): Json<CreateUser>, app: Arc<AppState>) -> Result<Json<User>> {
 57    let user_id = app
 58        .db
 59        .create_user(&params.github_login, params.admin)
 60        .await?;
 61
 62    let user = app
 63        .db
 64        .get_user_by_id(user_id)
 65        .await?
 66        .ok_or_else(|| anyhow!("couldn't find the user we just created"))?;
 67
 68    Ok(Json(user))
 69}
 70
 71#[derive(Deserialize)]
 72struct UpdateUser {
 73    admin: bool,
 74}
 75
 76async fn update_user(
 77    Path(user_id): Path<i32>,
 78    Json(params): Json<UpdateUser>,
 79    app: Arc<AppState>,
 80) -> Result<impl IntoResponse> {
 81    let user_id = UserId(user_id);
 82    app.db.set_user_is_admin(user_id, params.admin).await?;
 83    Ok(())
 84}
 85
 86// async fn update_user(mut request: Request) -> tide::Result {
 87//     request.require_token().await?;
 88
 89//     #[derive(Deserialize)]
 90//     struct Params {
 91//         admin: bool,
 92//     }
 93
 94//     request
 95//         .db()
 96//         .set_user_is_admin(user_id, params.admin)
 97//         .await?;
 98
 99//     Ok(tide::Response::builder(StatusCode::Ok).build())
100// }
101
102// async fn destroy_user(request: Request) -> tide::Result {
103//     request.require_token().await?;
104//     let user_id = UserId(
105//         request
106//             .param("id")?
107//             .parse::<i32>()
108//             .map_err(|error| surf::Error::from_str(StatusCode::BadRequest, error.to_string()))?,
109//     );
110
111//     request.db().destroy_user(user_id).await?;
112
113//     Ok(tide::Response::builder(StatusCode::Ok).build())
114// }
115
116// async fn create_access_token(request: Request) -> tide::Result {
117//     request.require_token().await?;
118
119//     let user = request
120//         .db()
121//         .get_user_by_github_login(request.param("github_login")?)
122//         .await?
123//         .ok_or_else(|| surf::Error::from_str(StatusCode::NotFound, "user not found"))?;
124
125//     #[derive(Deserialize)]
126//     struct QueryParams {
127//         public_key: String,
128//         impersonate: Option<String>,
129//     }
130
131//     let query_params: QueryParams = request.query().map_err(|_| {
132//         surf::Error::from_str(StatusCode::UnprocessableEntity, "invalid query params")
133//     })?;
134
135//     let mut user_id = user.id;
136//     if let Some(impersonate) = query_params.impersonate {
137//         if user.admin {
138//             if let Some(impersonated_user) =
139//                 request.db().get_user_by_github_login(&impersonate).await?
140//             {
141//                 user_id = impersonated_user.id;
142//             } else {
143//                 return Ok(tide::Response::builder(StatusCode::UnprocessableEntity)
144//                     .body(format!(
145//                         "Can't impersonate non-existent user {}",
146//                         impersonate
147//                     ))
148//                     .build());
149//             }
150//         } else {
151//             return Ok(tide::Response::builder(StatusCode::Unauthorized)
152//                 .body(format!(
153//                     "Can't impersonate user {} because the real user isn't an admin",
154//                     impersonate
155//                 ))
156//                 .build());
157//         }
158//     }
159
160//     let access_token = auth::create_access_token(request.db().as_ref(), user_id).await?;
161//     let encrypted_access_token =
162//         auth::encrypt_access_token(&access_token, query_params.public_key.clone())?;
163
164//     Ok(tide::Response::builder(StatusCode::Ok)
165//         .body(json!({"user_id": user_id, "encrypted_access_token": encrypted_access_token}))
166//         .build())
167// }
168
169// #[async_trait]
170// pub trait RequestExt {
171//     async fn require_token(&self) -> tide::Result<()>;
172// }
173
174// #[async_trait]
175// impl RequestExt for Request {
176//     async fn require_token(&self) -> tide::Result<()> {
177//         let token = self
178//             .header("Authorization")
179//             .and_then(|header| header.get(0))
180//             .and_then(|header| header.as_str().strip_prefix("token "))
181//             .ok_or_else(|| surf::Error::from_str(403, "invalid authorization header"))?;
182
183//         if token == self.state().config.api_token {
184//             Ok(())
185//         } else {
186//             Err(tide::Error::from_str(403, "invalid authorization token"))
187//         }
188//     }
189// }