kanidmd_lib/valueset/
url.rs1use crate::prelude::*;
2use crate::schema::SchemaAttribute;
3use crate::valueset::{
4 DbValueSetV2, ScimResolveStatus, ValueSet, ValueSetResolveStatus, ValueSetScimPut,
5};
6use kanidm_proto::scim_v1::client::ScimUrls;
7use kanidm_proto::scim_v1::JsonValue;
8use smolset::SmolSet;
9
10#[derive(Debug, Clone)]
11pub struct ValueSetUrl {
12 set: SmolSet<[Url; 1]>,
13}
14
15impl ValueSetUrl {
16 pub fn new(b: Url) -> Box<Self> {
17 let mut set = SmolSet::new();
18 set.insert(b);
19 Box::new(ValueSetUrl { set })
20 }
21
22 pub fn push(&mut self, b: Url) -> bool {
23 self.set.insert(b)
24 }
25
26 pub fn from_dbvs2(data: Vec<Url>) -> Result<ValueSet, OperationError> {
27 let set = data.into_iter().collect();
28 Ok(Box::new(ValueSetUrl { set }))
29 }
30
31 #[allow(clippy::should_implement_trait)]
34 pub fn from_iter<T>(iter: T) -> Option<Box<Self>>
35 where
36 T: IntoIterator<Item = Url>,
37 {
38 let set = iter.into_iter().collect();
39 Some(Box::new(ValueSetUrl { set }))
40 }
41}
42
43impl ValueSetScimPut for ValueSetUrl {
44 fn from_scim_json_put(value: JsonValue) -> Result<ValueSetResolveStatus, OperationError> {
45 let ScimUrls(url_set) = serde_json::from_value(value).map_err(|err| {
46 error!(?err, "SCIM URL syntax invalid");
47 OperationError::SC0007UrlSyntaxInvalid
48 })?;
49
50 let set = SmolSet::from_iter(url_set);
51
52 Ok(ValueSetResolveStatus::Resolved(Box::new(ValueSetUrl {
53 set,
54 })))
55 }
56}
57
58impl ValueSetT for ValueSetUrl {
59 fn insert_checked(&mut self, value: Value) -> Result<bool, OperationError> {
60 match value {
61 Value::Url(u) => Ok(self.set.insert(u)),
62 _ => {
63 debug_assert!(false);
64 Err(OperationError::InvalidValueState)
65 }
66 }
67 }
68
69 fn clear(&mut self) {
70 self.set.clear();
71 }
72
73 fn remove(&mut self, pv: &PartialValue, _cid: &Cid) -> bool {
74 match pv {
75 PartialValue::Url(u) => self.set.remove(u),
76 _ => false,
77 }
78 }
79
80 fn contains(&self, pv: &PartialValue) -> bool {
81 match pv {
82 PartialValue::Url(u) => self.set.contains(u),
83 _ => false,
84 }
85 }
86
87 fn substring(&self, _pv: &PartialValue) -> bool {
88 false
89 }
90
91 fn startswith(&self, _pv: &PartialValue) -> bool {
92 false
93 }
94
95 fn endswith(&self, _pv: &PartialValue) -> bool {
96 false
97 }
98
99 fn lessthan(&self, _pv: &PartialValue) -> bool {
100 false
101 }
102
103 fn len(&self) -> usize {
104 self.set.len()
105 }
106
107 fn generate_idx_eq_keys(&self) -> Vec<String> {
108 self.set.iter().map(|u| u.to_string()).collect()
109 }
110
111 fn syntax(&self) -> SyntaxType {
112 SyntaxType::Url
113 }
114
115 fn validate(&self, _schema_attr: &SchemaAttribute) -> bool {
116 true
117 }
118
119 fn to_proto_string_clone_iter(&self) -> Box<dyn Iterator<Item = String> + '_> {
120 Box::new(self.set.iter().map(|i| i.to_string()))
121 }
122
123 fn to_scim_value(&self) -> Option<ScimResolveStatus> {
124 let mut iter = self.set.iter().map(|url| url.to_string());
125 if self.len() == 1 {
126 let v = iter.next().unwrap_or_default();
127 Some(v.into())
128 } else {
129 let mut arr = iter.collect::<Vec<_>>();
130 arr.sort();
131 Some(arr.into())
132 }
133 }
134
135 fn to_db_valueset_v2(&self) -> DbValueSetV2 {
136 DbValueSetV2::Url(self.set.iter().cloned().collect())
137 }
138
139 fn to_partialvalue_iter(&self) -> Box<dyn Iterator<Item = PartialValue> + '_> {
140 Box::new(self.set.iter().cloned().map(PartialValue::Url))
141 }
142
143 fn to_value_iter(&self) -> Box<dyn Iterator<Item = Value> + '_> {
144 Box::new(self.set.iter().cloned().map(Value::Url))
145 }
146
147 fn equal(&self, other: &ValueSet) -> bool {
148 if let Some(other) = other.as_url_set() {
149 &self.set == other
150 } else {
151 debug_assert!(false);
152 false
153 }
154 }
155
156 fn merge(&mut self, other: &ValueSet) -> Result<(), OperationError> {
157 if let Some(b) = other.as_url_set() {
158 mergesets!(self.set, b)
159 } else {
160 debug_assert!(false);
161 Err(OperationError::InvalidValueState)
162 }
163 }
164
165 fn to_url_single(&self) -> Option<&Url> {
166 if self.set.len() == 1 {
167 self.set.iter().take(1).next()
168 } else {
169 None
170 }
171 }
172
173 fn as_url_set(&self) -> Option<&SmolSet<[Url; 1]>> {
174 Some(&self.set)
175 }
176}
177
178#[cfg(test)]
179mod tests {
180 use super::ValueSetUrl;
181 use crate::prelude::{Url, ValueSet};
182
183 #[test]
184 fn test_scim_url() {
185 let u = Url::parse("https://idm.example.com").unwrap();
186 let vs: ValueSet = ValueSetUrl::new(u);
187 crate::valueset::scim_json_reflexive(&vs, r#""https://idm.example.com/""#);
188
189 crate::valueset::scim_json_put_reflexive::<ValueSetUrl>(&vs, &[]);
191
192 let u1 = Url::parse("https://idm1.example.com").unwrap();
194 let u2 = Url::parse("https://idm2.example.com").unwrap();
195 let vs: ValueSet = ValueSetUrl::from_iter([u1, u2]).expect("Unable to create ValueSet");
196 crate::valueset::scim_json_reflexive(
197 &vs,
198 r#"["https://idm1.example.com/", "https://idm2.example.com/"]"#,
199 );
200 crate::valueset::scim_json_put_reflexive::<ValueSetUrl>(&vs, &[]);
201 }
202}