Skip to main content

ossify/ops/object/acl/
put_object_acl.rs

1//! PutObjectACL: set the access permissions on an existing object.
2//!
3//! The ACL is passed via the `x-oss-object-acl` header, not in the body.
4//!
5//! Official document: <https://www.alibabacloud.com/help/en/oss/developer-reference/putobjectacl>
6
7use std::future::Future;
8
9use http::{HeaderMap, HeaderName, Method};
10use serde::Serialize;
11
12use crate::body::ZeroBody;
13use crate::error::Result;
14use crate::ops::common::ObjectAcl;
15use crate::response::EmptyResponseProcessor;
16use crate::ser::OnlyKeyField;
17use crate::{Client, Ops, Prepared, Request};
18
19/// PutObjectACL query parameters: `?acl[&versionId=<id>]`.
20#[derive(Debug, Clone, Default, Serialize)]
21#[serde(rename_all = "camelCase")]
22pub struct PutObjectAclParams {
23    pub(crate) acl: OnlyKeyField,
24    #[serde(skip_serializing_if = "Option::is_none")]
25    pub version_id: Option<String>,
26}
27
28impl PutObjectAclParams {
29    pub fn new() -> Self {
30        Self::default()
31    }
32
33    pub fn version_id(mut self, v: impl Into<String>) -> Self {
34        self.version_id = Some(v.into());
35        self
36    }
37}
38
39/// PutObjectACL operation.
40pub struct PutObjectAcl {
41    pub object_key: String,
42    pub params: PutObjectAclParams,
43    pub acl: ObjectAcl,
44}
45
46impl Ops for PutObjectAcl {
47    type Response = EmptyResponseProcessor;
48    type Body = ZeroBody;
49    type Query = PutObjectAclParams;
50
51    fn prepare(self) -> Result<Prepared<PutObjectAclParams>> {
52        let mut headers = HeaderMap::new();
53        headers.insert(HeaderName::from_static("x-oss-object-acl"), self.acl.as_str().parse()?);
54        Ok(Prepared {
55            method: Method::PUT,
56            key: Some(self.object_key),
57            query: Some(self.params),
58            headers: Some(headers),
59            body: Some(()),
60            ..Default::default()
61        })
62    }
63}
64
65/// Trait for PutObjectACL operations.
66pub trait PutObjectAclOperations {
67    /// Set the ACL of an object.
68    fn put_object_acl(
69        &self,
70        object_key: impl Into<String>,
71        acl: ObjectAcl,
72        params: Option<PutObjectAclParams>,
73    ) -> impl Future<Output = Result<()>>;
74}
75
76impl PutObjectAclOperations for Client {
77    async fn put_object_acl(
78        &self,
79        object_key: impl Into<String>,
80        acl: ObjectAcl,
81        params: Option<PutObjectAclParams>,
82    ) -> Result<()> {
83        let ops = PutObjectAcl {
84            object_key: object_key.into(),
85            params: params.unwrap_or_default(),
86            acl,
87        };
88        self.request(ops).await
89    }
90}
91
92#[cfg(test)]
93mod tests {
94    use super::*;
95
96    #[test]
97    fn test_serialize_params_default() {
98        let q = crate::ser::to_string(&PutObjectAclParams::default()).unwrap();
99        assert_eq!(q, "acl");
100    }
101
102    #[test]
103    fn test_serialize_params_with_version() {
104        let q = crate::ser::to_string(&PutObjectAclParams::new().version_id("v1")).unwrap();
105        assert_eq!(q, "acl&versionId=v1");
106    }
107
108    #[test]
109    fn test_prepare_header() {
110        let p = PutObjectAcl {
111            object_key: "foo.jpg".into(),
112            params: PutObjectAclParams::new(),
113            acl: ObjectAcl::PublicRead,
114        }
115        .prepare()
116        .unwrap();
117        assert_eq!(p.method, Method::PUT);
118        assert_eq!(p.key.as_deref(), Some("foo.jpg"));
119        assert_eq!(p.headers.unwrap().get("x-oss-object-acl").unwrap(), "public-read");
120    }
121}