use axum::body::Bytes;
use axum::extract::State;
use axum::http::{HeaderMap, StatusCode};
use axum::response::IntoResponse;
use axum_extra::extract::Query;
use crate::server::APPLICATION;
use serde::Deserialize;
use std::sync::Arc;
use tracing::Instrument;
use utoipa::IntoParams;
#[derive(Deserialize, IntoParams)]
pub struct Params {
d: String,
i: u8,
#[serde(default)]
style_csp: Vec<String>,
#[serde(default)]
script_csp: Vec<String>,
}
#[utoipa::path(
put,
path = "/templates",
tag = APPLICATION,
request_body(content = [u8], content_type = "application/octet-stream"),
params(Params),
responses(
(status = 401, description = "unauthorized for operation"),
(status = 200, description = "upload a template for an application"),
),
security(
("access" = []),
),
)]
pub async fn upload(
State(state): State<Arc<crate::server::OrdinaryApiServerState>>,
Query(Params {
d,
i,
style_csp,
script_csp,
}): Query<Params>,
headers: HeaderMap,
body: Bytes,
) -> impl IntoResponse {
let domain = d;
let idx = i;
let span = tracing::info_span!("app", %domain);
let span = span.in_scope(|| tracing::info_span!("template", idx));
let span = span.in_scope(|| tracing::info_span!("upload"));
async {
match crate::server::check_ordinary_auth(&state, &headers, 4, &domain) {
Ok(account) => account,
Err(code) => return code.into_response(),
};
tracing::info!("uploading");
let apps = state.apps.read().await;
if let Some(wrapped_app) = apps.get(&domain) {
match wrapped_app
.app
.set_template(
idx,
&body[..],
(!style_csp.is_empty()).then_some(style_csp),
(!script_csp.is_empty()).then_some(script_csp),
state.secure,
)
.await
{
Ok(name) => {
tracing::info!(name, "uploaded");
return StatusCode::OK.into_response();
}
Err(err) => {
tracing::error!(%err, "failed");
}
}
}
StatusCode::INTERNAL_SERVER_ERROR.into_response()
}
.instrument(span)
.await
}