use crate::{
domain::{Context, TrustRecord, TrustRecordIds},
storage::repository::{TrustRecordQuery, TrustRecordRepository},
};
use anyhow::anyhow;
use axum::{
Json,
extract::{State, rejection::JsonRejection},
};
use chrono::{SecondsFormat, Utc};
use serde::{Deserialize, Serialize};
use serde_json::json;
use super::SharedData;
use crate::http::error::AppError;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct OutputDto {
#[serde(flatten)]
trust_record: TrustRecord,
time_requested: String,
time_evaluated: String,
message: String,
}
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct InputDto {
#[serde(flatten)]
ids: TrustRecordIds,
context: Option<Context>,
}
async fn handle_trqp<R>(
state: SharedData<R>,
payload: Result<Json<InputDto>, JsonRejection>,
) -> Result<TrustRecord, AppError>
where
R: TrustRecordRepository + Send + ?Sized + 'static,
{
let body = payload.map_err(|e| AppError::BadRequest {
details: Some(json!([{ "issue": e.body_text() }])),
internal_error: e.into(),
})?;
let input = body.0;
let query_result = state
.repository
.find_by_query(TrustRecordQuery::from_ids(input.ids))
.await;
let mut trust_record = query_result
.map_err(|e| AppError::Internal {
internal_error: e.into(),
details: None,
})?
.ok_or(AppError::NotFound {
internal_error: anyhow!("Trust record not found"),
details: None,
})?;
if let Some(c) = input.context {
trust_record = trust_record.merge_contexts(c);
}
Ok(trust_record)
}
pub async fn handle_trqp_authorization<R>(
State(state): State<SharedData<R>>,
payload: Result<Json<InputDto>, JsonRejection>,
) -> Result<Json<OutputDto>, AppError>
where
R: TrustRecordRepository + Send + ?Sized + 'static,
{
let requested_at = Utc::now();
let mut trust_record = handle_trqp(state, payload).await?;
trust_record = trust_record.none_recognized();
let message = format!(
"{} authorized to {}+{} by {}",
trust_record.entity_id(),
trust_record.action(),
trust_record.resource(),
trust_record.authority_id()
);
let evaluated_at = Utc::now();
Ok(Json(OutputDto {
trust_record,
time_requested: requested_at.to_rfc3339_opts(SecondsFormat::Secs, true),
time_evaluated: evaluated_at.to_rfc3339_opts(SecondsFormat::Secs, true),
message,
}))
}
pub async fn handle_trqp_recognition<R>(
State(state): State<SharedData<R>>,
payload: Result<Json<InputDto>, JsonRejection>,
) -> Result<Json<OutputDto>, AppError>
where
R: TrustRecordRepository + Send + ?Sized + 'static,
{
let requested_at = Utc::now();
let mut trust_record = handle_trqp(state, payload).await?;
trust_record = trust_record.none_authorized();
let message = format!(
"{} recognized by {}",
trust_record.entity_id(),
trust_record.authority_id()
);
let evaluated_at = Utc::now();
Ok(Json(OutputDto {
trust_record,
time_requested: requested_at.to_rfc3339_opts(SecondsFormat::Secs, true),
time_evaluated: evaluated_at.to_rfc3339_opts(SecondsFormat::Secs, true),
message,
}))
}