use std::collections::HashMap;
use axum::Json;
use axum::extract::{Path, State};
use axum::http::StatusCode;
use serde::Deserialize;
use serde_json::Value;
use vta_sdk::did_templates::{DidTemplate, DidTemplateRecord, TemplateVars};
pub use vta_sdk::protocols::did_template_management::list::ListDidTemplatesResultBody as ListDidTemplatesResponse;
pub use vta_sdk::protocols::did_template_management::render::RenderDidTemplateResultBody as RenderDidTemplateResponse;
use crate::auth::{AuthClaims, SuperAdminAuth};
use crate::error::AppError;
use crate::operations;
use crate::server::AppState;
#[derive(Debug, Deserialize, utoipa::ToSchema)]
pub struct RenderDidTemplateRequest {
#[serde(default)]
pub vars: HashMap<String, Value>,
}
#[utoipa::path(
get, path = "/did-templates", tag = "did-templates",
security(("bearer_jwt" = [])),
responses(
(status = 200, description = "DID templates", body = ListDidTemplatesResponse),
(status = 401, description = "Missing or invalid bearer token"),
),
)]
pub async fn list_handler(
auth: AuthClaims,
State(state): State<AppState>,
) -> Result<Json<ListDidTemplatesResponse>, AppError> {
let templates =
operations::did_templates::list_global(&state.did_templates_ks, &auth, "rest").await?;
Ok(Json(ListDidTemplatesResponse { templates }))
}
#[utoipa::path(
post, path = "/did-templates", tag = "did-templates",
security(("bearer_jwt" = [])),
request_body = DidTemplate,
responses(
(status = 201, description = "DID template created", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
(status = 403, description = "Caller is not a super admin"),
),
)]
pub async fn create_handler(
auth: SuperAdminAuth,
State(state): State<AppState>,
Json(template): Json<DidTemplate>,
) -> Result<(StatusCode, Json<DidTemplateRecord>), AppError> {
let record = operations::did_templates::create_global(
&state.did_templates_ks,
&state.audit_ks,
&auth.0,
template,
"rest",
)
.await?;
Ok((StatusCode::CREATED, Json(record)))
}
#[utoipa::path(
get, path = "/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("name" = String, Path, description = "Template name")),
responses(
(status = 200, description = "DID template", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn get_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path(name): Path<String>,
) -> Result<Json<DidTemplateRecord>, AppError> {
let record =
operations::did_templates::get_global(&state.did_templates_ks, &auth, &name, "rest")
.await?;
Ok(Json(record))
}
#[utoipa::path(
put, path = "/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("name" = String, Path, description = "Template name")),
request_body = DidTemplate,
responses(
(status = 200, description = "DID template updated", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
(status = 403, description = "Caller is not a super admin"),
(status = 404, description = "Template not found"),
),
)]
pub async fn update_handler(
auth: SuperAdminAuth,
State(state): State<AppState>,
Path(name): Path<String>,
Json(template): Json<DidTemplate>,
) -> Result<Json<DidTemplateRecord>, AppError> {
let record = operations::did_templates::update_global(
&state.did_templates_ks,
&state.audit_ks,
&auth.0,
&name,
template,
"rest",
)
.await?;
Ok(Json(record))
}
#[utoipa::path(
delete, path = "/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("name" = String, Path, description = "Template name")),
responses(
(status = 204, description = "DID template deleted"),
(status = 401, description = "Missing or invalid bearer token"),
(status = 403, description = "Caller is not a super admin"),
(status = 404, description = "Template not found"),
),
)]
pub async fn delete_handler(
auth: SuperAdminAuth,
State(state): State<AppState>,
Path(name): Path<String>,
) -> Result<StatusCode, AppError> {
operations::did_templates::delete_global(
&state.did_templates_ks,
&state.audit_ks,
&auth.0,
&name,
"rest",
)
.await?;
Ok(StatusCode::NO_CONTENT)
}
#[utoipa::path(
post, path = "/did-templates/{name}/render", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("name" = String, Path, description = "Template name")),
request_body = RenderDidTemplateRequest,
responses(
(status = 200, description = "Rendered DID document", body = RenderDidTemplateResponse),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn render_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path(name): Path<String>,
Json(req): Json<RenderDidTemplateRequest>,
) -> Result<Json<RenderDidTemplateResponse>, AppError> {
let mut caller_vars = TemplateVars::new();
for (k, v) in req.vars {
caller_vars.insert(k, v);
}
let config_guard = state.config.read().await;
let document = operations::did_templates::render_global(
&state.did_templates_ks,
&config_guard,
&auth,
&name,
caller_vars,
"rest",
)
.await?;
Ok(Json(RenderDidTemplateResponse { document }))
}
#[utoipa::path(
get, path = "/contexts/{id}/did-templates", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("id" = String, Path, description = "Context identifier")),
responses(
(status = 200, description = "DID templates", body = ListDidTemplatesResponse),
(status = 401, description = "Missing or invalid bearer token"),
),
)]
pub async fn list_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path(context_id): Path<String>,
) -> Result<Json<ListDidTemplatesResponse>, AppError> {
let templates = operations::did_templates::list_context(
&state.did_templates_ks,
&auth,
&context_id,
"rest",
)
.await?;
Ok(Json(ListDidTemplatesResponse { templates }))
}
#[utoipa::path(
post, path = "/contexts/{id}/did-templates", tag = "did-templates",
security(("bearer_jwt" = [])),
params(("id" = String, Path, description = "Context identifier")),
request_body = DidTemplate,
responses(
(status = 201, description = "DID template created", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
),
)]
pub async fn create_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path(context_id): Path<String>,
Json(template): Json<DidTemplate>,
) -> Result<(StatusCode, Json<DidTemplateRecord>), AppError> {
let record = operations::did_templates::create_context(
&state.did_templates_ks,
&state.contexts_ks,
&state.audit_ks,
&auth,
&context_id,
template,
"rest",
)
.await?;
Ok((StatusCode::CREATED, Json(record)))
}
#[utoipa::path(
get, path = "/contexts/{id}/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(
("id" = String, Path, description = "Context identifier"),
("name" = String, Path, description = "Template name"),
),
responses(
(status = 200, description = "DID template", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn get_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path((context_id, name)): Path<(String, String)>,
) -> Result<Json<DidTemplateRecord>, AppError> {
let record = operations::did_templates::get_context(
&state.did_templates_ks,
&auth,
&context_id,
&name,
"rest",
)
.await?;
Ok(Json(record))
}
#[utoipa::path(
put, path = "/contexts/{id}/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(
("id" = String, Path, description = "Context identifier"),
("name" = String, Path, description = "Template name"),
),
request_body = DidTemplate,
responses(
(status = 200, description = "DID template updated", body = DidTemplateRecord),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn update_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path((context_id, name)): Path<(String, String)>,
Json(template): Json<DidTemplate>,
) -> Result<Json<DidTemplateRecord>, AppError> {
let record = operations::did_templates::update_context(
&state.did_templates_ks,
&state.audit_ks,
&auth,
&context_id,
&name,
template,
"rest",
)
.await?;
Ok(Json(record))
}
#[utoipa::path(
delete, path = "/contexts/{id}/did-templates/{name}", tag = "did-templates",
security(("bearer_jwt" = [])),
params(
("id" = String, Path, description = "Context identifier"),
("name" = String, Path, description = "Template name"),
),
responses(
(status = 204, description = "DID template deleted"),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn delete_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path((context_id, name)): Path<(String, String)>,
) -> Result<StatusCode, AppError> {
operations::did_templates::delete_context(
&state.did_templates_ks,
&state.audit_ks,
&auth,
&context_id,
&name,
"rest",
)
.await?;
Ok(StatusCode::NO_CONTENT)
}
#[utoipa::path(
post, path = "/contexts/{id}/did-templates/{name}/render", tag = "did-templates",
security(("bearer_jwt" = [])),
params(
("id" = String, Path, description = "Context identifier"),
("name" = String, Path, description = "Template name"),
),
request_body = RenderDidTemplateRequest,
responses(
(status = 200, description = "Rendered DID document", body = RenderDidTemplateResponse),
(status = 401, description = "Missing or invalid bearer token"),
(status = 404, description = "Template not found"),
),
)]
pub async fn render_context_handler(
auth: AuthClaims,
State(state): State<AppState>,
Path((context_id, name)): Path<(String, String)>,
Json(req): Json<RenderDidTemplateRequest>,
) -> Result<Json<RenderDidTemplateResponse>, AppError> {
let mut caller_vars = TemplateVars::new();
for (k, v) in req.vars {
caller_vars.insert(k, v);
}
let config_guard = state.config.read().await;
let document = operations::did_templates::render_context(
&state.did_templates_ks,
&state.contexts_ks,
&config_guard,
&auth,
&context_id,
&name,
caller_vars,
"rest",
)
.await?;
Ok(Json(RenderDidTemplateResponse { document }))
}