use super::super::Lifecycle;
use super::{SiteAct, SiteChange, SiteError};
use crate::auth_lys::live::drafts::DraftLimits;
use crate::auth_lys::live::{HttpLysAsk, PreparedAct};
use crate::auth_lys::lys_pass_adapter::LiveAnswer;
#[derive(Clone, Copy)]
pub struct VerifiedContext<'a> {
pub lifecycle: &'a Lifecycle,
pub pass: &'a lys_pass::VerifiedPass,
pub token: &'a str,
pub live: &'a HttpLysAsk,
pub at_ms: u64,
pub decisions: crate::config::types::Decisions,
pub warned: &'a crate::auth_lys::advisory::Warned,
pub limits: DraftLimits,
}
pub fn hold_verified(
context: VerifiedContext<'_>,
operation: &str,
target: &str,
change: SiteChange,
) -> Result<serde_json::Value, SiteError> {
let VerifiedContext {
lifecycle,
pass,
token,
live,
at_ms,
decisions,
warned,
limits: draft_limits,
} = context;
let bindings = lifecycle.site_bindings()?;
let limits = &bindings.limits;
if pass.claims().exp <= at_ms / 1000 {
return Err(SiteError::Pass("pass_expired".into()));
}
let act = SiteAct::prepare(target.into(), change, pass)?;
let words = serde_json::to_string(&act).map_err(|_| SiteError::Store)?;
if words.len() > limits.request_bytes.get() {
return Err(SiteError::Bound("request_bytes"));
}
let permission = lys_pass::Target::new(
act.change.kind(),
act.permission_id(lifecycle.network_id()),
act.change.action(),
)
.map_err(|_| SiteError::Invalid("construction target"))?;
if act.change.kind() == "liminal.template" {
bindings.effects.place("liminal.template", &act.target)?;
}
let advised = |lacking: &str| {
crate::auth_lys::advisory::advised(
decisions,
warned,
crate::auth_lys::advisory::Act {
holder: &act.holder,
kind: &permission.kind,
id: &permission.id,
action: &permission.action,
lacking,
},
)
};
let outright = |grant: &str| lifecycle.apply_outright(&act, grant, operation, &words, at_ms);
let answer = match live.ask_prepared(
token,
&PreparedAct {
holder: &act.holder,
target: &permission,
operation,
words: &words,
at_ms,
},
draft_limits,
) {
Ok(answer) => answer,
Err(error) => {
return advised(error.name()).map_or_else(
|| Err(SiteError::Pass(error.name().into())),
|receipt| outright(&receipt.grant),
);
}
};
match answer.decision {
LiveAnswer::Held { draft, .. } => advised(&format!("held under draft {draft}"))
.map_or_else(
|| Ok(serde_json::json!({"state":"held","draft":draft,"words":words})),
|receipt| outright(&receipt.grant),
),
LiveAnswer::Outright { grant } => outright(&grant),
LiveAnswer::Refused { refusal } => advised(&refusal).map_or_else(
|| Err(SiteError::Pass(refusal.clone())),
|receipt| outright(&receipt.grant),
),
}
}