Skip to main content

ali_oss_rs/blocking/
tagging.rs

1//! Object tagging module
2
3use std::collections::HashMap;
4
5use crate::tagging_common::{
6    build_delete_object_tag_request, build_get_object_tag_request, build_put_object_tag_request, parse_tags_from_xml, DeleteObjectTagOptions,
7    GetObjectTagOptions, PutObjectTagOptions,
8};
9use crate::Result;
10
11use super::Client;
12
13pub trait ObjectTagOperations {
14    /// Get object taggings
15    ///
16    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/getobjecttagging>
17    fn get_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, options: Option<GetObjectTagOptions>) -> Result<HashMap<String, String>>
18    where
19        S1: AsRef<str>,
20        S2: AsRef<str>;
21
22    /// Put object taggings
23    ///
24    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/putobjecttagging>
25    fn put_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, tags: HashMap<String, String>, options: Option<PutObjectTagOptions>) -> Result<()>
26    where
27        S1: AsRef<str>,
28        S2: AsRef<str>;
29
30    /// Delete object taggings
31    ///
32    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/deleteobjecttagging>
33    fn delete_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, options: Option<DeleteObjectTagOptions>) -> Result<()>
34    where
35        S1: AsRef<str>,
36        S2: AsRef<str>;
37}
38
39impl ObjectTagOperations for Client {
40    /// Get object taggings
41    ///
42    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/getobjecttagging>
43    fn get_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, options: Option<GetObjectTagOptions>) -> Result<HashMap<String, String>>
44    where
45        S1: AsRef<str>,
46        S2: AsRef<str>,
47    {
48        let request = build_get_object_tag_request(bucket_name.as_ref(), object_key.as_ref(), &options)?;
49        let (_, xml) = self.do_request::<String>(request)?;
50        parse_tags_from_xml(xml)
51    }
52
53    /// Put object taggings
54    ///
55    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/putobjecttagging>
56    fn put_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, tags: HashMap<String, String>, options: Option<PutObjectTagOptions>) -> Result<()>
57    where
58        S1: AsRef<str>,
59        S2: AsRef<str>,
60    {
61        let request = build_put_object_tag_request(bucket_name.as_ref(), object_key.as_ref(), &tags, &options)?;
62        let _ = self.do_request::<()>(request)?;
63        Ok(())
64    }
65
66    /// Delete object taggings
67    ///
68    /// Official document: <https://help.aliyun.com/zh/oss/developer-reference/deleteobjecttagging>
69    fn delete_object_tags<S1, S2>(&self, bucket_name: S1, object_key: S2, options: Option<DeleteObjectTagOptions>) -> Result<()>
70    where
71        S1: AsRef<str>,
72        S2: AsRef<str>,
73    {
74        let request = build_delete_object_tag_request(bucket_name.as_ref(), object_key.as_ref(), &options)?;
75        let _ = self.do_request::<()>(request)?;
76        Ok(())
77    }
78}
79
80#[cfg(all(test, feature = "blocking"))]
81mod test_tagging_blocking {
82    use std::{collections::HashMap, sync::Once};
83
84    use uuid::Uuid;
85
86    use crate::{
87        blocking::{object::ObjectOperations, tagging::ObjectTagOperations},
88        object_common::{HeadObjectOptionsBuilder, PutObjectApiResponse, PutObjectOptionsBuilder, PutObjectResult},
89        tagging_common::{GetObjectTagOptions, PutObjectTagOptions},
90    };
91
92    use super::Client;
93
94    static INIT: Once = Once::new();
95
96    fn setup() {
97        INIT.call_once(|| {
98            simple_logger::init_with_level(log::Level::Debug).unwrap();
99            dotenvy::dotenv().unwrap();
100        });
101    }
102
103    #[test]
104    fn test_tagging_blocking() {
105        log::debug!("test object tagging");
106        setup();
107        let client = Client::from_env();
108
109        let bucket_name = "yuanyq-2";
110        let object_key = format!("ali-oss-rs-test/{}.webp", Uuid::new_v4());
111        let file_path = "/home/yuanyq/Pictures/test-8.webp";
112
113        let options = PutObjectOptionsBuilder::new().tag("tag-a", "tag-value-a").build();
114
115        let res = client.put_object_from_file(bucket_name, &object_key, file_path, Some(options));
116        assert!(res.is_ok());
117
118        let ret = res.unwrap();
119
120        if let PutObjectResult::ApiResponse(PutObjectApiResponse {
121            request_id: _,
122            etag: _,
123            content_md5: _,
124            hash_crc64ecma: _,
125            version_id,
126        }) = ret
127        {
128            assert!(version_id.is_some());
129        } else {
130            panic!("response type does not match");
131        }
132
133        log::debug!("create a new version");
134
135        let options = PutObjectOptionsBuilder::new().tag("tag-a", "tag-value-a").build();
136
137        let res = client.put_object_from_file(bucket_name, &object_key, file_path, Some(options));
138        assert!(res.is_ok());
139
140        let ret = res.unwrap();
141
142        let version_id = if let PutObjectResult::ApiResponse(PutObjectApiResponse {
143            request_id: _,
144            etag: _,
145            content_md5: _,
146            hash_crc64ecma: _,
147            version_id,
148        }) = ret
149        {
150            assert!(version_id.is_some());
151            version_id.unwrap()
152        } else {
153            panic!("response type does not match");
154        };
155
156        log::debug!("last version id: {}", version_id);
157
158        let res = client.head_object(bucket_name, &object_key, Some(HeadObjectOptionsBuilder::new().version_id(&version_id).build()));
159
160        let ret = res.unwrap();
161        assert_eq!(Some(1), ret.tag_count);
162
163        let res = client.get_object_tags(
164            bucket_name,
165            &object_key,
166            Some(GetObjectTagOptions {
167                version_id: Some(version_id.clone()),
168            }),
169        );
170        log::debug!("get object tag response: {:#?}", res);
171        assert!(res.is_ok());
172        let ret = res.unwrap();
173        assert!(ret.contains_key("tag-a"));
174        assert_eq!("tag-value-a", ret.get("tag-a").unwrap());
175
176        let new_tags = HashMap::from([
177            ("tag-b".to_string(), "tag-value-b".to_string()),
178            ("tag-c".to_string(), "tag-value-c".to_string()),
179        ]);
180
181        let _ = client.put_object_tags(
182            bucket_name,
183            &object_key,
184            new_tags,
185            Some(PutObjectTagOptions {
186                version_id: Some(version_id.clone()),
187            }),
188        );
189
190        let res = client.get_object_tags(
191            bucket_name,
192            &object_key,
193            Some(GetObjectTagOptions {
194                version_id: Some(version_id.clone()),
195            }),
196        );
197        log::debug!("get object tag response: {:#?}", res);
198        assert!(res.is_ok());
199
200        let ret = res.unwrap();
201        assert!(ret.contains_key("tag-b"));
202        assert_eq!("tag-value-b", ret.get("tag-b").unwrap());
203
204        assert!(ret.contains_key("tag-c"));
205        assert_eq!("tag-value-c", ret.get("tag-c").unwrap());
206
207        let _ = client.delete_object_tags(bucket_name, &object_key, None);
208
209        let res = client.get_object_tags(
210            bucket_name,
211            &object_key,
212            Some(GetObjectTagOptions {
213                version_id: Some(version_id.clone()),
214            }),
215        );
216        log::debug!("get object tag response: {:#?}", res);
217        assert!(res.is_ok());
218        let ret = res.unwrap();
219        assert!(ret.is_empty());
220
221        let _ = client.delete_object(bucket_name, &object_key, None);
222    }
223}