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}