rustical_dav/
privileges.rs

1use itertools::Itertools;
2use quick_xml::name::Namespace;
3use rustical_xml::{XmlDeserialize, XmlSerialize};
4use std::collections::{HashMap, HashSet};
5
6// https://datatracker.ietf.org/doc/html/rfc3744
7#[derive(Debug, Clone, XmlSerialize, XmlDeserialize, Eq, Hash, PartialEq, PartialOrd, Ord)]
8pub enum UserPrivilege {
9    Read,
10    Write,
11    WriteProperties,
12    WriteContent,
13    ReadAcl,
14    ReadCurrentUserPrivilegeSet,
15    WriteAcl,
16    All,
17}
18
19impl XmlSerialize for UserPrivilegeSet {
20    fn serialize(
21        &self,
22        ns: Option<Namespace>,
23        tag: Option<&str>,
24        namespaces: &HashMap<Namespace, &str>,
25        writer: &mut quick_xml::Writer<&mut Vec<u8>>,
26    ) -> std::io::Result<()> {
27        #[derive(XmlSerialize)]
28        pub struct FakeUserPrivilegeSet {
29            #[xml(rename = "privilege", flatten)]
30            privileges: Vec<UserPrivilege>,
31        }
32
33        FakeUserPrivilegeSet {
34            privileges: self.privileges.iter().cloned().sorted().collect(),
35        }
36        .serialize(ns, tag, namespaces, writer)
37    }
38
39    fn attributes<'a>(&self) -> Option<Vec<quick_xml::events::attributes::Attribute<'a>>> {
40        None
41    }
42}
43
44#[derive(Debug, Clone, Default, PartialEq, Eq)]
45pub struct UserPrivilegeSet {
46    privileges: HashSet<UserPrivilege>,
47}
48
49impl UserPrivilegeSet {
50    #[must_use]
51    pub fn has(&self, privilege: &UserPrivilege) -> bool {
52        if (privilege == &UserPrivilege::WriteProperties
53            || privilege == &UserPrivilege::WriteContent)
54            && self.privileges.contains(&UserPrivilege::Write)
55        {
56            return true;
57        }
58        self.privileges.contains(privilege) || self.privileges.contains(&UserPrivilege::All)
59    }
60
61    #[must_use]
62    pub fn all() -> Self {
63        Self {
64            privileges: HashSet::from([UserPrivilege::All]),
65        }
66    }
67
68    #[must_use]
69    pub fn owner_only(is_owner: bool) -> Self {
70        if is_owner {
71            Self::all()
72        } else {
73            Self::default()
74        }
75    }
76
77    #[must_use]
78    pub fn owner_read(is_owner: bool) -> Self {
79        if is_owner {
80            Self::read_only()
81        } else {
82            Self::default()
83        }
84    }
85
86    #[must_use]
87    pub fn owner_write_properties(is_owner: bool) -> Self {
88        // Content is read-only but we can write properties
89        if is_owner {
90            Self::write_properties()
91        } else {
92            Self::default()
93        }
94    }
95
96    #[must_use]
97    pub fn read_only() -> Self {
98        Self {
99            privileges: HashSet::from([
100                UserPrivilege::Read,
101                UserPrivilege::ReadAcl,
102                UserPrivilege::ReadCurrentUserPrivilegeSet,
103            ]),
104        }
105    }
106
107    #[must_use]
108    pub fn write_properties() -> Self {
109        Self {
110            privileges: HashSet::from([
111                UserPrivilege::Read,
112                UserPrivilege::WriteProperties,
113                UserPrivilege::ReadAcl,
114                UserPrivilege::ReadCurrentUserPrivilegeSet,
115            ]),
116        }
117    }
118}
119
120impl<const N: usize> From<[UserPrivilege; N]> for UserPrivilegeSet {
121    fn from(privileges: [UserPrivilege; N]) -> Self {
122        Self {
123            privileges: HashSet::from(privileges),
124        }
125    }
126}