diff --git a/src/commands/test/labeler/create_report.rs b/src/commands/test/labeler/create_report.rs index 4c2f921..60e2665 100644 --- a/src/commands/test/labeler/create_report.rs +++ b/src/commands/test/labeler/create_report.rs @@ -108,6 +108,91 @@ pub trait CreateReportTee: Send + Sync { ) -> Result; } +/// Real `CreateReportTee` implementation using reqwest. +pub struct RealCreateReportTee { + client: reqwest::Client, + endpoint: Url, +} + +impl RealCreateReportTee { + /// Create a new `RealCreateReportTee` using the given shared reqwest + /// client and labeler endpoint. The endpoint is the labeler's service + /// URL (e.g., `https://labeler.example.com`); the POST path + /// `/xrpc/com.atproto.moderation.createReport` is appended. + pub fn new(client: reqwest::Client, endpoint: Url) -> Self { + Self { client, endpoint } + } +} + +#[async_trait] +impl CreateReportTee for RealCreateReportTee { + async fn post_create_report( + &self, + auth: Option<&str>, + body: &serde_json::Value, + ) -> Result { + let mut url = self.endpoint.clone(); + url.set_path("xrpc/com.atproto.moderation.createReport"); + let source_url = url.to_string(); + + tracing::debug!( + url = %source_url, + auth_kind = match auth { + None => "none", + Some(t) if !t.starts_with("ey") => "malformed", + Some(_) => "jwt", + }, + "report stage: issuing createReport POST" + ); + + let mut req = self + .client + .post(url.as_str()) + .header("Content-Type", "application/json") + .body(serde_json::to_vec(body).expect("serde_json::Value always serializes")); + if let Some(token) = auth { + req = req.header("Authorization", format!("Bearer {token}")); + } + + let response = req + .send() + .await + .map_err(|e| CreateReportStageError::Transport { + message: e.to_string(), + source: Some(Box::new(e)), + })?; + + let status = response.status(); + let content_type = response + .headers() + .get(reqwest::header::CONTENT_TYPE) + .and_then(|h| h.to_str().ok()) + .map(|s| s.to_ascii_lowercase()); + + let body_bytes = response + .bytes() + .await + .map_err(|e| CreateReportStageError::Transport { + message: e.to_string(), + source: Some(Box::new(e)), + })?; + + tracing::debug!( + url = %source_url, + status = %status, + body_len = body_bytes.len(), + "report stage: createReport response received" + ); + + Ok(RawCreateReportResponse { + status, + content_type, + raw_body: Arc::from(body_bytes.as_ref()), + source_url, + }) + } +} + #[cfg(test)] mod did_tests { use super::*;