diff --git a/blog b/blog index 83f331c..5145556 100755 --- a/blog +++ b/blog @@ -44,8 +44,12 @@ multi MAIN( my $title = get; print "Tagline: "; my $tagline = get; + print "Base URL: "; + my $base-url = get; - my $meta = BlogMeta.new: title => $title, tagline => $tagline; + my $meta = + BlogMeta.new: + title => $title, tagline => $tagline, base-url => $base-url; my $db = DB::PostDB.init: $meta; diff --git a/lib/Atom.rakumod b/lib/Atom.rakumod new file mode 100644 index 0000000..0c0ad7b --- /dev/null +++ b/lib/Atom.rakumod @@ -0,0 +1,64 @@ +use v6.e.PREVIEW; + +use DB::Post; +use DB::BlogMeta; + +use XML; + +unit module Atom; + +# get the link for a post +sub post-link(BlogMeta:D $meta, Int:D $id, Post:D $post --> Str:D) { + my @slugs = $post.all-slugs; + my $base = $meta.get-base-url; + if @slugs.elems { + "$base/posts/by-slug/{@slugs[*-1]}.html" + } else { + "$base/posts/by-id/$id.html" + } +} + +#| Convert a single post to an atom item +sub post-to-item(BlogMeta:D $meta, Int:D $id, Post:D $post --> XML::Element) { + my $link = post-link $meta, $id, $post; + my $desc = $post.description; + my $xml = XML::Element.new(:name); + $xml.append: + XML::Element.new(:name, :nodes([$link])); + $xml.append: + XML::Element.new(:name, :nodes([$post.title])); + $xml.append: + XML::Element.new(:name<updated>, :nodes([$post.updated])); + $xml.append: + XML::Element.new(:name<published>, :nodes([$post.posted-at])); + my $author = XML::Element.new(:name<author>); + $author.append: + XML::Element.new(:name<email>, :nodes(["thatonelutenist@stranger.systems"])); + $author.append: + XML::Element.new(:name<name>, :nodes(["Nathan McCarty"])); + $xml.append: $author; + $xml.append: + XML::Element.new(:name<link>, :attribs({:href($link), :rel<alternate>})); + $xml.append: + XML::Element.new(:name<summary>, :nodes([$desc])) if $desc; + + $xml +} + +#| Produce an atom feed from the database +sub posts-to-atom($db --> XML::Element) is export { + my $updated = $db.posts.values.map(*.updated).max; + my $xml = + XML::Element.new( + :name<feed>, + :attribs({:xmlns('http://www.w3.org/2005/Atom')})); + $xml.append: XML::Element.new(:name<id>, :nodes([$db.meta.get-base-url])); + $xml.append: XML::Element.new(:name<title>, :nodes([$db.meta.title])); + $xml.append: XML::Element.new(:name<updated>, :nodes([$updated])); + for $db.sorted-posts -> $pair { + unless $pair.value.hidden { + $xml.append: post-to-item $db.meta, $pair.key, $pair.value; + } + } + $xml +} diff --git a/lib/Config.rakumod b/lib/Config.rakumod index c7a32df..595d2ce 100644 --- a/lib/Config.rakumod +++ b/lib/Config.rakumod @@ -72,7 +72,7 @@ method site-header(BlogMeta:D $meta) { 'About'; ]; ]; - a :href</feed.xml>, [ + a :href</atom.xml>, [ icon 'rss'; ' '; span [ @@ -193,8 +193,8 @@ method generate-blurb(Int:D $id, $db) { my $desc = $post.description; my @slugs = $post.all-slugs; # Use the primary slug if there is one, the id if there isn't - my $link = do if @slugs.elems > 0 { - "/posts/by-slug/{@slugs[0]}.html" + my $link = do if @slugs.elems { + "/posts/by-slug/{@slugs[*-1]}.html" } else { "/posts/by-id/$id.html" } diff --git a/lib/DB.rakumod b/lib/DB.rakumod index c4e7827..fe30ec0 100644 --- a/lib/DB.rakumod +++ b/lib/DB.rakumod @@ -5,12 +5,14 @@ unit module DB; use Pandoc; use JSON::Class:auth<zef:vrurg>; +use XML; use DB::Post; use DB::BlogMeta; use DB::MarkdownPost; use DB::IdrisPost; use DB::PlaceholderPost; +use Atom; use Config; subset PostTypes where MarkdownPost:D | IdrisPost:D | PlaceholderPost:D; @@ -92,12 +94,14 @@ class PostDB { $out-dir.add('index.html').spurt: $config.generate-index(self); # Render the archive $out-dir.add('archive.html').spurt: $config.generate-archive(self); - # TODO: Symlink the about article + # Symlink the about article my $about-path = $out-dir.add('about.html'); $about-path.unlink if $about-path.l; $by-id.add("{$!meta.about-id}.html").symlink: $about-path; - # TODO: Render the rss/atom feed - die "Not Implemented" + # Render the rss/atom feed + my $atom-path = $out-dir.add('atom.xml'); + my $atom = posts-to-atom self; + $atom-path.spurt: ~$atom; } #| Get a list of posts sorted by date diff --git a/lib/DB/BlogMeta.rakumod b/lib/DB/BlogMeta.rakumod index b8477ae..e6ccf5d 100644 --- a/lib/DB/BlogMeta.rakumod +++ b/lib/DB/BlogMeta.rakumod @@ -16,3 +16,16 @@ has Int:D $.placeholder-id is rw = 0; #| The id of the about post has Int:D $.about-id is rw = 0; + +#| The base url of this post +has Str:D $.base-url is required; + +#| Return the base url, but substitute it out if the test environment variable +#| is set +method get-base-url(--> Str:D) { + if %*ENV<BLOG_TEST> { + "http://localhost:8080" + } else { + $!base-url + } +} diff --git a/lib/DB/Post.rakumod b/lib/DB/Post.rakumod index dbdc0f7..ed0819d 100644 --- a/lib/DB/Post.rakumod +++ b/lib/DB/Post.rakumod @@ -43,6 +43,15 @@ has Bool:D $.hidden is json is rw = False; #| document produced it method title(--> Str:D) {...} +#| The time the post was last updated at +method updated(--> DateTime:D) { + if @!edited-at { + @!edited-at.max + } else { + $!posted-at + } +} + #| Get the list of slugs for this post, including ones auto generated from #| the title, as well as any additional slugs method all-slugs(--> Array[Str:D]) {