tencent_sdk/services/ssl/
upload.rs1use crate::{
2 client::{TencentCloudAsync, TencentCloudBlocking},
3 core::{Endpoint, TencentCloudResult},
4};
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7use std::borrow::Cow;
8
9#[derive(Debug, Deserialize)]
10pub struct UploadCertificateResponse {
11 #[serde(rename = "Response")]
12 pub response: UploadCertificateResult,
13}
14
15#[derive(Debug, Deserialize)]
16pub struct UploadCertificateResult {
17 #[serde(rename = "CertificateId")]
18 pub certificate_id: Option<String>,
19 #[serde(rename = "RepeatCertId")]
20 pub repeat_cert_id: Option<String>,
21 #[serde(rename = "RequestId")]
22 pub request_id: String,
23}
24
25#[derive(Serialize, Clone, Debug, PartialEq)]
26#[serde(untagged)]
27pub enum CertificateType<'a> {
28 #[serde(rename = "CA")]
29 Ca,
30 #[serde(rename = "SVR")]
31 Svr,
32 Custom(&'a str),
33}
34
35impl<'a> From<&'a str> for CertificateType<'a> {
36 fn from(s: &'a str) -> Self {
37 match s.to_uppercase().as_str() {
38 "CA" => CertificateType::Ca,
39 "SVR" => CertificateType::Svr,
40 _ => CertificateType::Custom(s),
41 }
42 }
43}
44
45impl<'a> CertificateType<'a> {
46 pub fn as_str(&self) -> &str {
47 match self {
48 CertificateType::Ca => "CA",
49 CertificateType::Svr => "SVR",
50 CertificateType::Custom(value) => value,
51 }
52 }
53}
54
55#[derive(Serialize, Clone, Debug, PartialEq)]
56#[serde(untagged)]
57pub enum CertificateUse<'a> {
58 #[serde(rename = "CLB")]
59 Clb,
60 #[serde(rename = "CDN")]
61 Cdn,
62 #[serde(rename = "WAF")]
63 Waf,
64 #[serde(rename = "LIVE")]
65 Live,
66 #[serde(rename = "DDOS")]
67 Ddos,
68 Custom(&'a str),
69}
70
71impl<'a> From<&'a str> for CertificateUse<'a> {
72 fn from(s: &'a str) -> Self {
73 match s.to_uppercase().as_str() {
74 "CLB" => CertificateUse::Clb,
75 "CDN" => CertificateUse::Cdn,
76 "WAF" => CertificateUse::Waf,
77 "LIVE" => CertificateUse::Live,
78 "DDOS" => CertificateUse::Ddos,
79 _ => CertificateUse::Custom(s),
80 }
81 }
82}
83
84impl<'a> CertificateUse<'a> {
85 pub fn as_str(&self) -> &str {
86 match self {
87 CertificateUse::Clb => "CLB",
88 CertificateUse::Cdn => "CDN",
89 CertificateUse::Waf => "WAF",
90 CertificateUse::Live => "LIVE",
91 CertificateUse::Ddos => "DDOS",
92 CertificateUse::Custom(value) => value,
93 }
94 }
95}
96
97#[derive(Debug, Serialize)]
98pub struct Tag<'a> {
99 #[serde(rename = "TagKey")]
100 pub key: &'a str,
101 #[serde(rename = "TagValue")]
102 pub value: &'a str,
103}
104
105pub struct UploadCertificate<'a> {
107 pub region: Option<&'a str>,
108 pub certificate_public_key: &'a str,
109 pub certificate_private_key: Option<&'a str>,
110 pub certificate_type: Option<CertificateType<'a>>,
111 pub alias: Option<&'a str>,
112 pub project_id: Option<u64>,
113 pub certificate_use: Option<CertificateUse<'a>>,
114 pub tags: Option<Vec<Tag<'a>>>,
115 pub repeatable: Option<bool>,
116 pub key_password: Option<&'a str>,
117}
118
119impl<'a> UploadCertificate<'a> {
120 pub fn new(certificate_public_key: &'a str) -> Self {
122 Self {
123 region: None,
124 certificate_public_key,
125 certificate_private_key: None,
126 certificate_type: None,
127 alias: None,
128 project_id: None,
129 certificate_use: None,
130 tags: None,
131 repeatable: None,
132 key_password: None,
133 }
134 }
135
136 pub fn with_region(mut self, region: &'a str) -> Self {
138 self.region = Some(region);
139 self
140 }
141
142 pub fn with_private_key(mut self, private_key: &'a str) -> Self {
144 self.certificate_private_key = Some(private_key);
145 self
146 }
147
148 pub fn with_certificate_type(mut self, cert_type: &'a str) -> Self {
150 self.certificate_type = Some(cert_type.into());
151 self
152 }
153
154 pub fn with_alias(mut self, alias: &'a str) -> Self {
156 self.alias = Some(alias);
157 self
158 }
159
160 pub fn with_project_id(mut self, project_id: u64) -> Self {
162 self.project_id = Some(project_id);
163 self
164 }
165
166 pub fn with_certificate_use(mut self, cert_use: &'a str) -> Self {
168 self.certificate_use = Some(cert_use.into());
169 self
170 }
171
172 pub fn with_tag(mut self, key: &'a str, value: &'a str) -> Self {
174 let tag = Tag { key, value };
175 self.tags.get_or_insert_with(Vec::new).push(tag);
176 self
177 }
178
179 pub fn with_repeatable(mut self, repeatable: bool) -> Self {
181 self.repeatable = Some(repeatable);
182 self
183 }
184
185 pub fn with_key_password(mut self, password: &'a str) -> Self {
187 self.key_password = Some(password);
188 self
189 }
190}
191
192impl<'a> Endpoint for UploadCertificate<'a> {
193 type Output = UploadCertificateResponse;
194
195 fn service(&self) -> Cow<'static, str> {
196 Cow::Borrowed("ssl")
197 }
198
199 fn action(&self) -> Cow<'static, str> {
200 Cow::Borrowed("UploadCertificate")
201 }
202
203 fn version(&self) -> Cow<'static, str> {
204 Cow::Borrowed("2019-12-05")
205 }
206
207 fn region(&self) -> Option<Cow<'_, str>> {
208 self.region.map(Cow::Borrowed)
209 }
210
211 fn payload(&self) -> Value {
212 let mut payload = serde_json::json!({
213 "CertificatePublicKey": self.certificate_public_key,
214 });
215
216 if let Some(private_key) = self.certificate_private_key {
217 payload["CertificatePrivateKey"] = serde_json::json!(private_key);
218 }
219 if let Some(cert_type) = &self.certificate_type {
220 payload["CertificateType"] = serde_json::json!(cert_type.as_str());
221 }
222 if let Some(alias) = self.alias {
223 payload["Alias"] = serde_json::json!(alias);
224 }
225 if let Some(project_id) = self.project_id {
226 payload["ProjectId"] = serde_json::json!(project_id);
227 }
228 if let Some(cert_use) = &self.certificate_use {
229 payload["CertificateUse"] = serde_json::json!(cert_use.as_str());
230 }
231 if let Some(tags) = &self.tags {
232 payload["Tags"] = serde_json::json!(tags);
233 }
234 if let Some(repeatable) = self.repeatable {
235 payload["Repeatable"] = serde_json::json!(repeatable);
236 }
237 if let Some(key_password) = self.key_password {
238 payload["KeyPassword"] = serde_json::json!(key_password);
239 }
240
241 payload
242 }
243}
244
245pub async fn upload_certificate_async(
247 client: &TencentCloudAsync,
248 request: &UploadCertificate<'_>,
249) -> TencentCloudResult<UploadCertificateResponse> {
250 client.request(request).await
251}
252
253pub fn upload_certificate_blocking(
255 client: &TencentCloudBlocking,
256 request: &UploadCertificate<'_>,
257) -> TencentCloudResult<UploadCertificateResponse> {
258 client.request(request)
259}
260
261#[cfg(test)]
262mod tests {
263
264 use super::*;
265 use serde_json::json;
266
267 #[test]
268 fn upload_certificate_payload_basic() {
269 let public_key = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----";
270 let private_key = "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----";
271
272 let request = UploadCertificate::new(public_key)
273 .with_private_key(private_key)
274 .with_certificate_type("SVR")
275 .with_alias("my-website-cert")
276 .with_project_id(123456)
277 .with_certificate_use("CLB")
278 .with_repeatable(false);
279
280 let payload = request.payload();
281
282 assert!(payload["CertificatePublicKey"]
283 .as_str()
284 .expect("certificate public key should be string")
285 .contains("BEGIN CERTIFICATE"));
286 assert!(payload["CertificatePrivateKey"]
287 .as_str()
288 .expect("certificate private key should be string")
289 .contains("BEGIN RSA PRIVATE KEY"));
290 assert_eq!(payload["CertificateType"], json!("SVR"));
291 assert_eq!(payload["Alias"], json!("my-website-cert"));
292 assert_eq!(payload["ProjectId"], json!(123456));
293 assert_eq!(payload["CertificateUse"], json!("CLB"));
294 assert_eq!(payload["Repeatable"], json!(false));
295 }
296
297 #[test]
298 fn upload_certificate_payload_ca() {
299 let public_key = "-----BEGIN CERTIFICATE-----\nCA_CERT\n-----END CERTIFICATE-----";
300
301 let request = UploadCertificate::new(public_key)
302 .with_certificate_type("CA")
303 .with_alias("root-ca")
304 .with_repeatable(true);
305
306 let payload = request.payload();
307
308 assert!(payload["CertificatePublicKey"]
309 .as_str()
310 .expect("certificate public key should be string")
311 .contains("CA_CERT"));
312 assert_eq!(payload["CertificateType"], json!("CA"));
313 assert_eq!(payload["Alias"], json!("root-ca"));
314 assert_eq!(payload["Repeatable"], json!(true));
315 assert!(payload.get("CertificatePrivateKey").is_none());
317 }
318
319 #[test]
320 fn upload_certificate_with_tags() {
321 let public_key = "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----";
322
323 let request = UploadCertificate::new(public_key)
324 .with_tag("environment", "production")
325 .with_tag("application", "web-server")
326 .with_tag("owner", "team-a");
327
328 let payload = request.payload();
329
330 let tags = payload["Tags"].as_array().expect("Tags should be an array");
331 assert_eq!(tags.len(), 3);
332
333 assert_eq!(tags[0]["TagKey"], json!("environment"));
335 assert_eq!(tags[0]["TagValue"], json!("production"));
336
337 assert_eq!(tags[1]["TagKey"], json!("application"));
339 assert_eq!(tags[1]["TagValue"], json!("web-server"));
340 }
341
342 #[test]
343 fn deserialize_upload_certificate_response() {
344 let payload = r#"{
345 "Response": {
346 "CertificateId": "cert-abc123xyz",
347 "RepeatCertId": "cert-duplicate456",
348 "RequestId": "req-789def"
349 }
350 }"#;
351
352 let parsed: UploadCertificateResponse =
353 serde_json::from_str(payload).expect("deserialize UploadCertificateResponse");
354
355 assert_eq!(
356 parsed.response.certificate_id.as_deref(),
357 Some("cert-abc123xyz")
358 );
359 assert_eq!(
360 parsed.response.repeat_cert_id.as_deref(),
361 Some("cert-duplicate456")
362 );
363 assert_eq!(parsed.response.request_id, "req-789def");
364 }
365
366 #[test]
367 fn deserialize_upload_certificate_response_without_duplicate() {
368 let payload = r#"{
369 "Response": {
370 "CertificateId": "cert-new-unique",
371 "RequestId": "req-123abc"
372 }
373 }"#;
374
375 let parsed: UploadCertificateResponse =
376 serde_json::from_str(payload).expect("deserialize UploadCertificateResponse");
377
378 assert_eq!(
379 parsed.response.certificate_id.as_deref(),
380 Some("cert-new-unique")
381 );
382 assert!(parsed.response.repeat_cert_id.is_none());
383 assert_eq!(parsed.response.request_id, "req-123abc");
384 }
385
386 #[test]
387 fn certificate_type_enum_conversion() {
388 let ca: CertificateType = "CA".into();
389 let svr: CertificateType = "SVR".into();
390 let custom: CertificateType = "CUSTOM_TYPE".into();
391
392 assert!(matches!(ca, CertificateType::Ca));
393 assert!(matches!(svr, CertificateType::Svr));
394 assert!(matches!(custom, CertificateType::Custom("CUSTOM_TYPE")));
395 }
396
397 #[test]
398 fn certificate_use_enum_conversion() {
399 let uses = ["CLB", "CDN", "WAF", "LIVE", "DDOS", "CUSTOM"];
400
401 for use_str in uses {
402 let cert_use: CertificateUse = use_str.into();
403
404 match use_str {
405 "CLB" => assert!(matches!(cert_use, CertificateUse::Clb)),
406 "CDN" => assert!(matches!(cert_use, CertificateUse::Cdn)),
407 "WAF" => assert!(matches!(cert_use, CertificateUse::Waf)),
408 "LIVE" => assert!(matches!(cert_use, CertificateUse::Live)),
409 "DDOS" => assert!(matches!(cert_use, CertificateUse::Ddos)),
410 _ => assert!(matches!(cert_use, CertificateUse::Custom("CUSTOM"))),
411 }
412 }
413 }
414
415 #[test]
416 fn certificate_enums_serialize_as_bare_strings() {
417 let custom_type: CertificateType = "any-type".into();
418 let custom_use: CertificateUse = "custom-use".into();
419
420 let payload = serde_json::json!({
421 "CertificateType": custom_type,
422 "CertificateUse": custom_use
423 });
424
425 assert_eq!(payload["CertificateType"], json!("any-type"));
426 assert_eq!(payload["CertificateUse"], json!("custom-use"));
427 }
428}