redmine_api/api/
attachments.rs1use derive_builder::Builder;
10use reqwest::Method;
11use std::borrow::Cow;
12
13use crate::api::users::UserEssentials;
14use crate::api::{Endpoint, NoPagination, ReturnsJsonResponse};
15
16#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
20pub struct Attachment {
21 pub id: u64,
23 pub filename: String,
25 pub filesize: u64,
27 pub content_type: Option<String>,
29 #[serde(default)]
31 pub description: Option<String>,
32 pub content_url: String,
34 pub author: UserEssentials,
36 #[serde(
38 serialize_with = "crate::api::serialize_rfc3339",
39 deserialize_with = "crate::api::deserialize_rfc3339"
40 )]
41 pub created_on: time::OffsetDateTime,
42 #[serde(default, skip_serializing_if = "Option::is_none")]
44 thumbnail_url: Option<String>,
45}
46
47#[derive(Debug, Clone, Builder)]
49#[builder(setter(strip_option))]
50pub struct GetAttachment {
51 id: u64,
53}
54
55impl ReturnsJsonResponse for GetAttachment {}
56impl NoPagination for GetAttachment {}
57
58impl GetAttachment {
59 #[must_use]
61 pub fn builder() -> GetAttachmentBuilder {
62 GetAttachmentBuilder::default()
63 }
64}
65
66impl Endpoint for GetAttachment {
67 fn method(&self) -> Method {
68 Method::GET
69 }
70
71 fn endpoint(&self) -> Cow<'static, str> {
72 format!("attachments/{}.json", &self.id).into()
73 }
74}
75
76#[derive(Debug, Clone, Builder)]
78#[builder(setter(strip_option))]
79pub struct DeleteAttachment {
80 id: u64,
82}
83
84impl DeleteAttachment {
85 #[must_use]
87 pub fn builder() -> DeleteAttachmentBuilder {
88 DeleteAttachmentBuilder::default()
89 }
90}
91
92impl Endpoint for DeleteAttachment {
93 fn method(&self) -> Method {
94 Method::DELETE
95 }
96
97 fn endpoint(&self) -> Cow<'static, str> {
98 format!("attachments/{}.json", &self.id).into()
99 }
100}
101
102#[derive(Debug, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
104pub struct AttachmentWrapper<T> {
105 pub attachment: T,
107}
108
109#[cfg(test)]
110mod test {
111 use super::*;
112 use pretty_assertions::assert_eq;
113 use std::error::Error;
114 use tracing_test::traced_test;
115
116 #[traced_test]
117 #[test]
118 fn test_get_attachment() -> Result<(), Box<dyn Error>> {
119 dotenvy::dotenv()?;
120 let redmine = crate::api::Redmine::from_env(
121 reqwest::blocking::Client::builder()
122 .use_rustls_tls()
123 .build()?,
124 )?;
125 let endpoint = GetAttachment::builder().id(38468).build()?;
126 redmine.json_response_body::<_, AttachmentWrapper<Attachment>>(&endpoint)?;
127 Ok(())
128 }
129
130 #[traced_test]
135 #[test]
136 fn test_completeness_attachment_type() -> Result<(), Box<dyn Error>> {
137 dotenvy::dotenv()?;
138 let redmine = crate::api::Redmine::from_env(
139 reqwest::blocking::Client::builder()
140 .use_rustls_tls()
141 .build()?,
142 )?;
143 let endpoint = GetAttachment::builder().id(38468).build()?;
144 let AttachmentWrapper { attachment: value } =
145 redmine.json_response_body::<_, AttachmentWrapper<serde_json::Value>>(&endpoint)?;
146 let o: Attachment = serde_json::from_value(value.clone())?;
147 let reserialized = serde_json::to_value(o)?;
148 assert_eq!(value, reserialized);
149 Ok(())
150 }
151}