use url::Url;
use crate::objects::bugzilla::Attachment;
use crate::service::bugzilla::Bugzilla;
use crate::traits::{InjectAuth, RequestSend, WebService};
use crate::Error;
#[derive(Debug)]
pub struct Request {
service: Bugzilla,
pub ids: Vec<u64>,
pub data: bool,
}
impl Request {
pub(crate) fn new<I>(service: &Bugzilla, ids: I) -> Self
where
I: IntoIterator<Item = u64>,
{
Self {
service: service.clone(),
ids: ids.into_iter().collect(),
data: true,
}
}
fn url(&self) -> crate::Result<Url> {
let id = self
.ids
.first()
.ok_or_else(|| Error::InvalidRequest("no IDs specified".to_string()))?;
let mut url = self
.service
.config()
.base
.join(&format!("rest/bug/attachment/{id}"))?;
for id in self.ids[1..].iter().map(|x| x.to_string()) {
url.query_pairs_mut().append_pair("attachment_ids", &id);
}
if !self.data {
url.query_pairs_mut().append_pair("exclude_fields", "data");
}
Ok(url)
}
pub fn data(&mut self, fetch: bool) -> &mut Self {
self.data = fetch;
self
}
}
impl RequestSend for Request {
type Output = Vec<Attachment>;
async fn send(&self) -> crate::Result<Self::Output> {
let request = self
.service
.client()
.get(self.url()?)
.auth_optional(&self.service);
let response = request.send().await?;
let mut data = self.service.parse_response(response).await?;
let mut data = data["attachments"].take();
let mut attachments = vec![];
for id in self.ids.iter().map(|x| x.to_string()) {
let data = data[&id].take();
if data.is_null() {
return Err(Error::InvalidValue(format!("nonexistent attachment: {id}")));
}
if self.data && data["data"].is_null() {
return Err(Error::InvalidValue(format!("deleted attachment: {id}")));
}
let attachment = serde_json::from_value(data).map_err(|_| {
Error::InvalidResponse(format!("failed deserializing attachment: {id}"))
})?;
attachments.push(attachment);
}
Ok(attachments)
}
}
#[cfg(test)]
mod tests {
use crate::test::*;
use super::*;
#[tokio::test]
async fn request() {
let path = TESTDATA_PATH.join("bugzilla");
let server = TestServer::new().await;
let service = Bugzilla::new(server.uri()).unwrap();
let ids = Vec::<u64>::new();
let err = service.attachment_get(ids).send().await.unwrap_err();
assert!(matches!(err, Error::InvalidRequest(_)));
assert_err_re!(err, "no IDs specified");
server
.respond(200, path.join("attachment/get/nonexistent.json"))
.await;
let err = service.attachment_get([1]).send().await.unwrap_err();
assert!(matches!(err, Error::InvalidValue(_)));
assert_err_re!(err, "nonexistent attachment: 1");
server.reset().await;
server
.respond(200, path.join("attachment/get/deleted.json"))
.await;
let err = service.attachment_get([21]).send().await.unwrap_err();
assert!(matches!(err, Error::InvalidValue(_)));
assert_err_re!(err, "deleted attachment: 21");
server.reset().await;
server
.respond(200, path.join("attachment/get/invalid.json"))
.await;
let err = service.attachment_get([123]).send().await.unwrap_err();
assert!(matches!(err, Error::InvalidResponse(_)));
assert_err_re!(err, "failed deserializing attachment: 123");
server.reset().await;
server
.respond(200, path.join("attachment/get/single-without-data.json"))
.await;
let attachment = &service
.attachment_get([123])
.data(false)
.send()
.await
.unwrap()[0];
assert!(attachment.is_empty());
server.reset().await;
server
.respond(200, path.join("attachment/get/single-plain-text.json"))
.await;
let attachment = &service.attachment_get([123]).send().await.unwrap()[0];
assert_eq!(attachment.id, 123);
assert_eq!(attachment.bug_id, 321);
assert_eq!(attachment.file_name, "test.txt");
assert_eq!(attachment.summary, "test.txt");
assert_eq!(attachment.size, 8_u64);
assert_eq!(attachment.creator, "person");
assert_eq!(attachment.content_type, "text/plain");
assert!(!attachment.is_private);
assert!(!attachment.is_obsolete);
assert!(!attachment.is_patch);
assert_eq!(attachment.created.to_string(), "2024-02-19 08:35:02 UTC");
assert_eq!(attachment.updated.to_string(), "2024-02-19 08:35:02 UTC");
assert!(attachment.flags.is_empty());
assert_eq!(String::from_utf8_lossy(attachment.as_ref()), "bugbite\n");
server.reset().await;
server
.respond(200, path.join("attachment/get/multiple-plain-text.json"))
.await;
let ids = [123, 124];
let attachments = &service.attachment_get(ids).send().await.unwrap();
assert_ordered_eq!(attachments.iter().map(|x| x.id), ids);
}
}