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 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 let n_sub_items = n_item.items.inner_mut();
212 a_item.items.merge_items(n_sub_items);
213 }
214 }
215 }
216
217 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 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 let n_sub_items = n_item.items.inner_mut();
261 a_item.items.merge_items(n_sub_items);
262 }
263 }
264 }
265
266 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}