use std::sync::Arc;
use reqwest::header::{AUTHORIZATION, CONTENT_TYPE, USER_AGENT};
use agent_framework_core::error::{Error, Result};
use crate::auth::TokenProvider;
use crate::models::{ProcessContentRequest, ProcessContentResponse};
use crate::settings::PurviewSettings;
const PURVIEW_USER_AGENT: &str = concat!("agent-framework-rs-purview/", env!("CARGO_PKG_VERSION"));
pub struct PurviewClient {
http: reqwest::Client,
token_provider: Arc<dyn TokenProvider>,
graph_base_uri: String,
ignore_payment_required: bool,
}
impl PurviewClient {
pub fn new(token_provider: impl TokenProvider + 'static, settings: &PurviewSettings) -> Self {
Self {
http: reqwest::Client::new(),
token_provider: Arc::new(token_provider),
graph_base_uri: settings.graph_base_uri.trim_end_matches('/').to_string(),
ignore_payment_required: settings.ignore_payment_required,
}
}
pub async fn process_content(
&self,
request: &ProcessContentRequest,
) -> Result<ProcessContentResponse> {
let token = self.token_provider.get_token().await?;
let url = format!(
"{}/users/{}/dataSecurityAndGovernance/processContent",
self.graph_base_uri, request.user_id
);
let resp = self
.http
.post(&url)
.header(AUTHORIZATION, format!("Bearer {token}"))
.header(CONTENT_TYPE, "application/json")
.header(USER_AGENT, PURVIEW_USER_AGENT)
.json(request)
.send()
.await
.map_err(|e| Error::service(format!("Purview request to {url} failed: {e}")))?;
let status = resp.status();
let text = resp
.text()
.await
.map_err(|e| Error::service(format!("failed reading Purview response body: {e}")))?;
if status.as_u16() == 402 && self.ignore_payment_required {
return Ok(ProcessContentResponse::default());
}
if !status.is_success() {
return Err(Error::service_status(status.as_u16(), text, None));
}
serde_json::from_str(&text).map_err(|e| {
Error::service(format!(
"invalid Purview processContent response JSON: {e} (body: {text})"
))
})
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::auth::StaticTokenProvider;
#[test]
fn graph_base_uri_is_trimmed_of_trailing_slash() {
let settings = PurviewSettings::new("Test App");
let client = PurviewClient::new(StaticTokenProvider::new("t"), &settings);
assert_eq!(client.graph_base_uri, "https://graph.microsoft.com/v1.0");
}
#[test]
fn ignore_payment_required_is_captured_from_settings() {
let settings = PurviewSettings::new("Test App").with_ignore_payment_required(true);
let client = PurviewClient::new(StaticTokenProvider::new("t"), &settings);
assert!(client.ignore_payment_required);
let settings2 = PurviewSettings::new("Test App");
let client2 = PurviewClient::new(StaticTokenProvider::new("t"), &settings2);
assert!(!client2.ignore_payment_required);
}
}