pub mod combinators;
use std::marker::PhantomData;
use async_trait::async_trait;
use reinhardt_di::{DiError, DiResult, Injectable, InjectionContext};
use reinhardt_http::AuthState;
use crate::core::{Permission, PermissionContext};
pub struct Guard<P: Permission>(PhantomData<P>);
impl<P: Permission> std::fmt::Debug for Guard<P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Guard").finish()
}
}
impl<P: Permission> Clone for Guard<P> {
fn clone(&self) -> Self {
Guard(PhantomData)
}
}
impl<P: Permission> Default for Guard<P> {
fn default() -> Self {
Guard(PhantomData)
}
}
#[cfg(feature = "params")]
#[async_trait]
impl<P> Injectable for Guard<P>
where
P: Permission + Default + Send + Sync + 'static,
{
async fn inject(ctx: &InjectionContext) -> DiResult<Self> {
let request = ctx.get_http_request().ok_or_else(|| {
DiError::NotFound(
"Guard: No HTTP request available in InjectionContext. \
Ensure the router is configured with .with_di_context()"
.to_string(),
)
})?;
let auth_state: AuthState = request
.extensions
.get::<AuthState>()
.unwrap_or_else(AuthState::anonymous);
let perm_ctx = PermissionContext {
request,
is_authenticated: auth_state.is_authenticated(),
is_admin: auth_state.is_admin(),
is_active: auth_state.is_active(),
user: None,
};
if P::default().has_permission(&perm_ctx).await {
Ok(Guard(PhantomData))
} else {
Err(DiError::Authorization("Permission denied".to_string()))
}
}
}
#[cfg(not(feature = "params"))]
#[async_trait]
impl<P> Injectable for Guard<P>
where
P: Permission + Default + Send + Sync + 'static,
{
async fn inject(_ctx: &InjectionContext) -> DiResult<Self> {
Err(DiError::NotFound(
"Guard requires the 'params' feature to be enabled".to_string(),
))
}
}
#[derive(Debug, Clone, Default)]
pub struct Public;
#[async_trait]
impl Injectable for Public {
async fn inject(_ctx: &InjectionContext) -> DiResult<Self> {
Ok(Public)
}
}
pub struct All<T>(PhantomData<T>);
impl<T> std::fmt::Debug for All<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("All").finish()
}
}
impl<T> Clone for All<T> {
fn clone(&self) -> Self {
All(PhantomData)
}
}
impl<T> Default for All<T> {
fn default() -> Self {
All(PhantomData)
}
}
pub struct Any<T>(PhantomData<T>);
impl<T> std::fmt::Debug for Any<T> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Any").finish()
}
}
impl<T> Clone for Any<T> {
fn clone(&self) -> Self {
Any(PhantomData)
}
}
impl<T> Default for Any<T> {
fn default() -> Self {
Any(PhantomData)
}
}
pub struct Not<P>(PhantomData<P>);
impl<P> std::fmt::Debug for Not<P> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Not").finish()
}
}
impl<P> Clone for Not<P> {
fn clone(&self) -> Self {
Not(PhantomData)
}
}
impl<P> Default for Not<P> {
fn default() -> Self {
Not(PhantomData)
}
}