decode.rs (10434B)
1 #[cfg(not(feature = "std"))] 2 use alloc::{ 3 string::{String, ToString}, 4 vec::Vec, 5 }; 6 7 use radroots_event::{ 8 social::group::{ 9 GroupAdmins, GroupCreateGroup, GroupCreateInvite, GroupDeleteEvent, GroupDeleteGroup, 10 GroupEditMetadata, GroupEditableMetadata, GroupJoinRequest, GroupLeaveRequest, 11 GroupMembers, GroupMetadata, GroupPutUser, GroupRemoveUser, GroupRole, GroupRoles, 12 GroupUserRef, KIND_GROUP_ADMINS, KIND_GROUP_CREATE_GROUP, KIND_GROUP_CREATE_INVITE, 13 KIND_GROUP_DELETE_EVENT, KIND_GROUP_DELETE_GROUP, KIND_GROUP_EDIT_METADATA, 14 KIND_GROUP_JOIN_REQUEST, KIND_GROUP_LEAVE_REQUEST, KIND_GROUP_MEMBERS, KIND_GROUP_METADATA, 15 KIND_GROUP_PUT_USER, KIND_GROUP_REMOVE_USER, KIND_GROUP_ROLES, 16 }, 17 tag::name::{TAG_D, TAG_E, TAG_H, TAG_P}, 18 }; 19 20 use crate::error::EventParseError; 21 use crate::field_helpers::{ 22 optional_tag_value, require_empty_content, required_tag_value, validate_non_empty_tag_value, 23 }; 24 25 const TAG_ABOUT: &str = "about"; 26 const TAG_CLOSED: &str = "closed"; 27 const TAG_CODE: &str = "code"; 28 const TAG_HIDDEN: &str = "hidden"; 29 const TAG_NAME: &str = "name"; 30 const TAG_PICTURE: &str = "picture"; 31 const TAG_PRIVATE: &str = "private"; 32 const TAG_RESTRICTED: &str = "restricted"; 33 const TAG_ROLE: &str = "role"; 34 const TAG_SUPPORTED_KINDS: &str = "supported_kinds"; 35 36 pub fn group_put_user_from_event( 37 kind: u32, 38 tags: &[Vec<String>], 39 content: &str, 40 ) -> Result<GroupPutUser, EventParseError> { 41 require_kind(kind, KIND_GROUP_PUT_USER, "9000")?; 42 let (pubkey, roles) = required_user_tag(tags)?; 43 Ok(GroupPutUser { 44 group_id: required_tag_value(tags, TAG_H)?, 45 message: optional_content(content), 46 pubkey, 47 roles, 48 }) 49 } 50 51 pub fn group_remove_user_from_event( 52 kind: u32, 53 tags: &[Vec<String>], 54 content: &str, 55 ) -> Result<GroupRemoveUser, EventParseError> { 56 require_kind(kind, KIND_GROUP_REMOVE_USER, "9001")?; 57 let (pubkey, _) = required_user_tag(tags)?; 58 Ok(GroupRemoveUser { 59 group_id: required_tag_value(tags, TAG_H)?, 60 message: optional_content(content), 61 pubkey, 62 }) 63 } 64 65 pub fn group_create_group_from_event( 66 kind: u32, 67 tags: &[Vec<String>], 68 content: &str, 69 ) -> Result<GroupCreateGroup, EventParseError> { 70 require_kind(kind, KIND_GROUP_CREATE_GROUP, "9007")?; 71 Ok(GroupCreateGroup { 72 group_id: required_tag_value(tags, TAG_H)?, 73 message: optional_content(content), 74 metadata: metadata_from_tags(tags)?, 75 }) 76 } 77 78 pub fn group_edit_metadata_from_event( 79 kind: u32, 80 tags: &[Vec<String>], 81 content: &str, 82 ) -> Result<GroupEditMetadata, EventParseError> { 83 require_kind(kind, KIND_GROUP_EDIT_METADATA, "9002")?; 84 Ok(GroupEditMetadata { 85 group_id: required_tag_value(tags, TAG_H)?, 86 message: optional_content(content), 87 metadata: metadata_from_tags(tags)?, 88 }) 89 } 90 91 pub fn group_delete_group_from_event( 92 kind: u32, 93 tags: &[Vec<String>], 94 content: &str, 95 ) -> Result<GroupDeleteGroup, EventParseError> { 96 require_kind(kind, KIND_GROUP_DELETE_GROUP, "9008")?; 97 Ok(GroupDeleteGroup { 98 group_id: required_tag_value(tags, TAG_H)?, 99 message: optional_content(content), 100 }) 101 } 102 103 pub fn group_delete_event_from_event( 104 kind: u32, 105 tags: &[Vec<String>], 106 content: &str, 107 ) -> Result<GroupDeleteEvent, EventParseError> { 108 require_kind(kind, KIND_GROUP_DELETE_EVENT, "9005")?; 109 Ok(GroupDeleteEvent { 110 group_id: required_tag_value(tags, TAG_H)?, 111 message: optional_content(content), 112 event_id: required_tag_value(tags, TAG_E)?, 113 }) 114 } 115 116 pub fn group_create_invite_from_event( 117 kind: u32, 118 tags: &[Vec<String>], 119 content: &str, 120 ) -> Result<GroupCreateInvite, EventParseError> { 121 require_kind(kind, KIND_GROUP_CREATE_INVITE, "9009")?; 122 Ok(GroupCreateInvite { 123 group_id: required_tag_value(tags, TAG_H)?, 124 message: optional_content(content), 125 code: required_tag_value(tags, TAG_CODE)?, 126 }) 127 } 128 129 pub fn group_join_request_from_event( 130 kind: u32, 131 tags: &[Vec<String>], 132 content: &str, 133 ) -> Result<GroupJoinRequest, EventParseError> { 134 require_kind(kind, KIND_GROUP_JOIN_REQUEST, "9021")?; 135 Ok(GroupJoinRequest { 136 group_id: required_tag_value(tags, TAG_H)?, 137 message: optional_content(content), 138 code: optional_tag_value(tags, TAG_CODE)?, 139 }) 140 } 141 142 pub fn group_leave_request_from_event( 143 kind: u32, 144 tags: &[Vec<String>], 145 content: &str, 146 ) -> Result<GroupLeaveRequest, EventParseError> { 147 require_kind(kind, KIND_GROUP_LEAVE_REQUEST, "9022")?; 148 Ok(GroupLeaveRequest { 149 group_id: required_tag_value(tags, TAG_H)?, 150 message: optional_content(content), 151 }) 152 } 153 154 pub fn group_metadata_from_event( 155 kind: u32, 156 tags: &[Vec<String>], 157 content: &str, 158 ) -> Result<GroupMetadata, EventParseError> { 159 require_kind(kind, KIND_GROUP_METADATA, "39000")?; 160 require_empty_content(content, "content")?; 161 Ok(GroupMetadata { 162 d_tag: required_tag_value(tags, TAG_D)?, 163 metadata: metadata_from_tags(tags)?, 164 }) 165 } 166 167 pub fn group_admins_from_event( 168 kind: u32, 169 tags: &[Vec<String>], 170 content: &str, 171 ) -> Result<GroupAdmins, EventParseError> { 172 require_kind(kind, KIND_GROUP_ADMINS, "39001")?; 173 Ok(GroupAdmins { 174 d_tag: required_tag_value(tags, TAG_D)?, 175 description: optional_content(content), 176 admins: user_refs_from_tags(tags)?, 177 }) 178 } 179 180 pub fn group_members_from_event( 181 kind: u32, 182 tags: &[Vec<String>], 183 content: &str, 184 ) -> Result<GroupMembers, EventParseError> { 185 require_kind(kind, KIND_GROUP_MEMBERS, "39002")?; 186 Ok(GroupMembers { 187 d_tag: required_tag_value(tags, TAG_D)?, 188 description: optional_content(content), 189 members: user_refs_from_tags(tags)?, 190 }) 191 } 192 193 pub fn group_roles_from_event( 194 kind: u32, 195 tags: &[Vec<String>], 196 content: &str, 197 ) -> Result<GroupRoles, EventParseError> { 198 require_kind(kind, KIND_GROUP_ROLES, "39003")?; 199 Ok(GroupRoles { 200 d_tag: required_tag_value(tags, TAG_D)?, 201 description: optional_content(content), 202 roles: roles_from_tags(tags)?, 203 }) 204 } 205 206 fn require_kind( 207 kind: u32, 208 expected_kind: u32, 209 expected: &'static str, 210 ) -> Result<(), EventParseError> { 211 if kind == expected_kind { 212 Ok(()) 213 } else { 214 Err(EventParseError::InvalidKind { 215 expected, 216 got: kind, 217 }) 218 } 219 } 220 221 fn metadata_from_tags(tags: &[Vec<String>]) -> Result<GroupEditableMetadata, EventParseError> { 222 Ok(GroupEditableMetadata { 223 name: optional_tag_value(tags, TAG_NAME)?, 224 about: optional_tag_value(tags, TAG_ABOUT)?, 225 picture: optional_tag_value(tags, TAG_PICTURE)?, 226 is_private: marker_tag(tags, TAG_PRIVATE)?, 227 is_restricted: marker_tag(tags, TAG_RESTRICTED)?, 228 is_closed: marker_tag(tags, TAG_CLOSED)?, 229 is_hidden: marker_tag(tags, TAG_HIDDEN)?, 230 supported_kinds: supported_kinds_from_tags(tags)?, 231 }) 232 } 233 234 fn marker_tag(tags: &[Vec<String>], key: &'static str) -> Result<bool, EventParseError> { 235 let mut found = false; 236 for tag in tags 237 .iter() 238 .filter(|tag| tag.first().map(|value| value.as_str()) == Some(key)) 239 { 240 if found || tag.len() != 1 { 241 return Err(EventParseError::InvalidTag(key)); 242 } 243 found = true; 244 } 245 Ok(found) 246 } 247 248 fn supported_kinds_from_tags(tags: &[Vec<String>]) -> Result<Option<Vec<u32>>, EventParseError> { 249 let mut matches = tags 250 .iter() 251 .filter(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_SUPPORTED_KINDS)); 252 let Some(tag) = matches.next() else { 253 return Ok(None); 254 }; 255 if matches.next().is_some() { 256 return Err(EventParseError::InvalidTag(TAG_SUPPORTED_KINDS)); 257 } 258 let mut supported_kinds = Vec::new(); 259 for value in tag.iter().skip(1) { 260 validate_non_empty_tag_value(value, TAG_SUPPORTED_KINDS)?; 261 supported_kinds.push( 262 value 263 .parse::<u32>() 264 .map_err(|err| EventParseError::InvalidNumber(TAG_SUPPORTED_KINDS, err))?, 265 ); 266 } 267 Ok(Some(supported_kinds)) 268 } 269 270 fn required_user_tag(tags: &[Vec<String>]) -> Result<(String, Vec<String>), EventParseError> { 271 let tag = tags 272 .iter() 273 .find(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_P)) 274 .ok_or(EventParseError::MissingTag(TAG_P))?; 275 user_from_tag(tag) 276 } 277 278 fn user_refs_from_tags(tags: &[Vec<String>]) -> Result<Vec<GroupUserRef>, EventParseError> { 279 tags.iter() 280 .filter(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_P)) 281 .map(|tag| { 282 let (pubkey, roles) = user_from_tag(tag)?; 283 Ok(GroupUserRef { pubkey, roles }) 284 }) 285 .collect() 286 } 287 288 fn user_from_tag(tag: &[String]) -> Result<(String, Vec<String>), EventParseError> { 289 let pubkey = tag 290 .get(1) 291 .cloned() 292 .ok_or(EventParseError::InvalidTag(TAG_P))?; 293 validate_non_empty_tag_value(&pubkey, TAG_P)?; 294 let mut roles = Vec::new(); 295 for role in tag.iter().skip(2) { 296 validate_non_empty_tag_value(role, TAG_P)?; 297 roles.push(role.clone()); 298 } 299 Ok((pubkey, roles)) 300 } 301 302 fn roles_from_tags(tags: &[Vec<String>]) -> Result<Vec<GroupRole>, EventParseError> { 303 tags.iter() 304 .filter(|tag| tag.first().map(|value| value.as_str()) == Some(TAG_ROLE)) 305 .map(|tag| { 306 let name = tag 307 .get(1) 308 .cloned() 309 .ok_or(EventParseError::InvalidTag(TAG_ROLE))?; 310 validate_non_empty_tag_value(&name, TAG_ROLE)?; 311 let description = tag.get(2).cloned(); 312 if let Some(description) = description.as_deref() { 313 validate_non_empty_tag_value(description, TAG_ROLE)?; 314 } 315 let mut permissions = Vec::new(); 316 for permission in tag.iter().skip(3) { 317 validate_non_empty_tag_value(permission, TAG_ROLE)?; 318 permissions.push(permission.clone()); 319 } 320 Ok(GroupRole { 321 name, 322 description, 323 permissions, 324 }) 325 }) 326 .collect() 327 } 328 329 fn optional_content(content: &str) -> Option<String> { 330 if content.is_empty() { 331 None 332 } else { 333 Some(content.to_string()) 334 } 335 }