use std::collections::BTreeMap;
use std::convert::Infallible;
use std::error::Error;
use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};
use crate::evaluation::DecisionKind;
use crate::model::{ActorRef, ExpiryCause, KeepsakeId, RelationId, SubjectRef};
#[cfg(any(test, feature = "test"))]
mod memory;
#[cfg(any(test, feature = "test"))]
pub use memory::{InMemoryAuditError, InMemoryAuditSink};
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuditEvent {
pub event_type: AuditEventType,
pub at: DateTime<Utc>,
pub actor: ActorRef,
pub keepsake_id: KeepsakeId,
pub subject: SubjectRef,
pub relation_id: RelationId,
pub decision: AuditDecision,
pub context: AuditContext,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum AuditEventType {
Apply,
DuplicateApply,
Revoke,
TimedExpiry,
FulfillmentExpiry,
}
impl AuditEventType {
#[must_use]
pub const fn as_str(self) -> &'static str {
match self {
Self::Apply => "apply",
Self::DuplicateApply => "duplicate_apply",
Self::Revoke => "revoke",
Self::TimedExpiry => "timed_expiry",
Self::FulfillmentExpiry => "fulfillment_expiry",
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
#[serde(tag = "type", rename_all = "snake_case")]
pub enum AuditDecision {
Applied {
duplicate_prevented: bool,
},
Revoked,
Expired {
cause: ExpiryCause,
},
Evaluated {
decision: DecisionKind,
},
}
#[derive(Debug, Clone, Default, PartialEq, Eq, Serialize, Deserialize)]
pub struct AuditContext {
pub attributes: BTreeMap<String, String>,
}
pub type AuditResult<T, E> = core::result::Result<T, E>;
pub trait AuditSink: Send + Sync {
type Error: Error + Send + Sync + 'static;
fn record(&self, event: AuditEvent) -> AuditResult<(), Self::Error>;
}
#[derive(Debug, Clone, Copy, Default)]
pub struct NoopAuditSink;
impl AuditSink for NoopAuditSink {
type Error = Infallible;
fn record(&self, _event: AuditEvent) -> AuditResult<(), Self::Error> {
Ok(())
}
}