1use async_trait::async_trait;
9use reqwest::Method;
10use serde::{Deserialize, Serialize};
11use smbcloud_ascapi_core::jsonapi::{
12 CreateBody, CreateData, Document, Resource, ResourceId, ToOne, UpdateBody, UpdateData,
13};
14use smbcloud_ascapi_core::Client;
15use smbcloud_ascapi_core::Result;
16
17pub const RESOURCE_TYPE: &str = "betaBuildLocalizations";
18
19#[derive(Debug, Clone, Serialize, Deserialize)]
21#[serde(rename_all = "camelCase")]
22pub struct BetaBuildLocalizationAttributes {
23 pub locale: Option<String>,
25 pub whats_new: Option<String>,
27}
28
29pub type BetaBuildLocalization = Resource<BetaBuildLocalizationAttributes>;
31
32#[derive(Debug, Clone, Serialize)]
35#[serde(rename_all = "camelCase")]
36struct CreateAttributes {
37 locale: String,
38 whats_new: Option<String>,
39}
40
41#[derive(Debug, Clone, Serialize)]
42struct CreateRelationships {
43 build: ToOne,
44}
45
46#[derive(Debug, Clone, Serialize)]
47#[serde(rename_all = "camelCase")]
48struct UpdateAttributes {
49 whats_new: String,
50}
51
52#[async_trait]
61pub trait BetaBuildLocalizationsApi {
62 async fn list_beta_build_localizations(
65 &self,
66 build_id: &str,
67 ) -> Result<Vec<BetaBuildLocalization>>;
68
69 async fn get_beta_build_localization(&self, id: &str) -> Result<BetaBuildLocalization>;
71
72 async fn create_beta_build_localization(
77 &self,
78 build_id: &str,
79 locale: &str,
80 whats_new: Option<&str>,
81 ) -> Result<BetaBuildLocalization>;
82
83 async fn update_beta_build_localization(
86 &self,
87 id: &str,
88 whats_new: &str,
89 ) -> Result<BetaBuildLocalization>;
90}
91
92#[async_trait]
93impl BetaBuildLocalizationsApi for Client {
94 async fn list_beta_build_localizations(
95 &self,
96 build_id: &str,
97 ) -> Result<Vec<BetaBuildLocalization>> {
98 self.list_all::<BetaBuildLocalizationAttributes>(
99 "/v1/betaBuildLocalizations",
100 &[("filter[build]", build_id), ("limit", "200")],
101 )
102 .await
103 }
104
105 async fn get_beta_build_localization(&self, id: &str) -> Result<BetaBuildLocalization> {
106 let path = format!("/v1/betaBuildLocalizations/{id}");
107 let doc: Document<BetaBuildLocalizationAttributes> =
108 self.request(Method::GET, &path, &[], None::<&()>).await?;
109 Ok(doc.data)
110 }
111
112 async fn create_beta_build_localization(
113 &self,
114 build_id: &str,
115 locale: &str,
116 whats_new: Option<&str>,
117 ) -> Result<BetaBuildLocalization> {
118 let body = CreateBody {
119 data: CreateData {
120 resource_type: RESOURCE_TYPE,
121 attributes: CreateAttributes {
122 locale: locale.to_string(),
123 whats_new: whats_new.map(str::to_string),
124 },
125 relationships: Some(CreateRelationships {
126 build: ToOne {
127 data: ResourceId {
128 resource_type: crate::build::RESOURCE_TYPE,
129 id: build_id.to_string(),
130 },
131 },
132 }),
133 },
134 };
135 let doc: Document<BetaBuildLocalizationAttributes> = self
136 .request(Method::POST, "/v1/betaBuildLocalizations", &[], Some(&body))
137 .await?;
138 Ok(doc.data)
139 }
140
141 async fn update_beta_build_localization(
142 &self,
143 id: &str,
144 whats_new: &str,
145 ) -> Result<BetaBuildLocalization> {
146 let path = format!("/v1/betaBuildLocalizations/{id}");
147 let body = UpdateBody {
148 data: UpdateData {
149 resource_type: RESOURCE_TYPE,
150 id: id.to_string(),
151 attributes: UpdateAttributes {
152 whats_new: whats_new.to_string(),
153 },
154 },
155 };
156 let doc: Document<BetaBuildLocalizationAttributes> =
157 self.request(Method::PATCH, &path, &[], Some(&body)).await?;
158 Ok(doc.data)
159 }
160}
161
162#[cfg(test)]
163mod tests {
164 use super::*;
165 use smbcloud_ascapi_core::jsonapi::ListDocument;
166
167 #[test]
168 fn deserializes_a_localization_list() {
169 let body = serde_json::json!({
170 "data": [
171 {
172 "id": "LOC1",
173 "type": "betaBuildLocalizations",
174 "attributes": {
175 "locale": "en-US",
176 "whatsNew": "Bug fixes and performance improvements."
177 }
178 },
179 {
180 "id": "LOC2",
181 "type": "betaBuildLocalizations",
182 "attributes": {
183 "locale": "ja",
184 "whatsNew": "バグ修正とパフォーマンス改善。"
185 }
186 }
187 ]
188 });
189
190 let doc: ListDocument<BetaBuildLocalizationAttributes> =
191 serde_json::from_value(body).expect("localization list must deserialize");
192 assert_eq!(doc.data.len(), 2);
193
194 let en = &doc.data[0];
195 assert_eq!(en.id, "LOC1");
196 assert_eq!(en.attributes.locale.as_deref(), Some("en-US"));
197 assert_eq!(
198 en.attributes.whats_new.as_deref(),
199 Some("Bug fixes and performance improvements.")
200 );
201
202 let ja = &doc.data[1];
203 assert_eq!(ja.attributes.locale.as_deref(), Some("ja"));
204 }
205
206 #[test]
207 fn create_body_serializes_filter_key() {
208 let query: Vec<(&str, &str)> = vec![("filter[build]", "BUILD1"), ("limit", "200")];
210 assert_eq!(query[0].0, "filter[build]");
211 assert_eq!(query[0].1, "BUILD1");
212 }
213
214 #[test]
215 fn create_body_without_whats_new_omits_the_field() {
216 let body = CreateBody {
220 data: CreateData {
221 resource_type: RESOURCE_TYPE,
222 attributes: CreateAttributes {
223 locale: "en-US".into(),
224 whats_new: None,
225 },
226 relationships: None::<()>,
227 },
228 };
229 let v = serde_json::to_value(&body).unwrap();
230 let attrs = &v["data"]["attributes"];
231 assert_eq!(attrs["locale"], "en-US");
232 assert!(attrs["whatsNew"].is_null());
233 }
234}