domain support for feeds, factor out sc-specific bits
[scpubgit/SCS.git] / lib / SCSite / FeedGenerator.pm
index 463ce56..104b8cc 100644 (file)
@@ -1,46 +1,62 @@
 package SCSite::FeedGenerator;
 
+use URI;
 use Moo;
 no warnings 'once';
 
-has id_prefix => (is => 'ro', required => 1);
 has pages => (is => 'ro', required => 1);
 
 sub feed_http_response {
-  my ($self, $code, $feed_config) = @_;
+  my ($self, $code, $feed_config, $env) = @_;
   $self->_feed_response(
-    $code, $self->_config_to_data($feed_config)
+    $code, $self->_config_to_data($feed_config, $env)
   );
 }
 
 sub _config_to_data {
-  my ($self, $config) = @_;
+  my ($self, $config, $env) = @_;
+  my $url_scheme = $env->{'psgi.url_scheme'} || "http";
+  my $url_port = $env->{SERVER_PORT}||80;
+  my $base_url = URI->new(
+    $url_scheme
+    .'://'
+    .($env->{HTTP_HOST}
+      or (
+        ($env->{SERVER_NAME} || "")
+        .($url_scheme eq 'http' && $url_port == 80
+           ? ''
+           : ":${url_port}"
+         )
+      ))
+    .($env->{SCRIPT_NAME} || '/')
+  );
+  my $abs = sub { URI->new_abs($_[0], $base_url)->as_string };
   my $base_page = $self->pages->get({ path => $config->{base} });
   my @entry_pages = $base_page->children(%{$config->{entries}})
                               ->latest(10)->flatten;
+  my $updated = (sort map $_->created, @entry_pages)[-1];
   +{
      %$config,
-     id => $self->_id_for($base_page->path),
-     web_url => $base_page->path,
-     feed_url => "/feed/${\$config->{base}}",
-     entries => [ map +{
-       title => $_->title,
-       summary_html => do {
-         use HTML::Tags;
-         HTML::Tags::to_html_string(<p>, $_->description, </p>)
-       },
-       content_html => $_->body,
-       created => $_->created,
-       web_url => $_->path,
-     }, @entry_pages ],
+     id => $abs->("feed/${\$config->{base}}/"),
+     web_url => $abs->($config->{base}.'/'),
+     feed_url => $abs->("feed/${\$config->{base}}/"),
+     updated => join('T', split(' ',$updated)).'Z',
+     entries => [ map {
+      my $page_url = $abs->(do { (my $p = $_->path) =~ s/^\///; "$p/" });
+      +{
+         title => $_->title,
+         summary_html => do {
+           use HTML::Tags;
+           join '', HTML::Tags::to_html_string(<p>, $_->description, </p>)
+         },
+         content_html => $self->_absolutify_html($_->body, $base_url, $page_url),
+         created => join('T', split(' ',$_->created)).'Z',
+         web_url => $page_url,
+       }
+    } @entry_pages ],
   }
 }
 
-sub _id_for {
-  my ($self, $for) = @_;
-  join '', $self->id_prefix, $for;
-}
-
 sub _feed_response {
   my ($self, $code, $data) = @_;
   [ $code,
@@ -62,35 +78,44 @@ sub _feed_data_to_tags {
     feed title subtitle link id
   );
   my ($web_url, $feed_url) = @{$data}{qw(web_url feed_url)};
-  (\'<?xml version="1.0" encoding="UTF-8"?>',
-  <feed xmlns="http://www.w3.org/2005/Atom">,
-    <title type="text">, $data->{title}, </title>,
+  (\'<?xml version="1.0" encoding="UTF-8"?>', "\n",
+  <feed xmlns="http://www.w3.org/2005/Atom">, "\n",
+    '  ', <title type="text">, $data->{title}, </title>, "\n",
     ($data->{subtitle}
-      ? (<subtitle type="text">, $data->{subtitle}, </subtitle>)
+      ? ('  ', <subtitle type="text">, $data->{subtitle}, </subtitle>, "\n",)
       : ()),
-    <link rel="alternate" type="text/html" href="${web_url}" />,
-    <link rel="self" type="application/atom+xml" href="${feed_url}" />,
-    <id>, $data->{id}, </id>,
+    '  ', <link rel="alternate" type="text/html" href="${web_url}" />, "\n",
+    '  ', <link rel="self" type="application/atom+xml" href="${feed_url}" />, "\n",
+    '  ', <updated>, $data->{updated}, </updated>, "\n",
+    '  ', <id>, $data->{id}, </id>, "\n",
     (map $self->_entry_data_to_tags($_), @{$data->{entries}}),
   </feed>);
 }
 
 sub _entry_data_to_tags {
   my ($self, $data) = @_;
-  use XML::Tags qw(entry title link id published updated summary content);
+  use XML::Tags qw(
+    entry title author name link id published updated summary content
+  );
   my $web_url = $data->{web_url};
-  <entry>,
-    <title>, $data->{title}, </title>,
-    <link href="${web_url}" />,
-    <id>, $self->_id_for($data->{web_url}), </id>,
-    <published>, $data->{created}, </published>,
-    <updated>, ($data->{created}||$data->{updated}), </updated>,
+  '  ', <entry>, "\n",
+    '    ', <title>, $data->{title}, </title>, "\n",
+    '    ', <author>, <name>, "Shadowcat Staff", </name>, </author>, "\n",
+    '    ', <link href="${web_url}" />, "\n",
+    '    ', <id>, $web_url, </id>, "\n",
+    '    ', <published>, $data->{created}, </published>, "\n",
+    '    ', <updated>, ($data->{created}||$data->{updated}), </updated>, "\n",
     ($data->{summary_html}
-      ? (<summary type="html">, \($data->{summary_html}), </summary>)
+      ? ('    ', <summary type="html">, \('<![CDATA['.$data->{summary_html}.']]>'), </summary>, "\n")
       : ()
     ),
-    <content type="html">, \($data->{body_html}), </content>,
-  </entry>;
+    '    ', <content type="html">, \('<![CDATA['.$data->{content_html}.']]>'), </content>, "\n",
+  '  ', </entry>, "\n";
+}
+
+sub _absolutify_html {
+  my ($self, $html, $base_url, $page_url) = @_;
+  $html;
 }
 
 1;