1pub mod api_models {
3
4
5 pub mod users {
7 use chrono::{DateTime, Utc};
8 use serde_derive::{Deserialize, Serialize};
9
10 #[derive(Clone, Debug, Serialize, Deserialize)]
11 pub struct User {
13 pub username: String,
15
16 pub email: Option<String>,
18
19 pub created: Option<DateTime<Utc>>,
21 }
22 }
23
24 pub mod posts {
26 use chrono::{DateTime, Utc};
27 use derive_builder::Builder;
28 use reqwest::Method;
29 use serde_derive::{Deserialize, Serialize};
30
31 use crate::api_client::{ApiError, Client};
32
33 use super::collections::{Collection, MovePost, MoveResult};
34
35 #[derive(Clone, Debug, Serialize, Deserialize)]
36 pub enum PostAppearance {
38 #[serde(rename = "sans")]
39 SansSerif,
41
42 #[serde(rename = "serif")]
43 #[serde(alias = "norm")]
44 #[serde(alias = "serif")]
45 Serif,
47
48 #[serde(rename = "wrap")]
49 Wrap,
51
52 #[serde(rename = "mono")]
53 Mono,
55
56 #[serde(rename = "code")]
57 Code,
59 }
60
61 #[derive(Clone, Debug, Serialize, Deserialize, Builder)]
62 pub struct PostUpdate {
64 #[serde(skip_serializing)]
65 pub client: Option<Client>,
67
68 #[serde(skip_serializing)]
69 pub id: String,
71
72 pub token: Option<String>,
74
75 pub body: String,
77
78 pub title: Option<String>,
80
81 pub font: Option<PostAppearance>,
83
84 pub lang: Option<String>,
86
87 pub rtl: bool,
89 }
90
91 impl PostUpdate {
92 pub async fn update(&self) -> Result<Post, ApiError> {
94 if let Some(client) = self.client.clone() {
95 client
96 .api()
97 .post::<Post, PostUpdate>(
98 format!("/posts/{}", self.id).as_str(),
99 Some(self.clone()),
100 )
101 .await
102 .and_then(|mut p| Ok(p.with_client(client.clone())))
103 } else {
104 Err(ApiError::UsageError {})
105 }
106 }
107 }
108
109 #[derive(Clone, Debug, Serialize, Deserialize)]
110 pub struct Post {
112 pub client: Option<Client>,
114 pub id: String,
116 pub slug: Option<String>,
118 pub appearance: Option<PostAppearance>,
120 pub language: Option<String>,
122 pub rtl: bool,
124 pub created: Option<DateTime<Utc>>,
126 pub title: Option<String>,
128 pub body: String,
130 pub tags: Vec<String>,
132 pub views: Option<u64>,
134 pub collection: Option<Collection>,
136 pub token: Option<String>,
138 }
139
140 impl Post {
141 #[doc(hidden)]
142 pub fn with_client(&mut self, client: Client) -> Self {
143 self.client = Some(client);
144 self.clone()
145 }
146
147 pub fn build_update(&self, body: String) -> PostUpdateBuilder {
149 PostUpdateBuilder::default()
150 .client(self.client.clone())
151 .id(self.id.clone())
152 .body(body)
153 .clone()
154 }
155
156 pub async fn update(&self, update: PostUpdate) -> Result<Post, ApiError> {
158 if let Some(client) = self.client.clone() {
159 client
160 .api()
161 .post::<Post, PostUpdate>(
162 format!("/posts/{}", self.id).as_str(),
163 Some(update.clone()),
164 )
165 .await
166 .and_then(|mut p| Ok(p.with_client(client.clone())))
167 } else {
168 Err(ApiError::UsageError {})
169 }
170 }
171
172 pub async fn delete(&self) -> Result<(), ApiError> {
174 if let Some(client) = self.client.clone() {
175 let mut request = client
176 .api()
177 .request(format!("/posts/{}", self.id).as_str(), Method::DELETE)
178 .unwrap();
179 if !client.is_authenticated() && self.token.is_some() {
180 request = request.query(&[("token", self.token.clone().unwrap())]);
181 }
182 if let Ok(result) = request.send().await {
183 client.api().extract_response(result).await
184 } else {
185 Err(ApiError::ConnectionError {})
186 }
187 } else {
188 Err(ApiError::UsageError {})
189 }
190 }
191
192 pub async fn move_to(&self, collection: &str) -> Result<MoveResult, ApiError> {
194 if let Some(client) = self.client.clone() {
195 match client.collections().get(collection).await {
196 Ok(coll) => {
197 match client.is_authenticated() {
198 true => coll.take_posts(&[MovePost::new(&self.id)]).await,
199 false => coll.take_posts(&[MovePost {id: self.id.clone(), token: self.token.clone()}]).await
200 }.and_then(|v| {
201 match v.get(0) {
202 Some(item) => match item {
203 Ok(result) => Ok(result.clone()),
204 Err(result) => Ok(result.clone())
205 },
206 None => Err(ApiError::UnknownError { })
207 }
208 })
209 },
210 Err(e) => Err(e)
211 }
212 } else {
213 Err(ApiError::UsageError {})
214 }
215 }
216 }
217
218 #[derive(Clone, Debug, Serialize, Deserialize, Builder)]
219 pub struct PostCreation {
221 #[serde(skip_serializing)]
222 pub client: Option<Client>,
224
225 #[serde(skip_serializing)]
226 pub collection: Option<String>,
228
229 pub body: String,
231
232 pub title: Option<String>,
234
235 pub font: Option<PostAppearance>,
237
238 pub lang: Option<String>,
240
241 pub rtl: Option<bool>,
243
244 pub created: Option<DateTime<Utc>>,
246 }
247
248 impl PostCreation {
249 pub async fn publish(&self) -> Result<Post, ApiError> {
251 if let Some(client) = self.client.clone() {
252 if let Some(collection) = self.collection.clone() {
253 client
254 .api()
255 .post::<Post, PostCreation>(
256 format!("/collections/{collection}/post").as_str(),
257 Some(self.clone()),
258 )
259 .await
260 .and_then(|mut v| Ok(v.with_client(client.clone())))
261 } else {
262 client
263 .api()
264 .post::<Post, PostCreation>("/posts", Some(self.clone()))
265 .await
266 .and_then(|mut v| Ok(v.with_client(client.clone())))
267 }
268 } else {
269 Err(ApiError::UsageError {})
270 }
271 }
272 }
273 }
274
275 #[doc(hidden)]
276 pub mod responses {
277 use std::fmt::Debug;
278
279 use super::users::User;
280 use serde_derive::{Deserialize, Serialize};
281 use serde_json::Value;
282
283 #[derive(Clone, Debug, Serialize, Deserialize)]
284 pub struct Login {
285 pub access_token: String,
286 pub user: User,
287 }
288
289 #[derive(Clone, Debug, Serialize, Deserialize)]
290 pub struct ResponseModel {
291 pub code: u16,
292 pub data: Value,
293 }
294 }
295
296 #[doc(hidden)]
297 pub mod requests {
298 use serde_derive::{Deserialize, Serialize};
299
300 #[derive(Clone, Debug, Serialize, Deserialize)]
301 pub struct Login {
302 pub alias: String,
303 pub pass: String,
304 }
305 }
306
307 pub mod collections {
309 use derive_builder::Builder;
310 use serde_derive::{Deserialize, Serialize};
311 use serde_repr::{Deserialize_repr, Serialize_repr};
312
313 use crate::api_client::{ApiError, Client};
314
315 use super::posts::Post;
316
317 #[derive(Clone, Debug, Serialize, Deserialize)]
318 pub struct MovePost {
320 pub id: String,
322
323 pub token: Option<String>,
325 }
326
327 impl MovePost {
328 pub fn new(id: &str) -> Self {
330 MovePost {
331 id: id.to_string(),
332 token: None,
333 }
334 }
335
336 pub fn new_with_token(id: &str, token: &str) -> Self {
338 MovePost {
339 id: id.to_string(),
340 token: Some(token.to_string()),
341 }
342 }
343 }
344
345 #[derive(Clone, Debug, Serialize, Deserialize)]
346 #[serde(untagged)]
347 pub enum MoveResult {
349 Success {
351 code: u32,
353
354 post: Post
356 },
357
358 Error {
360 code: u32,
362
363 error_msg: String
365 },
366 }
367
368 #[derive(Clone, Debug, Serialize, Deserialize)]
369 pub struct PinPost {
371 pub id: String,
373
374 #[serde(skip_serializing_if = "Option::is_none")]
375 pub postion: Option<u64>
377 }
378
379 impl PinPost {
380 pub fn new(id: &str) -> Self {
382 PinPost {
383 id: id.to_string(),
384 postion: None
385 }
386 }
387
388 pub fn new_at_position(id: &str, position: u64) -> Self {
390 PinPost {
391 id: id.to_string(),
392 postion: Some(position),
393 }
394 }
395 }
396
397 #[derive(Clone, Debug, Serialize, Deserialize)]
398 #[serde(untagged)]
399 pub enum PinResult {
401 Success {
403 code: u32,
405 id: String
407 },
408
409 Error {
411 code: u32,
413 error_msg: String
415 },
416 }
417
418 #[derive(Clone, Debug, Serialize, Deserialize)]
419 pub struct Collection {
421 pub client: Option<Client>,
423 pub alias: String,
425 pub title: String,
427 pub description: Option<String>,
429 pub style_sheet: Option<String>,
431 pub public: bool,
433 pub views: Option<u64>,
435 pub verification_link: Option<String>,
437 pub total_posts: Option<u64>,
439 }
440
441 impl Collection {
442 #[doc(hidden)]
443 pub fn with_client(&mut self, client: Client) -> Self {
444 self.client = Some(client);
445 self.clone()
446 }
447
448 pub fn build_update(&self) -> CollectionUpdateBuilder {
450 CollectionUpdateBuilder::default()
451 .alias(Some(self.alias.clone()))
452 .client(self.client.clone())
453 .clone()
454 }
455
456 pub async fn update(&self, update: CollectionUpdate) -> Result<Collection, ApiError> {
458 if let Some(client) = self.client.clone() {
459 client
460 .api()
461 .post::<Collection, CollectionUpdate>(
462 format!("/collections/{}", self.alias).as_str(),
463 Some(update.clone()),
464 )
465 .await
466 .and_then(|mut p| Ok(p.with_client(client.clone())))
467 } else {
468 Err(ApiError::UsageError {})
469 }
470 }
471
472 pub async fn delete(&self) -> Result<(), ApiError> {
474 if let Some(client) = self.client.clone() {
475 client
476 .api()
477 .delete(format!("/collections/{}", self.alias).as_str())
478 .await
479 } else {
480 Err(ApiError::UsageError {})
481 }
482 }
483
484 pub async fn get_posts(&self) -> Result<Vec<Post>, ApiError> {
486 if let Some(client) = self.client.clone() {
487 client
488 .api()
489 .get::<Vec<Post>>(format!("/collections/{}/posts", self.alias).as_str())
490 .await
491 .and_then(|mut v| {
492 Ok(v.iter_mut()
493 .map(|x| x.with_client(client.clone()))
494 .collect())
495 })
496 } else {
497 Err(ApiError::UsageError {})
498 }
499 }
500
501 pub async fn get_post(&self, slug: String) -> Result<Post, ApiError> {
503 if let Some(client) = self.client.clone() {
504 client
505 .api()
506 .get::<Post>(format!("/collections/{}/posts/{}", self.alias, slug).as_str())
507 .await
508 .and_then(|mut v| Ok(v.with_client(client.clone())))
509 } else {
510 Err(ApiError::UsageError {})
511 }
512 }
513
514 pub async fn take_posts(
516 &self,
517 posts: &[MovePost],
518 ) -> Result<Vec<Result<MoveResult, MoveResult>>, ApiError> {
519 if let Some(client) = self.client.clone() {
520 let result = client
521 .api()
522 .post::<Vec<MoveResult>, &[MovePost]>(
523 format!("/collections/{}/collect", self.alias).as_str(),
524 Some(posts),
525 )
526 .await;
527 match result {
528 Ok(results) => Ok(results
529 .iter()
530 .map::<Result<MoveResult, MoveResult>, _>(|r| match r {
531 MoveResult::Success { code, post } => Ok(MoveResult::Success {
532 code: code.clone(),
533 post: post.clone().with_client(client.clone()),
534 }),
535 MoveResult::Error { code, error_msg } => Err(MoveResult::Error {
536 code: code.clone(),
537 error_msg: error_msg.clone(),
538 }),
539 })
540 .collect()),
541 Err(e) => Err(e),
542 }
543 } else {
544 Err(ApiError::UsageError {})
545 }
546 }
547
548 pub async fn pin_posts(
550 &self,
551 posts: &[PinPost],
552 ) -> Result<Vec<Result<PinResult, PinResult>>, ApiError> {
553 if let Some(client) = self.client.clone() {
554 let result = client
555 .api()
556 .post::<Vec<PinResult>, &[PinPost]>(
557 format!("/collections/{}/pin", self.alias).as_str(),
558 Some(posts),
559 )
560 .await;
561 match result {
562 Ok(results) => Ok(results
563 .iter()
564 .map::<Result<PinResult, PinResult>, _>(|r| match r {
565 PinResult::Success { code, id } => Ok(PinResult::Success {
566 code: code.clone(),
567 id: id.clone()
568 }),
569 PinResult::Error { code, error_msg } => Err(PinResult::Error {
570 code: code.clone(),
571 error_msg: error_msg.clone(),
572 }),
573 })
574 .collect()),
575 Err(e) => Err(e),
576 }
577 } else {
578 Err(ApiError::UsageError {})
579 }
580 }
581
582 pub async fn unpin_posts(&self, posts: &[String]) -> Result<Vec<Result<PinResult, PinResult>>, ApiError> {
584 if let Some(client) = self.client.clone() {
585 let result = client
586 .api()
587 .post::<Vec<PinResult>, Vec<PinPost>>(
588 format!("/collections/{}/unpin", self.alias).as_str(),
589 Some(posts.iter().map(|v| PinPost::new(v.as_str())).collect()),
590 )
591 .await;
592 match result {
593 Ok(results) => Ok(results
594 .iter()
595 .map::<Result<PinResult, PinResult>, _>(|r| match r {
596 PinResult::Success { code, id } => Ok(PinResult::Success {
597 code: code.clone(),
598 id: id.clone()
599 }),
600 PinResult::Error { code, error_msg } => Err(PinResult::Error {
601 code: code.clone(),
602 error_msg: error_msg.clone(),
603 }),
604 })
605 .collect()),
606 Err(e) => Err(e),
607 }
608 } else {
609 Err(ApiError::UsageError {})
610 }
611 }
612 }
613
614 #[derive(Clone, Debug, Serialize_repr, Deserialize_repr)]
615 #[repr(u8)]
616 pub enum CollectionVisibility {
618 Unlisted = 0,
620 Public = 1,
622 Private = 2,
624 Password = 4,
626 }
627
628 #[derive(Clone, Debug, Serialize, Deserialize, Builder)]
629 pub struct CollectionUpdate {
631 #[serde(skip_serializing)]
632 pub client: Option<Client>,
634
635 #[serde(skip_serializing)]
636 pub alias: Option<String>,
638
639 pub title: Option<String>,
641
642 pub description: Option<String>,
644
645 pub style_sheet: Option<String>,
647
648 pub script: Option<String>,
650
651 pub visibility: Option<CollectionVisibility>,
653
654 pub pass: Option<String>,
656
657 pub mathjax: bool,
659 }
660
661 impl CollectionUpdate {
662 pub async fn update(&self) -> Result<Collection, ApiError> {
664 if let Some(client) = self.client.clone() {
665 if let Some(alias) = self.alias.clone() {
666 client
667 .api()
668 .post::<Collection, CollectionUpdate>(
669 format!("/collections/{}", alias).as_str(),
670 Some(self.clone()),
671 )
672 .await
673 .and_then(|mut p| Ok(p.with_client(client.clone())))
674 } else {
675 Err(ApiError::UsageError {})
676 }
677 } else {
678 Err(ApiError::UsageError {})
679 }
680 }
681 }
682 }
683}