userman_auth/
role.rs

1use std::path::Path;
2
3use mongodb::bson::oid::ObjectId;
4use mongodb::bson::DateTime;
5use serde::{Deserialize, Serialize};
6
7use crate::{AuthError, Result};
8
9use crate::{serialize_oid_as_string, serialize_option_oid_as_string};
10
11pub const LOCAL_ROLE: &str = "local-default";
12
13fn crud_item<T: Into<String>>(name: T) -> Item {
14    Item {
15        name: name.into(),
16        values: RoleValues(vec![
17            Value {
18                name: "create".to_string(),
19                data: DataValue::Boolean(true),
20                options: None,
21            },
22            Value {
23                name: "read".to_string(),
24                data: DataValue::Boolean(true),
25                options: None,
26            },
27            Value {
28                name: "update".to_string(),
29                data: DataValue::Boolean(true),
30                options: None,
31            },
32            Value {
33                name: "delete".to_string(),
34                data: DataValue::Boolean(true),
35                options: None,
36            },
37        ]),
38        items: RoleItems::default(),
39    }
40}
41
42#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
43#[serde(rename_all = "camelCase")]
44pub enum DataValue {
45    String(String),
46    Float(f64),
47    Integer(i64),
48    Boolean(bool),
49}
50
51#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
52#[serde(rename_all = "camelCase")]
53pub struct DataOptions {
54    pub min_value: DataValue,
55    pub max_value: DataValue,
56}
57
58#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
59#[serde(rename_all = "camelCase")]
60pub struct Value {
61    pub name: String,
62    #[serde(flatten)]
63    pub data: DataValue,
64    #[serde(skip_serializing_if = "Option::is_none", default)]
65    pub options: Option<DataOptions>,
66}
67
68#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
69#[serde(rename_all = "camelCase")]
70pub struct RoleValues(pub Vec<Value>);
71
72impl RoleValues {
73    pub fn is_empty(&self) -> bool {
74        self.0.is_empty()
75    }
76
77    pub fn inner(&self) -> &Vec<Value> {
78        self.0.as_ref()
79    }
80
81    pub fn inner_mut(&mut self) -> &mut Vec<Value> {
82        self.0.as_mut()
83    }
84
85    pub fn find(&self, name: &str) -> Option<&Value> {
86        self.0.iter().find(|el| el.name == name)
87    }
88
89    pub fn find_mut(&mut self, name: &str) -> Option<&mut Value> {
90        self.0.iter_mut().find(|el| el.name == name)
91    }
92}
93
94#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
95#[serde(rename_all = "camelCase")]
96pub struct Item {
97    pub name: String,
98    #[serde(skip_serializing_if = "RoleValues::is_empty", default)]
99    pub values: RoleValues,
100    #[serde(skip_serializing_if = "RoleItems::is_empty", default)]
101    pub items: RoleItems,
102}
103
104#[derive(Clone, Debug, Deserialize, Serialize, PartialEq, Default)]
105#[serde(rename_all = "camelCase")]
106pub struct RoleItems(Vec<Item>);
107
108impl RoleItems {
109    pub fn local() -> Self {
110        Self(vec![
111            crud_item("users"),
112            crud_item("roles"),
113            crud_item("apps"),
114        ])
115    }
116
117    pub fn new(src: Vec<Item>) -> Self {
118        Self(src)
119    }
120
121    pub fn is_empty(&self) -> bool {
122        self.0.is_empty()
123    }
124
125    pub fn inner_mut(&mut self) -> &mut Vec<Item> {
126        self.0.as_mut()
127    }
128
129    pub fn find(&self, name: &str) -> Option<&Item> {
130        self.0.iter().find(|&el| el.name == name)
131    }
132
133    pub fn find_value<P: ?Sized + AsRef<Path>>(&self, src: &P) -> Result<DataValue> {
134        let mut cursor = self;
135
136        let path = src.as_ref();
137
138        let items = match path.parent() {
139            Some(t) => t,
140            None => return Err(AuthError::MissingParentPath),
141        };
142
143        for part in items.iter().take(items.iter().count() - 2) {
144            let name = part.to_str().ok_or(AuthError::InvalidUnicodeString)?;
145
146            if name != "/" {
147                cursor = match cursor.find(name) {
148                    Some(t) => &t.items,
149                    None => return Err(AuthError::InvalidAuthPath(name.to_string())),
150                }
151            }
152        }
153
154        let last_part = match items.iter().last() {
155            Some(t) => t.to_owned(),
156            None => return Err(AuthError::MissingLastItem),
157        };
158
159        let last_name = last_part.to_str().ok_or(AuthError::InvalidUnicodeString)?;
160
161        let last_item = match cursor.find(last_name) {
162            Some(t) => t,
163            None => return Err(AuthError::InvalidAuthPath(last_name.to_string())),
164        };
165
166        let value_name_part = match path.file_stem() {
167            Some(t) => t,
168            None => return Err(AuthError::MissingValueName),
169        };
170
171        let value_name = value_name_part
172            .to_str()
173            .ok_or(AuthError::InvalidUnicodeString)?;
174
175        let value_ext_part = match path.extension() {
176            Some(t) => t,
177            None => return Err(AuthError::MissingValueExtension),
178        };
179
180        let value_ext = value_ext_part
181            .to_str()
182            .ok_or(AuthError::InvalidUnicodeString)?;
183
184        let value = last_item
185            .values
186            .find(value_name)
187            .ok_or(AuthError::MissingValue)?;
188
189        match (value_ext, &value.data) {
190            ("boolean", DataValue::Boolean(_)) => {}
191            ("float", DataValue::Float(_)) => {}
192            ("integer", DataValue::Integer(_)) => {}
193            ("string", DataValue::String(_)) => {}
194            _ => return Err(AuthError::InvalidDataValueType),
195        }
196
197        Ok(value.data.clone())
198    }
199
200    fn merge_items(&self, new: &mut Vec<Item>) {
201        for n_item in new {
202            if let Some(a_item) = self.find(&n_item.name) {
203                // values
204                for n_value in n_item.values.inner_mut() {
205                    if let Some(a_value) = a_item.values.find(&n_value.name) {
206                        *n_value = a_value.clone();
207                    }
208                }
209
210                // sub-items
211                let n_sub_items = n_item.items.inner_mut();
212                a_item.items.merge_items(n_sub_items);
213            }
214        }
215    }
216
217    /// Merge the new &mut RoleItems collection with self RoleItems.
218    /// Look for new &mut RoleItems values in self collection. If the
219    /// value exists, update it with self collection value.
220    pub fn merge(&self, new: &mut RoleItems) {
221        self.merge_items(new.inner_mut());
222    }
223
224    fn add_items(&self, new: &mut Vec<Item>) {
225        for item in &self.0 {
226            match new.iter_mut().find(|t| t.name == item.name) {
227                Some(t) => {
228                    for value in item.values.inner() {
229                        match t.values.find_mut(&value.name) {
230                            Some(t) => match value.data {
231                                DataValue::Boolean(t) if !t => {}
232                                _ => {
233                                    t.data = value.data.clone();
234                                }
235                            },
236                            None => {
237                                t.values.inner_mut().push(value.clone());
238                            }
239                        }
240                    }
241
242                    item.items.add_items(t.items.inner_mut());
243                }
244                None => {
245                    new.push(item.clone());
246                }
247            }
248        }
249
250        for n_item in new {
251            if let Some(a_item) = self.find(&n_item.name) {
252                // values
253                for n_value in n_item.values.inner_mut() {
254                    if let Some(a_value) = a_item.values.find(&n_value.name) {
255                        *n_value = a_value.clone();
256                    }
257                }
258
259                // sub-items
260                let n_sub_items = n_item.items.inner_mut();
261                a_item.items.merge_items(n_sub_items);
262            }
263        }
264    }
265
266    /// Add the new &mut RoleItems collection with self RoleItems.
267    /// Look for new &mut RoleItems values in self collection.
268    /// If the value is Boolean(true), set to true.
269    /// If the value is Boolean(false), don't change.
270    /// If the value is not a Boolean, replace with the last one.
271    /// If the value is missing add the value.
272    pub fn add(&self, new: &mut RoleItems) {
273        self.add_items(new.inner_mut());
274    }
275}
276
277#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
278#[serde(rename_all = "camelCase")]
279pub struct Role {
280    #[serde(
281        rename(serialize = "id", deserialize = "_id"),
282        skip_serializing_if = "Option::is_none",
283        serialize_with = "serialize_option_oid_as_string"
284    )]
285    pub id: Option<ObjectId>,
286    #[serde(serialize_with = "serialize_oid_as_string")]
287    pub app: ObjectId,
288    pub name: String,
289    pub items: RoleItems,
290    #[serde(skip_serializing_if = "Option::is_none")]
291    pub created_at: Option<DateTime>,
292    #[serde(skip_serializing_if = "Option::is_none")]
293    pub updated_at: Option<DateTime>,
294}
295
296impl Default for Role {
297    fn default() -> Self {
298        Self {
299            id: None,
300            app: ObjectId::default(),
301            name: LOCAL_ROLE.to_string(),
302            items: RoleItems::default(),
303            created_at: None,
304            updated_at: None,
305        }
306    }
307}
308
309impl Role {
310    pub fn id(&self) -> ObjectId {
311        self.id.unwrap_or_default()
312    }
313
314    pub fn to_string_pretty(&self) -> std::result::Result<String, serde_json::Error> {
315        serde_json::to_string_pretty(&self)
316    }
317}