1use lazy_static::lazy_static;
2use ldap3::SearchEntry;
3use regex::Regex;
4use serde::{Deserialize, Serialize};
5use std::collections::HashMap;
6use std::fmt::Debug;
7use std::str::FromStr;
8
9#[derive(Debug, Serialize, Deserialize, Clone)]
10#[allow(non_snake_case)]
11pub struct LdapUser {
12 pub dn: String,
13 pub cn: String,
14 pub uid: String,
15 pub groups: Vec<String>,
16 pub krbPrincipalName: String,
17 pub mail: Vec<String>,
18 pub mobile: Vec<String>,
19 pub drinkBalance: Option<i64>,
20 pub ibutton: Vec<String>,
21}
22
23impl LdapUser {
24 #[must_use]
25 pub fn from_entry(entry: &SearchEntry) -> Self {
26 let user_attrs = &entry.attrs;
27 LdapUser {
28 dn: entry.dn.clone(),
29 cn: get_one(user_attrs, "cn").unwrap(),
30 uid: get_one(user_attrs, "uid").unwrap(),
31 groups: get_groups(get_vec(user_attrs, "memberOf")),
32 krbPrincipalName: get_one(user_attrs, "krbPrincipalName").unwrap(),
33 mail: get_vec(user_attrs, "mail"),
34 mobile: get_vec(user_attrs, "mobile"),
35 ibutton: get_vec(user_attrs, "ibutton"),
36 drinkBalance: get_one(user_attrs, "drinkBalance"),
37 }
38 }
39}
40
41fn get_one<T>(entry: &HashMap<String, Vec<String>>, field: &str) -> Option<T>
42where
43 T: FromStr,
44 <T as FromStr>::Err: Debug,
45{
46 match entry.get(field).map(|f| f.get(0).unwrap().parse::<T>()) {
47 Some(result) => match result {
48 Ok(r) => Some(r),
49 Err(_) => None,
50 },
51 None => None,
52 }
53}
54
55fn get_vec<T>(entry: &HashMap<String, Vec<String>>, field: &str) -> Vec<T>
56where
57 T: FromStr,
58 <T as FromStr>::Err: Debug,
59{
60 match entry.get(field) {
61 Some(v) => v.iter().map(|f| f.parse::<T>().unwrap()).collect(),
62 None => vec![],
63 }
64}
65
66#[must_use]
67pub fn get_groups(member_of: Vec<String>) -> Vec<String> {
68 lazy_static! {
69 static ref GROUP_REGEX: Regex =
70 Regex::new(r"cn=(?P<name>\w+),cn=groups,cn=accounts,dc=csh,dc=rit,dc=edu").unwrap();
71 }
72 member_of
73 .iter()
74 .filter_map(|group| {
75 GROUP_REGEX
76 .captures(group)
77 .map(|cap| cap["name"].to_owned())
78 })
79 .collect()
80}
81
82#[derive(Debug, Serialize, Deserialize)]
83#[allow(non_snake_case)]
84pub struct LdapUserChangeSet {
85 pub dn: String,
86 pub drinkBalance: Option<i64>,
87 pub ibutton: Option<Vec<String>>,
88}