xapi_rs/lrs/
role.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3//! Data structures and functions to represent and use authorization Roles
4//! for managing Users as well as access and use of **`LaRS`**.
5
6use serde::{Deserialize, Serialize};
7
8/// Authorization role variants.
9#[derive(Clone, Copy, Debug, Deserialize, PartialEq, Eq, Serialize)]
10pub enum Role {
11    /// Can watch.
12    Guest = 0,
13    /// Can use xAPI resources only.
14    User = 1,
15    /// Can use xAPI and authorize _Statements_.
16    AuthUser = 2,
17    /// Can manage users and verbs but not use xAPI resources.
18    Admin = 3,
19    /// Can do almost everything.
20    Root = 4,
21}
22
23// Roles are persisted as integer (`SMALLINT`) in _PostgreSQL_. These are used
24// for converting such values to/from Rust enum variants.
25impl From<i16> for Role {
26    fn from(value: i16) -> Self {
27        match value {
28            1 => Role::User,
29            2 => Role::AuthUser,
30            3 => Role::Admin,
31            4 => Role::Root,
32            _ => Role::Guest,
33        }
34    }
35}
36impl From<Role> for i16 {
37    fn from(value: Role) -> Self {
38        match value {
39            Role::User => 1,
40            Role::AuthUser => 2,
41            Role::Admin => 3,
42            Role::Root => 4,
43            _ => 0,
44        }
45    }
46}
47
48// Roles are also represented as unsigned integers when used in front-ends.
49// These are used to serialize/deserialize them.
50impl From<u16> for Role {
51    fn from(value: u16) -> Self {
52        match value {
53            1 => Role::User,
54            2 => Role::AuthUser,
55            3 => Role::Admin,
56            4 => Role::Root,
57            _ => Role::Guest,
58        }
59    }
60}
61
62impl From<Role> for u16 {
63    fn from(value: Role) -> Self {
64        match value {
65            Role::User => 1,
66            Role::AuthUser => 2,
67            Role::Admin => 3,
68            Role::Root => 4,
69            _ => 0,
70        }
71    }
72}
73
74#[cfg(test)]
75mod tests {
76    use super::*;
77    use serde_with::{serde_as, FromInto};
78
79    #[test]
80    fn test_serde() {
81        const OUT: &str = r#"{"bar":42,"baz":"whatever","role":2}"#;
82
83        #[serde_as]
84        #[derive(Debug, Clone, Copy, Deserialize, Serialize, PartialEq)]
85        struct Foo<'a> {
86            bar: i32,
87            baz: &'a str,
88            #[serde_as(as = "FromInto<u16>")]
89            role: Role,
90        }
91
92        let x = Foo {
93            bar: 42,
94            baz: "whatever",
95            role: Role::AuthUser,
96        };
97        let out = serde_json::to_string(&x).expect("Failed serializing Foo");
98        // println!("out = '{}'", out);
99        assert_eq!(out, OUT);
100
101        let foo: Foo = serde_json::from_str(&out).expect("Failed deserializing Foo");
102        // println!("foo = {:?}", foo);
103        assert_eq!(foo, x);
104    }
105}