use crate::models::{FamilyID, Membership}; use crate::services::families_service; use crate::services::login_token_service::LoginToken; use actix_web::dev::Payload; use actix_web::{FromRequest, HttpRequest}; use serde::Deserialize; use std::ops::Deref; #[derive(Debug)] pub struct FamilyInPath(Membership); #[derive(Debug)] pub struct FamilyInPathWithAdminMembership(FamilyInPath); impl FamilyInPath { async fn load_family_from_path(t: &LoginToken, id: FamilyID) -> anyhow::Result { Ok(Self(families_service::get_membership(id, t.user_id).await?)) } } impl From for Membership { fn from(val: FamilyInPath) -> Self { val.0 } } impl Deref for FamilyInPath { type Target = Membership; fn deref(&self) -> &Self::Target { &self.0 } } impl Deref for FamilyInPathWithAdminMembership { type Target = FamilyInPath; fn deref(&self) -> &Self::Target { &self.0 } } #[derive(Deserialize)] struct FamilyIdInPath { id: FamilyID, } impl FromRequest for FamilyInPath { type Error = actix_web::Error; type Future = futures_util::future::LocalBoxFuture<'static, Result>; fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { let req = req.clone(); Box::pin(async move { let token = LoginToken::extract(&req).await?; let family_id = actix_web::web::Path::::from_request(&req, &mut Payload::None) .await? .id; FamilyInPath::load_family_from_path(&token, family_id) .await .map_err(|e| { log::error!("Failed to extract family ID from URL! {}", e); actix_web::error::ErrorNotFound("Could not fetch family information!") }) }) } } impl FromRequest for FamilyInPathWithAdminMembership { type Error = actix_web::Error; type Future = futures_util::future::LocalBoxFuture<'static, Result>; fn from_request(req: &HttpRequest, _payload: &mut Payload) -> Self::Future { let req = req.clone(); Box::pin(async move { let family = FamilyInPath::extract(&req).await?; if !family.is_admin { log::error!( "The user {:?} attempted to perform restricted action on family {:?}!", family.user_id(), family.family_id() ); return Err(actix_web::error::ErrorUnauthorized( "You are not an administrator of this family!", )); } Ok(Self(family)) }) } }