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)]
45pub struct UserPrivilegeSet {
46    privileges: HashSet<UserPrivilege>,
47}
48
49impl UserPrivilegeSet {
50    pub fn has(&self, privilege: &UserPrivilege) -> bool {
51        if (privilege == &UserPrivilege::WriteProperties
52            || privilege == &UserPrivilege::WriteContent)
53            && self.privileges.contains(&UserPrivilege::Write)
54        {
55            return true;
56        }
57        self.privileges.contains(privilege) || self.privileges.contains(&UserPrivilege::All)
58    }
59
60    pub fn all() -> Self {
61        Self {
62            privileges: HashSet::from([UserPrivilege::All]),
63        }
64    }
65
66    pub fn owner_only(is_owner: bool) -> Self {
67        if is_owner {
68            Self::all()
69        } else {
70            Self::default()
71        }
72    }
73
74    pub fn owner_read(is_owner: bool) -> Self {
75        if is_owner {
76            Self::read_only()
77        } else {
78            Self::default()
79        }
80    }
81
82    pub fn owner_write_properties(is_owner: bool) -> Self {
83        // Content is read-only but we can write properties
84        if is_owner {
85            Self::write_properties()
86        } else {
87            Self::default()
88        }
89    }
90
91    pub fn read_only() -> Self {
92        Self {
93            privileges: HashSet::from([
94                UserPrivilege::Read,
95                UserPrivilege::ReadAcl,
96                UserPrivilege::ReadCurrentUserPrivilegeSet,
97            ]),
98        }
99    }
100
101    pub fn write_properties() -> Self {
102        Self {
103            privileges: HashSet::from([
104                UserPrivilege::Read,
105                UserPrivilege::WriteProperties,
106                UserPrivilege::ReadAcl,
107                UserPrivilege::ReadCurrentUserPrivilegeSet,
108            ]),
109        }
110    }
111}
112
113impl<const N: usize> From<[UserPrivilege; N]> for UserPrivilegeSet {
114    fn from(privileges: [UserPrivilege; N]) -> Self {
115        Self {
116            privileges: HashSet::from(privileges),
117        }
118    }
119}