use std::fmt;
#[derive(Debug, Clone)]
pub enum AuthResponse {
Allow,
Deny {
message: Option<String>,
status: u16,
},
}
impl AuthResponse {
pub fn allow() -> Self {
Self::Allow
}
pub fn deny(message: impl Into<String>) -> Self {
Self::Deny {
message: Some(message.into()),
status: 403,
}
}
pub fn deny_silent() -> Self {
Self::Deny {
message: None,
status: 403,
}
}
pub fn deny_as_not_found() -> Self {
Self::Deny {
message: None,
status: 404,
}
}
pub fn deny_with_status(message: impl Into<String>, status: u16) -> Self {
Self::Deny {
message: Some(message.into()),
status,
}
}
pub fn allowed(&self) -> bool {
matches!(self, Self::Allow)
}
pub fn denied(&self) -> bool {
matches!(self, Self::Deny { .. })
}
pub fn message(&self) -> Option<&str> {
match self {
Self::Deny { message, .. } => message.as_deref(),
Self::Allow => None,
}
}
pub fn status(&self) -> u16 {
match self {
Self::Allow => 200,
Self::Deny { status, .. } => *status,
}
}
}
impl From<bool> for AuthResponse {
fn from(allowed: bool) -> Self {
if allowed {
Self::Allow
} else {
Self::Deny {
message: None,
status: 403,
}
}
}
}
impl fmt::Display for AuthResponse {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Allow => write!(f, "Allowed"),
Self::Deny {
message: Some(msg), ..
} => write!(f, "Denied: {msg}"),
Self::Deny { message: None, .. } => write!(f, "Denied"),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_allow() {
let response = AuthResponse::allow();
assert!(response.allowed());
assert!(!response.denied());
assert_eq!(response.status(), 200);
}
#[test]
fn test_deny_with_message() {
let response = AuthResponse::deny("Not authorized");
assert!(!response.allowed());
assert!(response.denied());
assert_eq!(response.message(), Some("Not authorized"));
assert_eq!(response.status(), 403);
}
#[test]
fn test_deny_silent() {
let response = AuthResponse::deny_silent();
assert!(response.denied());
assert_eq!(response.message(), None);
assert_eq!(response.status(), 403);
}
#[test]
fn test_deny_as_not_found() {
let response = AuthResponse::deny_as_not_found();
assert!(response.denied());
assert_eq!(response.status(), 404);
}
#[test]
fn test_from_bool_true() {
let response: AuthResponse = true.into();
assert!(response.allowed());
}
#[test]
fn test_from_bool_false() {
let response: AuthResponse = false.into();
assert!(response.denied());
}
#[test]
fn test_display() {
assert_eq!(AuthResponse::allow().to_string(), "Allowed");
assert_eq!(
AuthResponse::deny("Forbidden").to_string(),
"Denied: Forbidden"
);
assert_eq!(AuthResponse::deny_silent().to_string(), "Denied");
}
}