Compare commits

...

3 Commits

Author SHA1 Message Date
projectmoon 20630beeda Update licenses check
continuous-integration/drone/push Build is passing Details
2024-12-04 22:00:19 +01:00
projectmoon 46088bb627 Fix odd compilation error on newer Rust
continuous-integration/drone/push Build is failing Details
2024-12-04 21:55:26 +01:00
projectmoon 1fe590925b More tests
continuous-integration/drone/push Build is passing Details
2024-03-27 12:36:42 +01:00
6 changed files with 725 additions and 322 deletions

892
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +1,6 @@
[package] [package]
name = "gemfreely" name = "gemfreely"
version = "0.1.7" version = "0.1.9"
edition = "2021" edition = "2021"
license = "AGPL-3.0-or-later" license = "AGPL-3.0-or-later"
description = "Synchronize Gemini protocol blogs to the Fediverse" description = "Synchronize Gemini protocol blogs to the Fediverse"

View File

@ -27,8 +27,9 @@ allow = [
"MPL-2.0", "MPL-2.0",
"ISC", "ISC",
"Unicode-DFS-2016", "Unicode-DFS-2016",
"Unicode-3.0",
"OpenSSL", "OpenSSL",
"BSD-3-Clause" "BSD-3-Clause",
] ]
# Some crates don't have (easily) machine readable licensing information, # Some crates don't have (easily) machine readable licensing information,

View File

@ -94,13 +94,18 @@ async fn sync_gemlog(
let mut count = 0; let mut count = 0;
for entry in gemlogs_to_post { for entry in gemlogs_to_post {
let post = wf.create_post(entry).await?; let result = wf.create_post(entry).await;
count += 1; count += 1;
if let Ok(post) = result {
println!( println!(
"Created post: {} [title={}]", "Created post: {} [title={}]",
post.id, post.id,
post.title.unwrap_or_default() post.title.unwrap_or_default()
); );
} else {
println!("Error creating post: {} ", result.unwrap_err());
}
} }
println!("Post synchronization complete [posts synced={}]", count); println!("Post synchronization complete [posts synced={}]", count);

View File

@ -146,7 +146,11 @@ impl Gemfeed {
settings: &GemfeedParserSettings, settings: &GemfeedParserSettings,
) -> Result<Gemfeed> { ) -> Result<Gemfeed> {
if let Some(content) = resp.content() { if let Some(content) = resp.content() {
let feed = content.parse::<AtomFeed>()?; let feed = match content.parse::<AtomFeed>() {
Ok(feed) => feed,
Err(_) => return Err(anyhow!("Could not parse Atom feed")),
};
let entries = parse_atom(&feed, settings)?; let entries = parse_atom(&feed, settings)?;
let title = feed.title(); let title = feed.title();
Ok(Self::new(url, title, entries)) Ok(Self::new(url, title, entries))
@ -224,8 +228,31 @@ pub struct GemfeedEntry {
body: OnceCell<String>, body: OnceCell<String>,
} }
impl Default for GemfeedEntry {
fn default() -> Self {
GemfeedEntry {
body: OnceCell::default(),
title: String::default(),
slug: String::default(),
url: Url::parse("gemini://example.com").unwrap(),
published: Option::default(),
}
}
}
#[allow(dead_code)] #[allow(dead_code)]
impl GemfeedEntry { impl GemfeedEntry {
/// Consumes self to forcibly set body to the given string.
pub fn with_body(self, body: String) -> GemfeedEntry {
GemfeedEntry {
title: self.title,
slug: self.slug,
published: self.published,
url: self.url,
body: OnceCell::from(body),
}
}
pub fn from_gemtext(base_url: &Url, node: &GemtextNode) -> Result<GemfeedEntry> { pub fn from_gemtext(base_url: &Url, node: &GemtextNode) -> Result<GemfeedEntry> {
let link = GemfeedLink::try_from(node)?; let link = GemfeedLink::try_from(node)?;
// Gemfeeds have only the date--according to spec, it should // Gemfeeds have only the date--according to spec, it should
@ -405,6 +432,63 @@ impl TryFrom<&AtomEntry> for GemfeedLink {
} }
} }
#[cfg(test)]
mod gemfeed_entry_tests {
use super::*;
#[test]
fn parse_markdown_with_gt_lt_title() -> Result<()> {
let gemtext: String = r#"
# This is gemtext <dyn>
With a > in it.
"#
.lines()
.map(|line| line.trim_start())
.map(|line| format!("{}\n", line))
.collect();
let entry = GemfeedEntry {
published: None,
slug: "".to_string(),
title: "".to_string(),
url: Url::parse("gemini://example.com")?,
body: OnceCell::from(gemtext),
};
let result = entry.body_as_markdown();
assert!(result.is_ok());
Ok(())
}
#[test]
fn parse_markdown_with_gt_lt() -> Result<()> {
let gemtext: String = r#"
# This is gemtext
With a < in > it.
"#
.lines()
.map(|line| line.trim_start())
.map(|line| format!("{}\n", line))
.collect();
let entry = GemfeedEntry {
published: None,
slug: "".to_string(),
title: "".to_string(),
url: Url::parse("gemini://example.com")?,
body: OnceCell::from(gemtext),
};
let result = entry.body_as_markdown();
assert!(result.is_ok());
Ok(())
}
}
#[cfg(test)] #[cfg(test)]
mod gemfeed_tests { mod gemfeed_tests {
use super::*; use super::*;
@ -585,6 +669,30 @@ mod gemfeed_tests {
Ok(()) Ok(())
} }
#[test]
fn parse_gemfeed_handles_gt_lt() -> Result<()> {
let gemfeed: String = r#"
# My Gemfeed
This is a gemfeed.
## Posts
=> post2.gmi 2023-03-05 Post 2 <dyn>
=> post1.gmi 2023-02-01 Post 1 >
"#
.lines()
.map(|line| line.trim_start())
.map(|line| format!("{}\n", line))
.collect();
let base_url = Url::parse("gemini://example.com/posts")?;
let ast = GemtextAst::from_string(gemfeed);
let results = parse_gemfeed(&base_url, &ast)?;
assert_eq!(results.len(), 2);
Ok(())
}
#[test] #[test]
fn convert_gemfeed_links_success() -> Result<()> { fn convert_gemfeed_links_success() -> Result<()> {
let gemfeed_links: String = r#" let gemfeed_links: String = r#"

View File

@ -99,3 +99,24 @@ impl TryFrom<&GemfeedEntry> for PostCreateRequest {
Ok(req) Ok(req)
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tryfrom_to_request_handles_gt_lt() {
let gemtext: String = r#"
# This is gemtext <dyn>
With a > in it.
"#
.lines()
.map(|line| line.trim_start())
.map(|line| format!("{}\n", line))
.collect();
let entry = GemfeedEntry::default().with_body(gemtext);
let result = PostCreateRequest::try_from(entry);
assert!(result.is_ok());
}
}