parse_rs/
role.rs

1use crate::acl::ParseACL;
2use crate::error::ParseError;
3use crate::object::{deserialize_string_to_option_parse_date, deserialize_string_to_parse_date};
4use crate::types::common::{Pointer, RelationOp};
5use crate::types::ParseDate; // Assuming ParseDate is in crate::types
6use reqwest::Method;
7use serde::{Deserialize, Serialize};
8use serde_json::Value;
9use std::collections::HashMap;
10
11/// Represents a Parse Role object, used for grouping users and other roles to manage permissions.
12#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
13pub struct ParseRole {
14    /// The unique identifier for the role object.
15    #[serde(rename = "objectId", skip_serializing_if = "Option::is_none")]
16    pub object_id: Option<String>,
17    /// The timestamp when the role was created.
18    #[serde(
19        rename = "createdAt",
20        deserialize_with = "deserialize_string_to_option_parse_date",
21        skip_serializing_if = "Option::is_none"
22    )]
23    pub created_at: Option<ParseDate>,
24    /// The timestamp when the role was last updated.
25    #[serde(
26        rename = "updatedAt",
27        deserialize_with = "deserialize_string_to_option_parse_date",
28        skip_serializing_if = "Option::is_none"
29    )]
30    pub updated_at: Option<ParseDate>,
31    /// The name of the role. This is required and must be unique.
32    /// It can only be set upon creation.
33    pub name: String,
34    /// The Access Control List for this role, determining who can read or write it.
35    #[serde(rename = "ACL")]
36    pub acl: ParseACL,
37    // The 'users' and 'roles' fields are relations and are managed via specific API calls
38    // or through ParseQuery using the $relatedTo operator. They are not typically part of
39    // the direct object representation unless explicitly included and expanded by the server,
40    // which is not the default behavior for direct role object retrieval.
41    /// Placeholder for any other custom fields that might be on a Role object.
42    /// While the _Role class is special, Parse Server might allow adding custom fields.
43    #[serde(flatten, default, skip_serializing_if = "HashMap::is_empty")]
44    pub other_fields: HashMap<String, Value>,
45}
46
47/// Represents the data required to create a new Parse Role.
48#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
49pub struct NewParseRole {
50    /// The name for the new role. Must be unique and is required.
51    pub name: String,
52    /// The Access Control List for the new role. Required.
53    #[serde(rename = "ACL")]
54    pub acl: ParseACL,
55    // TODO: Consider how to represent initial users and roles for creation.
56    // This might involve a different structure or passing relation operations.
57    // For now, keeping it simple: create role, then add relations.
58}
59
60/// Represents the server's response when a new role is successfully created.
61#[derive(Debug, Deserialize, Clone, PartialEq, Eq)]
62pub(crate) struct CreateRoleResponse {
63    #[serde(rename = "objectId")]
64    pub object_id: String,
65    #[serde(
66        rename = "createdAt",
67        deserialize_with = "deserialize_string_to_parse_date"
68    )]
69    pub created_at: ParseDate, // Or String if ParseDate deserialization needs adjustment
70}
71
72impl crate::Parse {
73    // Role management methods
74
75    /// Creates a new Role on the Parse Server.
76    ///
77    /// # Arguments
78    /// * `new_role`: A `NewParseRole` struct containing the name and ACL for the new role.
79    ///
80    /// # Returns
81    /// A `Result` containing the created `ParseRole` or a `ParseError`.
82    /// Note: The `users` and `roles` relations are not populated in the returned object.
83    /// They need to be managed via separate relation operations or queries.
84    pub async fn create_role(&self, new_role: &NewParseRole) -> Result<ParseRole, ParseError> {
85        let endpoint = "roles";
86        // Roles are typically managed with Master Key for security.
87        // For now, defaulting to false, but this might need to be true or configurable.
88        let use_master_key = self.master_key.is_some();
89
90        let response: CreateRoleResponse = self
91            ._request(
92                Method::POST,
93                endpoint,
94                Some(new_role),
95                use_master_key, // Use master key if available for role creation
96                None,           // No specific session token for role creation itself usually
97            )
98            .await?;
99
100        Ok(ParseRole {
101            object_id: Some(response.object_id),
102            created_at: Some(response.created_at),
103            updated_at: None, // Not provided by create response
104            name: new_role.name.clone(),
105            acl: new_role.acl.clone(),
106            other_fields: Default::default(),
107        })
108    }
109
110    /// Retrieves a specific Role by its objectId.
111    ///
112    /// # Arguments
113    /// * `object_id`: The objectId of the role to retrieve.
114    ///
115    /// # Returns
116    /// A `Result` containing the `ParseRole` or a `ParseError`.
117    /// Note: The `users` and `roles` relations are not populated by this call.
118    pub async fn get_role(&self, object_id: &str) -> Result<ParseRole, ParseError> {
119        let endpoint = format!("roles/{}", object_id);
120        // Reading a role might be allowed with different auth types depending on ACL.
121        // Defaulting to standard auth (session token if present, or JS/REST key).
122        // Master key can also be used if needed for roles with restrictive read ACLs.
123        let use_master_key = false; // Or determine based on needs/ACLs if this becomes more complex
124
125        self._request(
126            Method::GET,
127            &endpoint,
128            None::<&()>,
129            use_master_key,
130            self.session_token.as_deref(),
131        )
132        .await
133    }
134
135    /// Deletes a specific Role by its objectId.
136    ///
137    /// # Arguments
138    /// * `object_id`: The objectId of the role to delete.
139    ///
140    /// # Returns
141    /// A `Result` indicating success (`Ok(())`) or a `ParseError`.
142    /// This operation typically requires the Master Key or appropriate user permissions.
143    pub async fn delete_role(&self, object_id: &str) -> Result<(), ParseError> {
144        let endpoint = format!("roles/{}", object_id);
145        // Deleting roles typically requires Master Key or specific user permissions.
146        // Prioritize Master Key if available.
147        let use_master_key = self.master_key.is_some();
148        let session_token_to_use = if use_master_key {
149            None
150        } else {
151            self.session_token.as_deref()
152        };
153
154        let _response: serde_json::Value = self
155            ._request(
156                Method::DELETE,
157                &endpoint,
158                None::<&()>,
159                use_master_key,
160                session_token_to_use,
161            )
162            .await?;
163        // Successful DELETE usually returns an empty body or a simple confirmation
164        // that serde_json::Value can handle. We don't need to use the value.
165        Ok(())
166    }
167
168    /// Adds users to a specific Role.
169    ///
170    /// # Arguments
171    /// * `role_id`: The objectId of the Role to modify.
172    /// * `user_ids`: A slice of objectIds of the Users to add to the role.
173    ///
174    /// # Returns
175    /// A `Result` containing the `ParseDate` of the update or a `ParseError`.
176    /// This operation typically requires the Master Key.
177    pub async fn add_users_to_role(
178        &self,
179        role_id: &str,
180        user_ids: &[&str],
181    ) -> Result<ParseDate, ParseError> {
182        if user_ids.is_empty() {
183            // Or return current updatedAt if we fetch the role first? For now, early return.
184            return Err(ParseError::InvalidInput(
185                "user_ids cannot be empty for AddRelation.".to_string(),
186            ));
187        }
188        let endpoint = format!("roles/{}", role_id);
189        let pointers: Vec<Pointer> = user_ids
190            .iter()
191            .map(|id| Pointer::new("_User", id.to_string()))
192            .collect();
193
194        let relation_op = RelationOp::add(&pointers);
195        let body = serde_json::json!({ "users": relation_op });
196
197        // Modifying role relations typically requires Master Key.
198        let use_master_key = self.master_key.is_some();
199        if !use_master_key {
200            // Potentially return an error or log a warning, as this operation might fail without master key
201            // For now, proceed, but server will likely reject if ACLs are restrictive and no master key.
202        }
203        let session_token_to_use = if use_master_key {
204            None
205        } else {
206            self.session_token.as_deref()
207        };
208
209        #[derive(Deserialize)]
210        struct UpdateResponse {
211            #[serde(rename = "updatedAt")]
212            updated_at: String,
213        }
214
215        let response: UpdateResponse = self
216            ._request(
217                Method::PUT,
218                &endpoint,
219                Some(&body),
220                use_master_key,
221                session_token_to_use,
222            )
223            .await?;
224
225        Ok(ParseDate::new(response.updated_at))
226    }
227
228    /// Removes users from a specific Role.
229    ///
230    /// # Arguments
231    /// * `role_id`: The objectId of the Role to modify.
232    /// * `user_ids`: A slice of objectIds of the Users to remove from the role.
233    ///
234    /// # Returns
235    /// A `Result` containing the `ParseDate` of the update or a `ParseError`.
236    /// This operation typically requires the Master Key.
237    pub async fn remove_users_from_role(
238        &self,
239        role_id: &str,
240        user_ids: &[&str],
241    ) -> Result<ParseDate, ParseError> {
242        if user_ids.is_empty() {
243            return Err(ParseError::InvalidInput(
244                "user_ids cannot be empty for RemoveRelation.".to_string(),
245            ));
246        }
247        let endpoint = format!("roles/{}", role_id);
248        let pointers: Vec<Pointer> = user_ids
249            .iter()
250            .map(|id| Pointer::new("_User", id.to_string()))
251            .collect();
252
253        let relation_op = RelationOp::remove(&pointers);
254        let body = serde_json::json!({ "users": relation_op });
255
256        let use_master_key = self.master_key.is_some();
257        let session_token_to_use = if use_master_key {
258            None
259        } else {
260            self.session_token.as_deref()
261        };
262
263        #[derive(Deserialize)]
264        struct UpdateResponse {
265            #[serde(rename = "updatedAt")]
266            updated_at: String,
267        }
268
269        let response: UpdateResponse = self
270            ._request(
271                Method::PUT,
272                &endpoint,
273                Some(&body),
274                use_master_key,
275                session_token_to_use,
276            )
277            .await?;
278
279        Ok(ParseDate::new(response.updated_at))
280    }
281
282    /// Adds child roles to a specific (parent) Role.
283    ///
284    /// # Arguments
285    /// * `role_id`: The objectId of the parent Role to modify.
286    /// * `child_role_ids`: A slice of objectIds of the child Roles to add to the parent role.
287    ///
288    /// # Returns
289    /// A `Result` containing the `ParseDate` of the update or a `ParseError`.
290    /// This operation typically requires the Master Key.
291    pub async fn add_child_roles_to_role(
292        &self,
293        role_id: &str,
294        child_role_ids: &[&str],
295    ) -> Result<ParseDate, ParseError> {
296        if child_role_ids.is_empty() {
297            return Err(ParseError::InvalidInput(
298                "child_role_ids cannot be empty for AddRelation.".to_string(),
299            ));
300        }
301        let endpoint = format!("roles/{}", role_id);
302        let pointers: Vec<Pointer> = child_role_ids
303            .iter()
304            .map(|id| Pointer::new("_Role", id.to_string()))
305            .collect();
306
307        let relation_op = RelationOp::add(&pointers);
308        let body = serde_json::json!({ "roles": relation_op });
309
310        let use_master_key = self.master_key.is_some();
311        let session_token_to_use = if use_master_key {
312            None
313        } else {
314            self.session_token.as_deref()
315        };
316
317        #[derive(Deserialize)]
318        struct UpdateResponse {
319            #[serde(rename = "updatedAt")]
320            updated_at: String,
321        }
322
323        let response: UpdateResponse = self
324            ._request(
325                Method::PUT,
326                &endpoint,
327                Some(&body),
328                use_master_key,
329                session_token_to_use,
330            )
331            .await?;
332
333        Ok(ParseDate::new(response.updated_at))
334    }
335
336    /// Removes child roles from a specific (parent) Role.
337    ///
338    /// # Arguments
339    /// * `role_id`: The objectId of the parent Role to modify.
340    /// * `child_role_ids`: A slice of objectIds of the child Roles to remove from the parent role.
341    ///
342    /// # Returns
343    /// A `Result` containing the `ParseDate` of the update or a `ParseError`.
344    /// This operation typically requires the Master Key.
345    pub async fn remove_child_roles_from_role(
346        &self,
347        role_id: &str,
348        child_role_ids: &[&str],
349    ) -> Result<ParseDate, ParseError> {
350        let endpoint = format!("roles/{}", role_id);
351        let pointers: Vec<Pointer> = child_role_ids
352            .iter()
353            .map(|&id| Pointer::new("_Role", id)) // Corrected to _Role
354            .collect();
355        let relation_op = RelationOp::remove(&pointers); // Use remove
356        let mut body = std::collections::HashMap::new();
357        body.insert("roles", relation_op); // The field name for role-to-role relations is "roles"
358
359        // Define a local struct for the expected response, similar to add_child_roles_to_role
360        #[derive(Deserialize)]
361        struct UpdateResponse {
362            #[serde(rename = "updatedAt")]
363            updated_at: String,
364        }
365
366        let response: UpdateResponse = self
367            ._request(
368                Method::PUT,
369                &endpoint,
370                Some(&body),
371                true, // use_master_key
372                None, // session_token
373            )
374            .await?;
375        Ok(ParseDate::new(response.updated_at))
376    }
377}