use crate::{
endpoint_discovery::find_target_endpoint, error::WebmentionError, http_client::get, wm_url::Url,
};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Webmention {
pub source: Url,
pub target: Url,
checked: Option<bool>,
sent: bool,
}
#[derive(Debug, PartialEq)]
pub enum WebmentionAcceptance {
NoTargetEndpoint,
NotValid,
NotAccepted,
Accepted,
}
impl Webmention {
pub fn new<T: AsRef<str>>(source: T, target: T) -> Result<Webmention, url::ParseError> {
let source_url = Url::parse(source.as_ref())?;
let target_url = Url::parse(target.as_ref())?;
Ok(Webmention::from((source_url, target_url)))
}
pub async fn send(&mut self) -> Result<WebmentionAcceptance, WebmentionError> {
let valid = if let Some(cached_valid) = self.checked {
cached_valid
} else {
let valid = self.check().await.is_ok();
self.checked = Some(valid);
valid
};
if !valid {
return Ok(WebmentionAcceptance::NotValid);
}
let endpoint_result = find_target_endpoint(&self.target).await.map_err(|e| {
WebmentionError::DiscoveryRequestFailed {
source: Box::new(e),
url: self.target.clone(),
}
})?;
if endpoint_result.is_none() {
return Ok(WebmentionAcceptance::NoTargetEndpoint);
}
let endpoint = endpoint_result.ok_or(WebmentionError::UnparseableDocument)?;
let accepted = crate::http_client::post(&endpoint, &self).await?;
self.sent = true;
match accepted {
true => Ok(WebmentionAcceptance::Accepted),
false => Ok(WebmentionAcceptance::NotAccepted),
}
}
pub async fn check(&mut self) -> Result<(), WebmentionError> {
let response = get(&self.source).await?;
response.html.contains(&self.target)
}
pub fn set_checked(&mut self, checked: bool) {
self.checked = Some(checked);
}
}
impl From<(&Url, &Url)> for Webmention {
fn from(tuple: (&Url, &Url)) -> Webmention {
Webmention {
source: tuple.0.clone(),
target: tuple.1.clone(),
sent: false,
checked: None,
}
}
}
impl From<(Url, Url)> for Webmention {
fn from(tuple: (Url, Url)) -> Webmention {
Webmention {
source: tuple.0,
target: tuple.1,
sent: false,
checked: None,
}
}
}
#[cfg(test)]
mod test {
use super::{Webmention, WebmentionAcceptance};
use crate::wm_url::Url;
use tokio_test::block_on;
#[ignore]
#[test]
fn webmention_check_test() {
let source = Url::parse("https://marinintim.com/notes/2021/hwc-rsvp/").unwrap();
let target = Url::parse("https://evgenykuznetsov.org/events/2021/hwc-online/").unwrap();
let mut mention = Webmention::from((source, target));
let result = block_on(mention.check());
assert!(result.is_ok());
}
#[ignore]
#[test]
fn webmention_new_test() {
let wm = Webmention::new(
"https://marinintim.com/notes/2021/hwc-rsvp/",
"https://evgenykuznetsov.org/events/2021/hwc-online/",
);
assert!(wm.is_ok());
let mut wm = wm.unwrap();
wm.set_checked(true); let result = block_on(wm.send());
assert!(result.is_ok());
let result = result.unwrap();
assert_eq!(result, WebmentionAcceptance::Accepted);
}
}