aboutsummaryrefslogblamecommitdiffstats
path: root/stanza/src/xep_0156.rs
blob: bf6eac54f5a3fb60d97c33e550215de2ba32872d (plain) (tree)
1
2
                            
                                                         















                                                                       
                                                                                        
























                                                                 
                                                  














                                                                         
                                                                               







                                        
                                                  









                                                                   
                                                                               







                                        
                                                  








                                                                          
                                                                               







                                        
                                                  










                                                                        
                                                                               











                                                
                                                  
















                                                        
                                                                               






















                                                          
                                                  
















                                                                  
                                                                               











                                                                     
                                                  









                                                                             
                                                                           







                                                  
                                                  


                                                            
use chrono::{DateTime, Utc};
use peanuts::{Element, FromElement, IntoElement, XML_NS};

pub const XMLNS: &str = "http://docs.oasis-open.org/ns/xri/xrd-1.0";
pub const SIGNATURE_XMLNS: &str = "http://www.w3.org/2000/09/xmldsig#";

#[derive(Debug, Clone)]
pub struct XRD {
    pub id: Option<String>,
    pub expires: Option<Expires>,
    pub subject: Option<Subject>,
    pub aliases: Vec<Alias>,
    pub properties: Vec<Property>,
    pub links: Vec<Link>,
    pub signature: Vec<Signature>,
}

impl FromElement for XRD {
    fn from_element(mut element: peanuts::Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("XRD")?;
        element.check_namespace(XMLNS)?;

        let id = element.attribute_opt_namespaced("id", XML_NS)?;

        let expires = element.child_opt()?;
        let subject = element.child_opt()?;
        let aliases = element.children()?;
        let properties = element.children()?;
        let links = element.children()?;
        let signature = element.children()?;

        Ok(Self {
            id,
            expires,
            subject,
            aliases,
            properties,
            links,
            signature,
        })
    }
}

impl IntoElement for XRD {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("XRD", Some(XMLNS))
            .push_attribute_opt_namespaced(XML_NS, "id", self.id.clone())
            .push_child_opt(self.expires.clone())
            .push_child_opt(self.subject.clone())
            .push_children(self.aliases.clone())
            .push_children(self.properties.clone())
            .push_children(self.links.clone())
            .push_children(self.signature.clone())
    }
}

#[derive(Debug, Clone)]
pub struct Expires(pub DateTime<Utc>);

impl FromElement for Expires {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Expires")?;
        element.check_namespace(XMLNS)?;

        Ok(Self(element.pop_value()?))
    }
}

impl IntoElement for Expires {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Expires", Some(XMLNS))
            .push_text(self.0.format("%C%y-%m-%dT%H:%M:%S%.3f%:z"))
    }
}

// anyURI
#[derive(Debug, Clone)]
pub struct Subject(pub String);

impl FromElement for Subject {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Subject")?;
        element.check_namespace(XMLNS)?;

        Ok(Self(element.pop_value()?))
    }
}

impl IntoElement for Subject {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Subject", Some(XMLNS)).push_text(self.0.clone())
    }
}

// anyURI
#[derive(Debug, Clone)]
pub struct Alias(pub String);

impl FromElement for Alias {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Alias")?;
        element.check_namespace(XMLNS)?;

        Ok(Self(element.pop_value()?))
    }
}

impl IntoElement for Alias {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Alias", Some(XMLNS)).push_text(self.0.clone())
    }
}

#[derive(Debug, Clone)]
pub struct Property {
    pub r#type: String,
    pub property: Option<String>,
}

impl FromElement for Property {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Property")?;
        element.check_name(XMLNS)?;

        let r#type = element.attribute("type")?;

        let property = element.pop_value_opt()?;

        Ok(Self { r#type, property })
    }
}

impl IntoElement for Property {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Property", Some(XMLNS))
            .push_attribute("type", self.r#type.clone())
            .push_text_opt(self.property.clone())
    }
}

#[derive(Debug, Clone)]
pub struct Link {
    pub rel: Option<String>,
    pub r#type: Option<String>,
    pub href: Option<String>,
    pub template: Option<String>,
    pub titles: Vec<Title>,
    pub properties: Vec<Property>,
}

impl FromElement for Link {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Link")?;
        element.check_namespace(XMLNS)?;

        let rel = element.attribute_opt("rel")?;
        let r#type = element.attribute_opt("type")?;
        let href = element.attribute_opt("href")?;
        let template = element.attribute_opt("template")?;

        let titles = element.children()?;
        let properties = element.children()?;

        Ok(Self {
            rel,
            r#type,
            href,
            template,
            titles,
            properties,
        })
    }
}

impl IntoElement for Link {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Link", Some(XMLNS))
            .push_attribute_opt("rel", self.rel.clone())
            .push_attribute_opt("type", self.r#type.clone())
            .push_attribute_opt("href", self.href.clone())
            .push_attribute_opt("template", self.template.clone())
            .push_children(self.titles.clone())
            .push_children(self.properties.clone())
    }
}

#[derive(Debug, Clone)]
pub struct Title {
    pub lang: Option<String>,
    pub title: String,
}

impl FromElement for Title {
    fn from_element(mut element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Title")?;
        element.check_namespace(XMLNS)?;

        let lang = element.attribute_opt_namespaced("lang", XML_NS)?;

        let title = element.pop_value_opt()?.unwrap_or_default();

        Ok(Self { lang, title })
    }
}

impl IntoElement for Title {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Title", Some(XMLNS))
            .push_attribute_opt_namespaced(XML_NS, "lang", self.lang.clone())
            .push_text(self.title.clone())
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Signature;

impl FromElement for Signature {
    fn from_element(element: Element) -> peanuts::DeserializeResult<Self> {
        element.check_name("Signature")?;
        element.check_namespace(SIGNATURE_XMLNS)?;

        Ok(Self)
    }
}

impl IntoElement for Signature {
    fn builder(&self) -> peanuts::ElementBuilder {
        Element::builder("Signature", Some(SIGNATURE_XMLNS))
    }
}