1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::api_client::ApiClient;
use crate::error::{ApiError, ResultApi};
use crate::model::{NewTarget, Target, TargetResponse, TargetType, UpdateTarget};
impl ApiClient {
/// Get all targets for a blog.
///
/// # Parameters
///
/// - `blog_name`: identifier or slug of the blog whose targets should be retrieved.
///
/// # Returns
///
/// A `TargetResponse` decoded from the full JSON body.
///
/// # Errors
///
/// - `ApiError::HttpRequest` if the network request fails.
/// - `ApiError::JsonParse` if the HTTP response body cannot be parsed as JSON.
/// - `ApiError::Deserialization` if the body cannot be deserialized into `TargetResponse`.
pub async fn get_blog_targets(&self, blog_name: &str) -> ResultApi<TargetResponse> {
let path = format!("target/{blog_name}/");
let response = self.get_request(&path).await?;
let response = self.handle_response(&path, response).await?;
self.parse_json(response).await
}
/// Create a new target for a blog.
///
/// # Parameters
///
/// - `blog_url`: identifier or slug of the blog for which the target is created.
/// - `description`: textual description of the target (e.g., purpose of the fundraising).
/// - `target_sum`: numerical value of the target amount.
/// - `target_type`: one of [`TargetType::Money`] or [`TargetType::Subscribers`].
///
/// # Returns
///
/// A [`Target`] object deserialized from the JSON response body.
///
/// # Errors
///
/// - [`ApiError::HttpRequest`] — if the network request fails.
/// - [`ApiError::JsonParse`] — if the response body cannot be parsed as valid JSON.
/// - [`ApiError::Deserialization`] — if the JSON does not match the [`Target`] structure.
pub async fn create_blog_target(
&self,
blog_name: &str,
description: &str,
target_sum: f64,
target_type: TargetType,
) -> ResultApi<Target> {
let path = match target_type {
TargetType::Money => "target/money",
TargetType::Subscribers => "target/subscribers",
};
let form = NewTarget {
blog_url: blog_name.into(),
description: description.into(),
target_sum,
};
let response = self.post_request(path, &form, true).await?;
let response = self.handle_response(path, response).await?;
self.parse_json(response).await
}
/// Delete a target by its ID.
///
/// # Parameters
///
/// - `target_id`: numerical ID of the target to delete.
///
/// # Returns
///
/// `()` on success. The API returns 200 OK with an empty JSON body.
///
/// # Errors
///
/// - [`ApiError::HttpRequest`] — if the network request fails.
/// - [`ApiError::JsonParse`] — if the response body cannot be parsed as JSON (rare for DELETE).
pub async fn delete_blog_target(&self, target_id: u64) -> ResultApi<()> {
let path = format!("target/{}", target_id);
let response = self.delete_request(&path).await?;
let _ = response
.json::<serde_json::Value>()
.await
.map_err(ApiError::JsonParse)?;
Ok(())
}
/// Update an existing target by its ID.
///
/// # Parameters
///
/// - `target_id`: numerical ID of the target.
/// - `description`: new textual description of the target.
/// - `target_sum`: new target amount.
///
/// # Returns
///
/// Updated [`Target`] object.
///
/// # Errors
///
/// - [`ApiError::HttpRequest`] — if the network request fails.
/// - [`ApiError::JsonParse`] — if JSON parsing fails.
pub async fn update_blog_target(
&self,
target_id: u64,
description: &str,
target_sum: f64,
) -> ResultApi<Target> {
let form = UpdateTarget {
target_id,
description: description.into(),
target_sum,
};
let path = format!("target/{}", target_id);
let response = self.put_request(&path, &form, true).await?;
let response = self.handle_response(&path, response).await?;
self.parse_json(response).await
}
}