use crate::auth::MaybeCurrentUser;
use idkthings_core_macros::entity;
use mongodb::bson::doc;
use mongodb::Database;
use poem::{Endpoint, Middleware, Request, Result};
use serde::{Deserialize, Serialize};
use uuid::Uuid;
pub struct MaybeCurrentUserMiddleware {
pub database: Database,
}
impl<E: Endpoint> Middleware<E> for MaybeCurrentUserMiddleware {
type Output = MaybeCurrentUserMiddlewareImpl<E>;
fn transform(&self, ep: E) -> Self::Output {
MaybeCurrentUserMiddlewareImpl {
ep,
database: self.database.clone(),
}
}
}
pub struct MaybeCurrentUserMiddlewareImpl<E> {
ep: E,
database: Database,
}
#[poem::async_trait]
impl<E: Endpoint> Endpoint for MaybeCurrentUserMiddlewareImpl<E> {
type Output = E::Output;
async fn call(&self, mut req: Request) -> Result<Self::Output> {
let maybe_current_user = if let Some(value) = req
.headers()
.get("Authorization")
.and_then(|value| value.to_str().ok())
{
let token = value.to_string();
let current_user = maybe_current_user_from_token(&token, self.database.clone()).await;
current_user
} else {
MaybeCurrentUser(None)
};
req.extensions_mut()
.insert::<MaybeCurrentUser>(maybe_current_user);
self.ep.call(req).await
}
}
async fn maybe_current_user_from_token(token: &str, database: Database) -> MaybeCurrentUser {
let token = token.trim_start_matches("Bearer ");
let client = reqwest::Client::new();
let user_info: UserInfo = client
.get("https://idkthings-dev.au.auth0.com/userinfo")
.header("Authorization", format!("Bearer {}", token))
.send()
.await
.unwrap()
.json()
.await
.unwrap();
let user: Option<User> = database
.collection("users")
.find_one(doc! { "email": &user_info.email }, None)
.await
.unwrap();
MaybeCurrentUser(user.map(|user| user.into()))
}
#[derive(Debug, Serialize, Deserialize)]
struct UserInfo {
pub email: String,
}
#[entity]
pub struct User {
pub id: Uuid,
pub email: String,
}