2022-04-12 16:06:19 -06:00
|
|
|
use async_trait::async_trait;
|
|
|
|
use axum::{
|
2023-02-10 02:45:20 -07:00
|
|
|
extract::FromRequestParts,
|
2022-04-12 16:06:19 -06:00
|
|
|
response::IntoResponse,
|
|
|
|
routing::{get, post},
|
2023-02-10 02:45:20 -07:00
|
|
|
Router,
|
2022-04-12 16:06:19 -06:00
|
|
|
};
|
2021-04-20 10:07:11 -06:00
|
|
|
use eyre::Result;
|
2023-02-10 02:45:20 -07:00
|
|
|
use http::request::Parts;
|
2022-04-21 11:07:33 -06:00
|
|
|
use tower::ServiceBuilder;
|
|
|
|
use tower_http::trace::TraceLayer;
|
2021-04-20 14:53:07 -06:00
|
|
|
|
2023-02-15 01:54:09 -07:00
|
|
|
use super::{database::Database, handlers};
|
2022-03-13 13:53:49 -06:00
|
|
|
use crate::{models::User, settings::Settings};
|
2021-04-20 10:07:11 -06:00
|
|
|
|
2022-04-12 16:06:19 -06:00
|
|
|
#[async_trait]
|
2023-02-15 01:54:09 -07:00
|
|
|
impl<DB: Send + Sync> FromRequestParts<AppState<DB>> for User
|
|
|
|
where
|
|
|
|
DB: Database,
|
|
|
|
{
|
2022-04-12 16:06:19 -06:00
|
|
|
type Rejection = http::StatusCode;
|
|
|
|
|
2023-02-10 02:45:20 -07:00
|
|
|
async fn from_request_parts(
|
|
|
|
req: &mut Parts,
|
2023-02-15 01:54:09 -07:00
|
|
|
state: &AppState<DB>,
|
2023-02-10 02:45:20 -07:00
|
|
|
) -> Result<Self, Self::Rejection> {
|
2022-04-12 16:06:19 -06:00
|
|
|
let auth_header = req
|
2023-02-10 02:45:20 -07:00
|
|
|
.headers
|
2022-04-12 16:06:19 -06:00
|
|
|
.get(http::header::AUTHORIZATION)
|
|
|
|
.ok_or(http::StatusCode::FORBIDDEN)?;
|
|
|
|
let auth_header = auth_header
|
|
|
|
.to_str()
|
|
|
|
.map_err(|_| http::StatusCode::FORBIDDEN)?;
|
|
|
|
let (typ, token) = auth_header
|
|
|
|
.split_once(' ')
|
|
|
|
.ok_or(http::StatusCode::FORBIDDEN)?;
|
|
|
|
|
|
|
|
if typ != "Token" {
|
|
|
|
return Err(http::StatusCode::FORBIDDEN);
|
2021-04-20 10:07:11 -06:00
|
|
|
}
|
|
|
|
|
2023-02-10 02:45:20 -07:00
|
|
|
let user = state
|
2023-02-15 01:54:09 -07:00
|
|
|
.database
|
2022-04-12 16:06:19 -06:00
|
|
|
.get_session_user(token)
|
|
|
|
.await
|
|
|
|
.map_err(|_| http::StatusCode::FORBIDDEN)?;
|
2021-04-20 10:07:11 -06:00
|
|
|
|
2022-04-12 16:06:19 -06:00
|
|
|
Ok(user)
|
|
|
|
}
|
|
|
|
}
|
2021-04-20 10:07:11 -06:00
|
|
|
|
2022-04-12 16:06:19 -06:00
|
|
|
async fn teapot() -> impl IntoResponse {
|
|
|
|
(http::StatusCode::IM_A_TEAPOT, "☕")
|
|
|
|
}
|
2023-02-10 02:45:20 -07:00
|
|
|
|
|
|
|
#[derive(Clone)]
|
2023-02-15 01:54:09 -07:00
|
|
|
pub struct AppState<DB> {
|
|
|
|
pub database: DB,
|
2023-02-10 02:45:20 -07:00
|
|
|
pub settings: Settings,
|
|
|
|
}
|
|
|
|
|
2023-02-15 01:54:09 -07:00
|
|
|
pub fn router<DB: Database + Clone + Send + Sync + 'static>(
|
|
|
|
database: DB,
|
|
|
|
settings: Settings,
|
|
|
|
) -> Router {
|
2022-07-26 01:05:34 -06:00
|
|
|
let routes = Router::new()
|
2022-04-12 16:06:19 -06:00
|
|
|
.route("/", get(handlers::index))
|
|
|
|
.route("/sync/count", get(handlers::history::count))
|
|
|
|
.route("/sync/history", get(handlers::history::list))
|
2022-04-13 11:29:18 -06:00
|
|
|
.route("/sync/calendar/:focus", get(handlers::history::calendar))
|
2022-04-12 16:06:19 -06:00
|
|
|
.route("/history", post(handlers::history::add))
|
|
|
|
.route("/user/:username", get(handlers::user::get))
|
|
|
|
.route("/register", post(handlers::user::register))
|
2022-07-26 01:05:34 -06:00
|
|
|
.route("/login", post(handlers::user::login));
|
|
|
|
|
|
|
|
let path = settings.path.as_str();
|
|
|
|
if path.is_empty() {
|
|
|
|
routes
|
|
|
|
} else {
|
|
|
|
Router::new().nest(path, routes)
|
|
|
|
}
|
2023-02-10 02:45:20 -07:00
|
|
|
.fallback(teapot)
|
2023-02-15 01:54:09 -07:00
|
|
|
.with_state(AppState { database, settings })
|
2023-02-10 02:45:20 -07:00
|
|
|
.layer(ServiceBuilder::new().layer(TraceLayer::new_for_http()))
|
2021-04-20 10:07:11 -06:00
|
|
|
}
|