use chrono::Utc;
use vti_common::error::AppError;
use crate::acl::get_acl_entry;
use crate::community::load_profile;
use crate::members::Member;
use crate::server::AppState;
use super::facts::{
Actor, Context, Evidence, Facts, MemberState, Purpose, State as FactsState, Subject,
};
pub struct FactsInputs {
pub purpose: Purpose,
pub actor_did: String,
pub actor_role: Option<String>,
pub subject_did: String,
pub subject_member: Option<MemberState>,
pub evidence: Evidence,
}
pub async fn assemble_facts(state: &AppState, inputs: FactsInputs) -> Result<Facts, AppError> {
let community_did = load_profile(&state.community_ks)
.await?
.map(|p| p.community_did)
.unwrap_or_default();
Ok(Facts {
purpose: inputs.purpose,
now: Utc::now(),
actor: Actor {
did: inputs.actor_did,
role: inputs.actor_role,
authenticated: true,
},
subject: Subject {
did: inputs.subject_did,
},
context: Context {
community_did,
channel: "rest".to_string(),
member_count: state.member_count(),
},
evidence: inputs.evidence,
state: FactsState {
subject_member: inputs.subject_member,
},
})
}
pub async fn load_actor_role(state: &AppState, did: &str) -> Result<Option<String>, AppError> {
Ok(get_acl_entry(&state.acl_ks, did)
.await?
.map(|e| e.role.to_string()))
}
pub fn member_state(role: String, member: Option<&Member>) -> MemberState {
MemberState {
role,
status: member
.map(|m| {
if m.removed_at.is_some() {
"removed"
} else {
"active"
}
})
.unwrap_or("active")
.to_string(),
joined_at: member.map(|m| m.joined_at).unwrap_or_else(Utc::now),
personhood: None,
}
}