1use crate::{auth, AppState, Request, RequestExt as _};
2use async_trait::async_trait;
3use serde_json::json;
4use std::sync::Arc;
5
6pub fn add_routes(app: &mut tide::Server<Arc<AppState>>) {
7 app.at("/users/:github_login").get(get_user);
8 app.at("/users/:github_login/access_tokens")
9 .post(create_access_token);
10}
11
12async fn get_user(request: Request) -> tide::Result {
13 request.require_token().await?;
14
15 let user = request
16 .db()
17 .get_user_by_github_login(request.param("github_login")?)
18 .await?
19 .ok_or_else(|| surf::Error::from_str(404, "user not found"))?;
20
21 Ok(tide::Response::builder(200)
22 .body(tide::Body::from_json(&user)?)
23 .build())
24}
25
26async fn create_access_token(request: Request) -> tide::Result {
27 request.require_token().await?;
28
29 let user = request
30 .db()
31 .get_user_by_github_login(request.param("github_login")?)
32 .await?
33 .ok_or_else(|| surf::Error::from_str(404, "user not found"))?;
34 let token = auth::create_access_token(request.db(), user.id).await?;
35
36 Ok(tide::Response::builder(200)
37 .body(json!({"user_id": user.id, "access_token": token}))
38 .build())
39}
40
41#[async_trait]
42pub trait RequestExt {
43 async fn require_token(&self) -> tide::Result<()>;
44}
45
46#[async_trait]
47impl RequestExt for Request {
48 async fn require_token(&self) -> tide::Result<()> {
49 let token = self
50 .header("Authorization")
51 .and_then(|header| header.get(0))
52 .and_then(|header| header.as_str().strip_prefix("token "))
53 .ok_or_else(|| surf::Error::from_str(403, "invalid authorization header"))?;
54
55 if token == self.state().config.api_token {
56 Ok(())
57 } else {
58 Err(tide::Error::from_str(403, "invalid authorization token"))
59 }
60 }
61}