Skip to main content

ali_oss_rs/
tagging.rs

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