lib

Core libraries for Radroots
git clone https://radroots.dev/git/lib.git
Log | Files | Refs | README

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 }