use nextcloud_sdk_core::{
ApiPath, AuthProvider, Error, Headers, HttpMethod, Request, Response, StatusError, Transport,
};
use crate::options::PreviewOptions;
use crate::query::{build_file_id_query, build_path_query};
#[cfg(test)]
mod tests;
pub const PREVIEW_ENDPOINT: &str = "core/preview.png";
#[derive(Clone, Copy, Debug)]
pub struct PreviewClient<'a, T: Transport, A: AuthProvider> {
transport: &'a T,
auth: &'a A,
}
impl<'a, T: Transport, A: AuthProvider> PreviewClient<'a, T, A> {
pub const fn new(transport: &'a T, auth: &'a A) -> Self {
Self { transport, auth }
}
pub const fn transport(&self) -> &'a T {
self.transport
}
pub const fn auth(&self) -> &'a A {
self.auth
}
pub async fn get_by_file_id(
&self,
file_id: u64,
options: &PreviewOptions,
) -> Result<Vec<u8>, Error> {
tracing::debug!(file_id, "Fetching file preview by ID");
let query = build_file_id_query(file_id, options);
self.fetch_preview(&query).await
}
pub async fn get_by_path(
&self,
path: &str,
options: &PreviewOptions,
) -> Result<Vec<u8>, Error> {
tracing::debug!(path, "Fetching file preview by path");
let query = build_path_query(path, options);
self.fetch_preview(&query).await
}
async fn fetch_preview(&self, query: &str) -> Result<Vec<u8>, Error> {
let api_path = ApiPath::public(format!("{PREVIEW_ENDPOINT}{query}"))?;
let headers = self.authenticated_headers();
let request = Request::get(api_path.clone()).with_headers(headers);
let response = self.transport.execute(request).await?;
ensure_success(HttpMethod::Get, api_path, response)
}
fn authenticated_headers(&self) -> Headers {
let mut headers = Headers::new();
self.auth.authenticate(&mut headers);
headers
}
}
fn ensure_success(method: HttpMethod, path: ApiPath, response: Response) -> Result<Vec<u8>, Error> {
if response.status().is_success() {
Ok(response.into_body())
} else {
tracing::error!(
method = ?method,
path = %path.as_str(),
status = %response.status(),
"Preview request failed"
);
Err(Error::Status(StatusError::new(
method.as_str(),
path,
response.status(),
response.body(),
)))
}
}