imgchest/client/
builder.rs1use crate::PostPrivacy;
2use std::path::Path;
3use tokio_util::codec::BytesCodec;
4use tokio_util::codec::FramedRead;
5
6#[derive(Debug)]
10pub struct CreatePostBuilder {
11 pub title: Option<String>,
15
16 pub privacy: Option<PostPrivacy>,
20
21 pub anonymous: Option<bool>,
23
24 pub nsfw: Option<bool>,
26
27 pub images: Vec<UploadPostFile>,
29}
30
31impl CreatePostBuilder {
32 pub fn new() -> Self {
34 Self {
35 title: None,
36 privacy: None,
37 anonymous: None,
38 nsfw: None,
39 images: Vec::new(),
40 }
41 }
42
43 pub fn title(&mut self, title: impl Into<String>) -> &mut Self {
47 self.title = Some(title.into());
48 self
49 }
50
51 pub fn privacy(&mut self, privacy: PostPrivacy) -> &mut Self {
55 self.privacy = Some(privacy);
56 self
57 }
58
59 pub fn anonymous(&mut self, anonymous: bool) -> &mut Self {
61 self.anonymous = Some(anonymous);
62 self
63 }
64
65 pub fn nsfw(&mut self, nsfw: bool) -> &mut Self {
67 self.nsfw = Some(nsfw);
68 self
69 }
70
71 pub fn image(&mut self, file: UploadPostFile) -> &mut Self {
73 self.images.push(file);
74 self
75 }
76}
77
78impl Default for CreatePostBuilder {
79 fn default() -> Self {
80 Self::new()
81 }
82}
83
84#[derive(Debug)]
86pub struct UploadPostFile {
87 pub(super) file_name: String,
89
90 pub(super) body: reqwest::Body,
92}
93
94impl UploadPostFile {
95 pub fn from_body(file_name: &str, body: reqwest::Body) -> Self {
97 Self {
98 file_name: file_name.into(),
99 body,
100 }
101 }
102
103 pub fn from_bytes(file_name: &str, file_data: Vec<u8>) -> Self {
105 Self::from_body(file_name, file_data.into())
106 }
107
108 pub fn from_file(file_name: &str, file: tokio::fs::File) -> Self {
110 let stream = FramedRead::new(file, BytesCodec::new());
111 let body = reqwest::Body::wrap_stream(stream);
112
113 Self::from_body(file_name, body)
114 }
115
116 pub async fn from_path<P>(path: P) -> std::io::Result<Self>
118 where
119 P: AsRef<Path>,
120 {
121 let path = path.as_ref();
122
123 let file_name = path
124 .file_name()
125 .ok_or_else(|| std::io::Error::other("missing file name"))?
126 .to_str()
127 .ok_or_else(|| std::io::Error::other("file name is not valid unicode"))?;
128
129 let file = tokio::fs::File::open(path).await?;
130
131 Ok(Self::from_file(file_name, file))
132 }
133}
134
135#[derive(Debug)]
137pub struct UpdatePostBuilder {
138 pub title: Option<String>,
142
143 pub privacy: Option<PostPrivacy>,
145
146 pub nsfw: Option<bool>,
148}
149
150impl UpdatePostBuilder {
151 pub fn new() -> Self {
153 Self {
154 title: None,
155 privacy: None,
156 nsfw: None,
157 }
158 }
159
160 pub fn title(&mut self, title: impl Into<String>) -> &mut Self {
164 self.title = Some(title.into());
165 self
166 }
167
168 pub fn privacy(&mut self, privacy: PostPrivacy) -> &mut Self {
170 self.privacy = Some(privacy);
171 self
172 }
173
174 pub fn nsfw(&mut self, nsfw: bool) -> &mut Self {
176 self.nsfw = Some(nsfw);
177 self
178 }
179}
180
181impl Default for UpdatePostBuilder {
182 fn default() -> Self {
183 Self::new()
184 }
185}
186
187#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
189pub enum SortOrder {
190 Popular,
192
193 New,
195
196 Old,
198}
199
200#[derive(Debug, Clone)]
202pub struct ListPostsBuilder {
203 pub sort: SortOrder,
207
208 pub page: u64,
212
213 pub username: Option<String>,
215
216 pub profile: bool,
218}
219
220impl ListPostsBuilder {
221 pub fn new() -> Self {
223 Self {
224 sort: SortOrder::Popular,
225 page: 1,
226 username: None,
227 profile: false,
228 }
229 }
230
231 pub fn sort(&mut self, sort: SortOrder) -> &mut Self {
235 self.sort = sort;
236 self
237 }
238
239 pub fn page(&mut self, page: u64) -> &mut Self {
243 self.page = page;
244 self
245 }
246
247 pub fn username(&mut self, username: String) -> &mut Self {
249 self.username = Some(username);
250 self
251 }
252
253 pub fn profile(&mut self, profile: bool) -> &mut Self {
255 self.profile = profile;
256 self
257 }
258}
259
260impl Default for ListPostsBuilder {
261 fn default() -> Self {
262 Self::new()
263 }
264}