1use crate::Authentication;
2use crate::constants::OK_CODES;
3use crate::dvrip::DVRIPCam;
4use crate::error::Result;
5use crate::protocol::sofia_hash;
6use async_trait::async_trait;
7use serde_json::{Value, json};
8
9#[async_trait]
10pub trait UserManagement: Send + Sync {
11 async fn get_authority_list(&mut self) -> Result<Vec<Value>>;
13
14 async fn get_groups(&mut self) -> Result<Vec<Value>>;
16
17 async fn add_group(
19 &mut self,
20 name: &str,
21 comment: &str,
22 auth: Option<Vec<Value>>,
23 ) -> Result<bool>;
24
25 async fn modify_group(
27 &mut self,
28 name: &str,
29 newname: Option<&str>,
30 comment: Option<&str>,
31 auth: Option<Vec<Value>>,
32 ) -> Result<bool>;
33
34 async fn delete_group(&mut self, name: &str) -> Result<bool>;
36
37 async fn get_users(&mut self) -> Result<Vec<Value>>;
39
40 async fn add_user(
42 &mut self,
43 name: &str,
44 password: &str,
45 comment: &str,
46 group: &str,
47 auth: Option<Vec<Value>>,
48 sharable: bool,
49 ) -> Result<bool>;
50
51 async fn modify_user(
53 &mut self,
54 name: &str,
55 newname: Option<&str>,
56 comment: Option<&str>,
57 group: Option<&str>,
58 auth: Option<Vec<Value>>,
59 sharable: Option<bool>,
60 ) -> Result<bool>;
61
62 async fn delete_user(&mut self, name: &str) -> Result<bool>;
64}
65
66#[async_trait]
67impl UserManagement for DVRIPCam {
68 async fn get_authority_list(&mut self) -> Result<Vec<Value>> {
69 let data = self.get_command("AuthorityList", None).await?;
70 if let Some(auth_list) = data.get("AuthorityList").and_then(|v| v.as_array()) {
71 return Ok(auth_list.clone());
72 }
73 Ok(vec![])
74 }
75
76 async fn get_groups(&mut self) -> Result<Vec<Value>> {
77 let data = self.get_command("Groups", None).await?;
78 if let Some(groups) = data.get("Groups").and_then(|v| v.as_array()) {
79 return Ok(groups.clone());
80 }
81 Ok(vec![])
82 }
83
84 async fn add_group(
85 &mut self,
86 name: &str,
87 comment: &str,
88 auth: Option<Vec<Value>>,
89 ) -> Result<bool> {
90 let auth_list = match auth {
91 Some(a) => a,
92 None => self.get_authority_list().await?,
93 };
94
95 let data = json!({
96 "Group": {
97 "AuthorityList": auth_list,
98 "Memo": comment,
99 "Name": name,
100 }
101 });
102
103 let reply = self.set_command("AddGroup", data, None).await?;
104 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
105 return Ok(OK_CODES.contains(&(ret as u32)));
106 }
107 Ok(false)
108 }
109
110 async fn modify_group(
111 &mut self,
112 name: &str,
113 newname: Option<&str>,
114 comment: Option<&str>,
115 auth: Option<Vec<Value>>,
116 ) -> Result<bool> {
117 let groups = self.get_groups().await?;
118 let group = groups
119 .iter()
120 .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(name))
121 .ok_or_else(|| {
122 crate::error::DVRIPError::Unknown(format!("Group '{}' not found", name))
123 })?;
124
125 let auth_list = auth.unwrap_or_else(|| {
126 group
127 .get("AuthorityList")
128 .and_then(|a| a.as_array())
129 .cloned()
130 .unwrap_or_default()
131 });
132
133 let data = json!({
134 "Group": {
135 "AuthorityList": auth_list,
136 "Memo": comment.or_else(|| group.get("Memo").and_then(|m| m.as_str())).unwrap_or_default(),
137 "Name": newname.unwrap_or(name),
138 },
139 "GroupName": name,
140 });
141
142 let reply = self.set_command("ModifyGroup", data, None).await?;
143 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
144 return Ok(OK_CODES.contains(&(ret as u32)));
145 }
146 Ok(false)
147 }
148
149 async fn delete_group(&mut self, name: &str) -> Result<bool> {
150 let session = self.session_id();
151 let data = json!({
152 "Name": name,
153 "SessionID": format!("0x{:08X}", session),
154 });
155
156 let reply = self.set_command("DelGroup", data, None).await?;
157 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
158 return Ok(OK_CODES.contains(&(ret as u32)));
159 }
160 Ok(false)
161 }
162
163 async fn get_users(&mut self) -> Result<Vec<Value>> {
164 let data = self.get_command("Users", None).await?;
165 if let Some(users) = data.get("Users").and_then(|v| v.as_array()) {
166 return Ok(users.clone());
167 }
168 Ok(vec![])
169 }
170
171 async fn add_user(
172 &mut self,
173 name: &str,
174 password: &str,
175 comment: &str,
176 group: &str,
177 auth: Option<Vec<Value>>,
178 sharable: bool,
179 ) -> Result<bool> {
180 let groups = self.get_groups().await?;
181 let group_data = groups
182 .iter()
183 .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(group))
184 .ok_or_else(|| {
185 crate::error::DVRIPError::Unknown(format!("Group '{}' not found", group))
186 })?;
187
188 let auth_list = auth.unwrap_or_else(|| {
189 group_data
190 .get("AuthorityList")
191 .and_then(|a| a.as_array())
192 .cloned()
193 .unwrap_or_default()
194 });
195
196 let data = json!({
197 "User": {
198 "AuthorityList": auth_list,
199 "Group": group,
200 "Memo": comment,
201 "Name": name,
202 "Password": sofia_hash(password),
203 "Reserved": false,
204 "Sharable": sharable,
205 }
206 });
207
208 let reply = self.set_command("User", data, None).await?;
209 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
210 return Ok(OK_CODES.contains(&(ret as u32)));
211 }
212 Ok(false)
213 }
214
215 async fn modify_user(
216 &mut self,
217 name: &str,
218 newname: Option<&str>,
219 comment: Option<&str>,
220 group: Option<&str>,
221 auth: Option<Vec<Value>>,
222 sharable: Option<bool>,
223 ) -> Result<bool> {
224 let users = self.get_users().await?;
225 let user = users
226 .iter()
227 .find(|u| u.get("Name").and_then(|n| n.as_str()) == Some(name))
228 .ok_or_else(|| {
229 crate::error::DVRIPError::Unknown(format!("User '{}' not found", name))
230 })?;
231
232 let mut auth_list = user
233 .get("AuthorityList")
234 .and_then(|a| a.as_array())
235 .cloned()
236 .unwrap_or_default();
237
238 if let Some(group_name) = group {
239 let groups = self.get_groups().await?;
240 if let Some(group_data) = groups
241 .iter()
242 .find(|g| g.get("Name").and_then(|n| n.as_str()) == Some(group_name))
243 {
244 auth_list = group_data
245 .get("AuthorityList")
246 .and_then(|a| a.as_array())
247 .cloned()
248 .unwrap_or_default();
249 }
250 }
251
252 let data = json!({
253 "User": {
254 "AuthorityList": auth.unwrap_or(auth_list),
255 "Group": group.or_else(|| user.get("Group").and_then(|g| g.as_str())).unwrap_or(""),
256 "Memo": comment.or_else(|| user.get("Memo").and_then(|m| m.as_str())).unwrap_or_default(),
257 "Name": newname.unwrap_or(name),
258 "Password": "",
259 "Reserved": user.get("Reserved").and_then(|r| r.as_bool()).unwrap_or(false),
260 "Sharable": sharable.or_else(|| user.get("Sharable").and_then(|s| s.as_bool())).unwrap_or(false),
261 },
262 "UserName": name,
263 });
264
265 let reply = self.set_command("ModifyUser", data, None).await?;
266 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
267 return Ok(OK_CODES.contains(&(ret as u32)));
268 }
269 Ok(false)
270 }
271
272 async fn delete_user(&mut self, name: &str) -> Result<bool> {
273 let session = self.session_id();
274 let data = json!({
275 "Name": name,
276 "SessionID": format!("0x{:08X}", session),
277 });
278
279 let reply = self.set_command("DelUser", data, None).await?;
280 if let Some(ret) = reply.get("Ret").and_then(|r| r.as_u64()) {
281 return Ok(OK_CODES.contains(&(ret as u32)));
282 }
283 Ok(false)
284 }
285}