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(¶ms.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// }