use aauth_protocol::{Budget, Jwk};
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
#[derive(Clone, Debug, Default, PartialEq, Serialize, Deserialize)]
pub struct Person {
pub id: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub name: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub email: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub tenant: Option<String>,
#[serde(flatten)]
pub extra: Map<String, Value>,
}
impl Person {
pub fn new(id: impl Into<String>) -> Self {
Self {
id: id.into(),
..Default::default()
}
}
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Agent {
pub id: String,
pub provider: String,
pub jkt: String,
pub jwk: Jwk,
pub exp: i64,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ApprovalKind {
Mission,
AuthToken,
Completion,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum ApprovalStatus {
Pending,
Approved,
Denied,
Collected,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Approval {
pub id: String,
pub kind: ApprovalKind,
pub status: ApprovalStatus,
pub agent: Agent,
pub person: Person,
pub approver: Person,
pub description: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub summary: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mission_s256: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub resource: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub budget: Option<Budget>,
#[serde(default)]
pub grant: Map<String, Value>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decided_budget: Option<Budget>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decided_by: Option<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decided_at: Option<i64>,
pub created_at: i64,
pub expires_at: i64,
pub tenant: String,
}
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct LogEntry {
pub at: i64,
pub entry: String,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Mission {
pub s256: String,
pub mission: String,
pub agent_id: String,
pub person: Person,
pub resources: Vec<String>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub budget: Option<Budget>,
pub spent: u64,
#[serde(default)]
pub log: Vec<LogEntry>,
pub expires_at: i64,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub completed_at: Option<i64>,
pub tenant: String,
}
impl Mission {
pub fn is_live(&self, now: i64) -> bool {
self.completed_at.is_none() && now < self.expires_at
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
pub enum Verdict {
Approved,
Denied,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Decision {
pub status: Verdict,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub budget: Option<Budget>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub decided_by: Option<String>,
}
impl Decision {
pub fn approve() -> Self {
Self {
status: Verdict::Approved,
budget: None,
decided_by: None,
}
}
pub fn deny() -> Self {
Self {
status: Verdict::Denied,
budget: None,
decided_by: None,
}
}
pub fn with_budget(mut self, budget: Budget) -> Self {
self.budget = Some(budget);
self
}
pub fn by(mut self, decided_by: impl Into<String>) -> Self {
self.decided_by = Some(decided_by.into());
self
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
#[serde(rename_all = "snake_case")]
#[non_exhaustive]
pub enum IssuedKind {
PersonToken,
AuthToken,
}
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
pub struct Issued {
pub kind: IssuedKind,
pub agent: Agent,
pub person: Person,
pub resource: String,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub mission: Option<Mission>,
#[serde(default, skip_serializing_if = "Option::is_none")]
pub budget: Option<Budget>,
}