create_rust_app/auth/permissions/
mod.rs

1mod role_permission;
2mod user_permission;
3mod user_role;
4
5pub use role_permission::{RolePermission, RolePermissionChangeset};
6use std::hash::{Hash, Hasher};
7pub use user_permission::{UserPermission, UserPermissionChangeset};
8pub use user_role::{UserRole, UserRoleChangeset};
9
10use crate::database::Connection;
11use anyhow::Result;
12use diesel::{
13    sql_query,
14    sql_types::{Integer, Text},
15    RunQueryDsl,
16};
17use serde::{Deserialize, Serialize};
18
19use crate::auth::ID;
20
21pub struct Role;
22
23#[derive(Debug, Serialize, Deserialize, QueryableByName, Clone)]
24struct RoleQueryRow {
25    #[diesel(sql_type=Text)]
26    role: String,
27}
28
29impl Role {
30    /// assign `role` to the User whose id is [`user_id`](`ID`)
31    ///
32    /// Returns true if successful
33    ///
34    /// # Errors
35    /// * infallible
36    ///
37    /// TODO: don't return a result if we never fail, or return a result and not a bool
38    pub fn assign(db: &mut Connection, user_id: ID, role: &str) -> Result<bool> {
39        let assigned = UserRole::create(
40            db,
41            &UserRoleChangeset {
42                user_id,
43                role: role.to_string(),
44            },
45        );
46
47        Ok(assigned.is_ok())
48    }
49
50    /// assigns every role in `roles` to the User whose id is [`user_id`](`ID`)
51    ///
52    /// returns true if successful
53    ///
54    /// # Errors
55    /// * infallible
56    ///
57    /// TODO: don't return a result if we never fail, or return a result and not a bool
58    pub fn assign_many(db: &mut Connection, user_id: ID, roles: Vec<String>) -> Result<bool> {
59        let assigned = UserRole::create_many(
60            db,
61            roles
62                .into_iter()
63                .map(|r| UserRoleChangeset { user_id, role: r })
64                .collect::<Vec<_>>(),
65        );
66
67        Ok(assigned.is_ok())
68    }
69
70    /// unassigns `role` from the User whose id is [`user_id`](`ID`)
71    ///
72    /// returns true if successful
73    ///
74    /// # Errors
75    /// * infallible
76    ///
77    /// TODO: don't return a result if we never fail, or return a result and not a bool
78    pub fn unassign(db: &mut Connection, user_id: ID, role: &str) -> Result<bool> {
79        let unassigned = UserRole::delete(db, user_id, role.to_string());
80
81        Ok(unassigned.is_ok())
82    }
83
84    /// unassigns every role in `roles` from the User whose id is [`user_id`](`ID`)
85    ///
86    /// returns true if successful
87    ///
88    /// # Errors
89    /// * infallible
90    ///
91    /// TODO: don't return a result if we never fail, or return a result and not a bool
92    pub fn unassign_many(db: &mut Connection, user_id: ID, roles: Vec<String>) -> Result<bool> {
93        let unassigned = UserRole::delete_many(db, user_id, roles);
94
95        Ok(unassigned.is_ok())
96    }
97
98    /// returns a vector containing every role assigned to the User whose id is [`user_id`](`ID`)
99    ///
100    /// # Errors
101    /// * [`diesel::result::Error`](`diesel::result::Error`) if the query fails
102    pub fn fetch_all(db: &mut Connection, user_id: ID) -> Result<Vec<String>> {
103        let roles = sql_query("SELECT role FROM user_roles WHERE user_id = $1");
104
105        let roles = roles
106            .bind::<Integer, _>(user_id)
107            .get_results::<RoleQueryRow>(db)?;
108
109        let roles = roles.into_iter().map(|r| r.role).collect();
110
111        Ok(roles)
112    }
113}
114
115#[tsync::tsync]
116#[derive(Debug, Serialize, Deserialize, QueryableByName, Clone)]
117pub struct Permission {
118    #[diesel(sql_type=Text)]
119    /// the role this permission is coming from
120    pub from_role: String,
121
122    #[diesel(sql_type=Text)]
123    /// the permission itself
124    pub permission: String,
125}
126
127impl Hash for Permission {
128    fn hash<H: Hasher>(&self, state: &mut H) {
129        self.permission.as_str().hash(state);
130    }
131}
132
133impl PartialEq for Permission {
134    fn eq(&self, other: &Self) -> bool {
135        self.permission.eq(&other.permission)
136    }
137}
138impl Eq for Permission {}
139
140impl Permission {
141    // pub fn is_granted_to_user(db: &mut Connection, user_id: ID, permission: String) -> Result<bool> {
142    //   let permissions = Permission::for_user(&db, user_id)?;
143    //   let user_has_permission = permissions.iter().any(|perm| perm.permission == permission);
144
145    //   Ok(user_has_permission)
146    // }
147
148    /// grants `permission` to the User whose id is [`user_id`](`ID`)
149    ///
150    /// returns `Ok(())`, if successful
151    ///
152    /// # Errors
153    /// * if `UserPermission::create` fails, returns the error
154    pub fn grant_to_user(db: &mut Connection, user_id: ID, permission: &str) -> Result<()> {
155        let _granted = UserPermission::create(
156            db,
157            &UserPermissionChangeset {
158                permission: permission.to_string(),
159                user_id,
160            },
161        )?;
162
163        Ok(())
164    }
165
166    /// grant `permission` to `role`
167    ///
168    /// returns `Ok(())`, if successful
169    ///
170    /// # Errors
171    /// * if `RolePermission::create` fails, returns the error
172    pub fn grant_to_role(db: &mut Connection, role: &str, permission: &str) -> Result<()> {
173        let _granted = RolePermission::create(
174            db,
175            &RolePermissionChangeset {
176                permission: permission.to_string(),
177                role: role.to_string(),
178            },
179        )?;
180
181        Ok(())
182    }
183
184    /// grants every permission in `permissions` to `role`
185    ///
186    /// returns `Ok(())`, if successful
187    ///
188    /// # Errors
189    /// * if `RolePermission::create_many` fails, returns the error
190    pub fn grant_many_to_role(
191        db: &mut Connection,
192        role: String,
193        permissions: Vec<String>,
194    ) -> Result<()> {
195        let _granted = RolePermission::create_many(
196            db,
197            permissions
198                .into_iter()
199                .map(|permission| RolePermissionChangeset {
200                    permission,
201                    role: role.clone(),
202                })
203                .collect::<Vec<_>>(),
204        )?;
205
206        Ok(())
207    }
208
209    /// grants every permission in `permissions` to `role`
210    ///
211    /// returns `Ok(())`, if successful
212    ///
213    /// # Errors
214    /// * If `UserPermission::create_many` fails, returns the error
215    pub fn grant_many_to_user(
216        db: &mut Connection,
217        user_id: i32,
218        permissions: Vec<String>,
219    ) -> Result<()> {
220        let _granted = UserPermission::create_many(
221            db,
222            permissions
223                .into_iter()
224                .map(|permission| UserPermissionChangeset {
225                    user_id,
226                    permission,
227                })
228                .collect::<Vec<_>>(),
229        )?;
230
231        Ok(())
232    }
233
234    /// revokes `permission` from the User whose id is [`user_id`](`ID`)
235    ///
236    /// returns `Ok(())`, if successful
237    ///
238    /// # Errors
239    /// * If `UserPermission::delete` fails, returns the error
240    pub fn revoke_from_user(db: &mut Connection, user_id: ID, permission: &str) -> Result<()> {
241        let _deleted = UserPermission::delete(db, user_id, permission.to_string())?;
242
243        Ok(())
244    }
245
246    /// revokes `permission` from `role`
247    ///
248    /// returns `Ok(())`, if successful
249    ///
250    /// # Errors
251    /// * if `RolePermission::delete` fails, returns the error
252    ///
253    /// TODO: don't return a result if we never fail, or return a result and not a bool
254    pub fn revoke_from_role(db: &mut Connection, role: String, permission: String) -> Result<()> {
255        let _deleted = RolePermission::delete(db, role, permission)?;
256
257        Ok(())
258    }
259
260    /// revokes every permission in `permissions` from the User whose id is [`user_id`](`ID`)
261    ///
262    /// returns `Ok(())`, if successful
263    ///
264    /// # Errors
265    /// * if `UserPermission::delete_many` fails, returns the error
266    pub fn revoke_many_from_user(
267        db: &mut Connection,
268        user_id: ID,
269        permissions: Vec<String>,
270    ) -> Result<()> {
271        let _deleted = UserPermission::delete_many(db, user_id, permissions)?;
272
273        Ok(())
274    }
275
276    /// revokes every permission in `permissions` from `role`
277    ///
278    /// returns `Ok(())`, if successful
279    ///
280    /// # Errors
281    /// * if `RolePermission::delete_many` fails, returns the error
282    pub fn revoke_many_from_role(
283        db: &mut Connection,
284        role: String,
285        permissions: Vec<String>,
286    ) -> Result<()> {
287        let _deleted = RolePermission::delete_many(db, role, permissions)?;
288
289        Ok(())
290    }
291
292    /// revokes every permission granted to `role`
293    ///
294    /// returns `Ok(())`, if successful
295    ///
296    /// # Errors
297    /// * If `RolePermission::delete_all` fails, returns the error
298    pub fn revoke_all_from_role(db: &mut Connection, role: &str) -> Result<()> {
299        let _deleted = RolePermission::delete_all(db, role)?;
300
301        Ok(())
302    }
303
304    /// revokes every permission granted to the User whose id is [`user_id`](`ID`)
305    ///
306    /// returns `Ok(())`, if successful
307    ///
308    /// # Errors
309    /// * if `UserPermission::delete_all` fails, returns the error
310    pub fn revoke_all_from_user(db: &mut Connection, user_id: i32) -> Result<()> {
311        let _deleted = UserPermission::delete_all(db, user_id)?;
312
313        Ok(())
314    }
315
316    /// returns every permission granted to the User whose id is [`user_id`](`ID`)
317    ///
318    /// # Errors
319    /// * [`diesel::result::Error`](`diesel::result::Error`) if the query fails
320    pub fn fetch_all(db: &mut Connection, user_id: ID) -> Result<Vec<Self>> {
321        let permissions = sql_query(
322            r"
323      SELECT 
324        permission AS permission,
325        NULL AS from_role
326      FROM user_permissions
327      WHERE user_permissions.user_id = $1
328
329      UNION
330
331      SELECT
332        permission AS permission,
333        user_roles.role AS form_role
334      FROM user_roles
335      INNER JOIN role_permissions ON user_roles.role = role_permissions.role
336      WHERE user_roles.user_id = $1
337      ",
338        );
339
340        let permissions = permissions
341            .bind::<Integer, _>(user_id)
342            .get_results::<Self>(db)?;
343
344        Ok(permissions)
345    }
346}