cloud_storage_rs/resources/
bucket_access_control.rs

1use crate::error::GoogleResponse;
2use crate::resources::common::ListResponse;
3pub use crate::resources::common::{Entity, ProjectTeam, Role};
4
5/// The BucketAccessControl resource represents the Access Control Lists (ACLs) for buckets within
6/// Google Cloud Storage. ACLs let you specify who has access to your data and to what extent.
7///
8/// ```text,ignore
9/// Important: This method fails with a 400 Bad Request response for buckets with uniform
10/// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
11/// control access instead.
12/// ```
13///
14/// There are three roles that can be assigned to an entity:
15///
16/// * READERs can get the bucket, though no acl property will be returned, and list the bucket's
17/// objects.
18/// * WRITERs are READERs, and they can insert objects into the bucket and delete the bucket's
19/// objects.
20/// * OWNERs are WRITERs, and they can get the acl property of a bucket, update a bucket, and call
21/// all BucketAccessControl methods on the bucket.
22#[derive(Debug, PartialEq, serde::Serialize, serde::Deserialize)]
23#[serde(rename_all = "camelCase")]
24pub struct BucketAccessControl {
25    /// The kind of item this is. For bucket access control entries, this is always storage#bucketAccessControl.
26    pub kind: String,
27    /// The ID of the access-control entry.
28    pub id: String,
29    /// The link to this access-control entry.
30    pub self_link: String,
31    /// The name of the bucket.
32    pub bucket: String,
33    /// The entity holding the permission, in one of the following forms:
34    ///
35    /// * `user-userId`
36    /// * `user-email`
37    /// * `group-groupId`
38    /// * `group-email`
39    /// * `domain-domain`
40    /// * `project-team-projectId`
41    /// * `allUsers`
42    /// * `allAuthenticatedUsers`
43    ///
44    /// Examples:
45    ///
46    /// * The user liz@example.com would be user-liz@example.com.
47    /// * The group example@googlegroups.com would be group-example@googlegroups.com.
48    /// * To refer to all members of the G Suite for Business domain example.com, the entity would
49    /// be domain-example.com.
50    pub entity: Entity,
51    /// The access permission for the entity.
52    pub role: Role,
53    /// The email address associated with the entity, if any.
54    pub email: Option<String>,
55    /// The ID for the entity, if any.
56    pub entity_id: Option<String>,
57    /// The domain associated with the entity, if any.
58    pub domain: Option<String>,
59    /// The project team associated with the entity, if any.
60    pub project_team: Option<ProjectTeam>,
61    /// HTTP 1.1 Entity tag for the access-control entry.
62    pub etag: String,
63}
64
65/// Model that can be used to create a new BucketAccessControl object.
66#[derive(Debug, PartialEq, serde::Serialize)]
67#[serde(rename_all = "camelCase")]
68pub struct NewBucketAccessControl {
69    /// The entity holding the permission, in one of the following forms:
70    ///
71    /// * `user-userId`
72    /// * `user-email`
73    /// * `group-groupId`
74    /// * `group-email`
75    /// * `domain-domain`
76    /// * `project-team-projectId`
77    /// * `allUsers`
78    /// * `allAuthenticatedUsers`
79    ///
80    /// Examples:
81    ///
82    /// * The user liz@example.com would be user-liz@example.com.
83    /// * The group example@googlegroups.com would be group-example@googlegroups.com.
84    /// * To refer to all members of the G Suite for Business domain example.com, the entity would
85    /// be domain-example.com.
86    pub entity: Entity,
87    /// The access permission for the entity.
88    pub role: Role,
89}
90
91impl BucketAccessControl {
92    /// Create a new `BucketAccessControl` using the provided `NewBucketAccessControl`, related to
93    /// the `Bucket` provided by the `bucket_name` argument.
94    ///
95    /// ### Important
96    /// Important: This method fails with a 400 Bad Request response for buckets with uniform
97    /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
98    /// control access instead.
99    /// ### Example
100    /// ```rust,no_run
101    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
102    /// use cloud_storage::bucket_access_control::{BucketAccessControl, NewBucketAccessControl};
103    /// use cloud_storage::bucket_access_control::{Role, Entity};
104    ///
105    /// let new_bucket_access_control = NewBucketAccessControl {
106    ///     entity: Entity::AllUsers,
107    ///     role: Role::Reader,
108    /// };
109    /// BucketAccessControl::create("mybucket", &new_bucket_access_control)?;
110    /// # Ok(())
111    /// # }
112    /// ```
113    pub fn create(
114        bucket: &str,
115        new_bucket_access_control: &NewBucketAccessControl,
116    ) -> Result<Self, crate::Error> {
117        let url = format!("{}/b/{}/acl", crate::BASE_URL, bucket);
118        let client = reqwest::blocking::Client::new();
119        let result: GoogleResponse<Self> = client
120            .post(&url)
121            .headers(crate::get_headers()?)
122            .json(new_bucket_access_control)
123            .send()?
124            .json()?;
125        match result {
126            GoogleResponse::Success(s) => Ok(s),
127            GoogleResponse::Error(e) => Err(e.into()),
128        }
129    }
130
131    /// Returns all `BucketAccessControl`s related to this bucket.
132    ///
133    /// ### Important
134    /// Important: This method fails with a 400 Bad Request response for buckets with uniform
135    /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
136    /// control access instead.
137    /// ### Example
138    /// ```rust,no_run
139    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
140    /// use cloud_storage::bucket_access_control::BucketAccessControl;
141    ///
142    /// let acls = BucketAccessControl::list("mybucket")?;
143    /// # Ok(())
144    /// # }
145    /// ```
146    pub fn list(bucket: &str) -> Result<Vec<Self>, crate::Error> {
147        let url = format!("{}/b/{}/acl", crate::BASE_URL, bucket);
148        let client = reqwest::blocking::Client::new();
149        let result: GoogleResponse<ListResponse<Self>> = client
150            .get(&url)
151            .headers(crate::get_headers()?)
152            .send()?
153            .json()?;
154        match result {
155            GoogleResponse::Success(s) => Ok(s.items),
156            GoogleResponse::Error(e) => Err(e.into()),
157        }
158    }
159
160    /// Returns the ACL entry for the specified entity on the specified bucket.
161    ///
162    /// ### Important
163    /// Important: This method fails with a 400 Bad Request response for buckets with uniform
164    /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
165    /// control access instead.
166    /// ### Example
167    /// ```rust,no_run
168    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
169    /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
170    ///
171    /// let controls = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
172    /// # Ok(())
173    /// # }
174    /// ```
175    pub fn read(bucket: &str, entity: &Entity) -> Result<Self, crate::Error> {
176        let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, bucket, entity);
177        let client = reqwest::blocking::Client::new();
178        let result: GoogleResponse<Self> = client
179            .get(&url)
180            .headers(crate::get_headers()?)
181            .send()?
182            .json()?;
183        match result {
184            GoogleResponse::Success(s) => Ok(s),
185            GoogleResponse::Error(e) => Err(e.into()),
186        }
187    }
188
189    /// Update this `BucketAccessControl`.
190    ///
191    /// ### Important
192    /// Important: This method fails with a 400 Bad Request response for buckets with uniform
193    /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
194    /// control access instead.
195    /// ### Example
196    /// ```rust,no_run
197    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
198    /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
199    ///
200    /// let mut acl = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
201    /// acl.entity = Entity::AllAuthenticatedUsers;
202    /// # Ok(())
203    /// # }
204    /// ```
205    pub fn update(&self) -> Result<Self, crate::Error> {
206        let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, self.bucket, self.entity);
207        let client = reqwest::blocking::Client::new();
208        let result: GoogleResponse<Self> = client
209            .put(&url)
210            .headers(crate::get_headers()?)
211            .json(self)
212            .send()?
213            .json()?;
214        match result {
215            GoogleResponse::Success(s) => Ok(s),
216            GoogleResponse::Error(e) => Err(e.into()),
217        }
218    }
219
220    /// Permanently deletes the ACL entry for the specified entity on the specified bucket.
221    ///
222    /// ### Important
223    /// Important: This method fails with a 400 Bad Request response for buckets with uniform
224    /// bucket-level access enabled. Use `Bucket::get_iam_policy` and `Bucket::set_iam_policy` to
225    /// control access instead.
226    /// ### Example
227    /// ```rust,no_run
228    /// # fn main() -> Result<(), Box<dyn std::error::Error>> {
229    /// use cloud_storage::bucket_access_control::{BucketAccessControl, Entity};
230    ///
231    /// let controls = BucketAccessControl::read("mybucket", &Entity::AllUsers)?;
232    /// controls.delete()?;
233    /// # Ok(())
234    /// # }
235    /// ```
236    pub fn delete(self) -> Result<(), crate::Error> {
237        let url = format!("{}/b/{}/acl/{}", crate::BASE_URL, self.bucket, self.entity);
238        let client = reqwest::blocking::Client::new();
239        let response = client.delete(&url).headers(crate::get_headers()?).send()?;
240        if response.status().is_success() {
241            Ok(())
242        } else {
243            Err(crate::Error::Google(response.json()?))
244        }
245    }
246}
247
248#[cfg(test)]
249mod tests {
250    use super::*;
251
252    #[test]
253    fn create() -> Result<(), Box<dyn std::error::Error>> {
254        let bucket = crate::read_test_bucket();
255        let new_bucket_access_control = NewBucketAccessControl {
256            entity: Entity::AllUsers,
257            role: Role::Reader,
258        };
259        BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
260        Ok(())
261    }
262
263    #[test]
264    fn list() -> Result<(), Box<dyn std::error::Error>> {
265        let bucket = crate::read_test_bucket();
266        BucketAccessControl::list(&bucket.name)?;
267        Ok(())
268    }
269
270    #[test]
271    fn read() -> Result<(), Box<dyn std::error::Error>> {
272        let bucket = crate::read_test_bucket();
273        BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
274        Ok(())
275    }
276
277    #[test]
278    fn update() -> Result<(), Box<dyn std::error::Error>> {
279        // use a seperate bucket to prevent synchronization issues
280        let bucket = crate::create_test_bucket("test-update-bucket-access-controls");
281        let new_bucket_access_control = NewBucketAccessControl {
282            entity: Entity::AllUsers,
283            role: Role::Reader,
284        };
285        BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
286        let mut acl = BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
287        acl.entity = Entity::AllAuthenticatedUsers;
288        acl.update()?;
289        bucket.delete()?;
290        Ok(())
291    }
292
293    #[test]
294    fn delete() -> Result<(), Box<dyn std::error::Error>> {
295        // use a seperate bucket to prevent synchronization issues
296        let bucket = crate::create_test_bucket("test-delete-bucket-access-controls");
297        let new_bucket_access_control = NewBucketAccessControl {
298            entity: Entity::AllUsers,
299            role: Role::Reader,
300        };
301        BucketAccessControl::create(&bucket.name, &new_bucket_access_control)?;
302        let acl = BucketAccessControl::read(&bucket.name, &Entity::AllUsers)?;
303        acl.delete()?;
304        bucket.delete()?;
305        Ok(())
306    }
307}