e8e28c109d8d8384e84ef78a2d6355f3b8fbdb09
[scpubgit/SCS.git] / lib / SCSite / FeedGenerator.pm
1 package SCSite::FeedGenerator;
2
3 use Moo;
4 no warnings 'once';
5
6 has id_prefix => (is => 'ro', required => 1);
7 has pages => (is => 'ro', required => 1);
8
9 sub feed_http_response {
10   my ($self, $code, $feed_config) = @_;
11   $self->_feed_response(
12     $code, $self->_config_to_data($feed_config)
13   );
14 }
15
16 sub _config_to_data {
17   my ($self, $config) = @_;
18   my $base_page = $self->pages->get({ path => $config->{base} });
19   my @entry_pages = $base_page->children(%{$config->{entries}})
20                               ->latest(10)->flatten;
21   my $updated = (sort map $_->created, @entry_pages)[-1];
22   +{
23      %$config,
24      id => $self->_id_for($base_page->path),
25      web_url => $base_page->path.'/',
26      feed_url => "/feed/${\$config->{base}}/",
27      updated => join('T', split(' ',$updated)).'Z',
28      entries => [ map +{
29        title => $_->title,
30        summary_html => do {
31          use HTML::Tags;
32          join '', HTML::Tags::to_html_string(<p>, $_->description, </p>)
33        },
34        content_html => $_->body,
35        created => join('T', split(' ',$_->created)).'Z',
36        web_url => $_->path,
37      }, @entry_pages ],
38   }
39 }
40
41 sub _id_for {
42   my ($self, $for) = @_;
43   join '', $self->id_prefix, $for;
44 }
45
46 sub _feed_response {
47   my ($self, $code, $data) = @_;
48   [ $code,
49     [ 'Content-type' => 'application/atom+xml' ],
50     [ $self->_feed_string($data) ]
51   ]
52 }
53
54 sub _feed_string {
55   my ($self, $data) = @_;
56   XML::Tags::to_xml_string(
57     $self->_feed_data_to_tags($data)
58   );
59 }
60
61 sub _feed_data_to_tags {
62   my ($self, $data) = @_;
63   use XML::Tags qw(
64     feed title subtitle link id
65   );
66   my ($web_url, $feed_url) = @{$data}{qw(web_url feed_url)};
67   (\'<?xml version="1.0" encoding="UTF-8"?>', "\n",
68   <feed xmlns="http://www.w3.org/2005/Atom">, "\n",
69     '  ', <title type="text">, $data->{title}, </title>, "\n",
70     ($data->{subtitle}
71       ? ('  ', <subtitle type="text">, $data->{subtitle}, </subtitle>, "\n",)
72       : ()),
73     '  ', <link rel="alternate" type="text/html" href="${web_url}" />, "\n",
74     '  ', <link rel="self" type="application/atom+xml" href="${feed_url}" />, "\n",
75     '  ', <updated>, $data->{updated}, </updated>, "\n",
76     '  ', <id>, $data->{id}, </id>, "\n",
77     (map $self->_entry_data_to_tags($_), @{$data->{entries}}),
78   </feed>);
79 }
80
81 sub _entry_data_to_tags {
82   my ($self, $data) = @_;
83   use XML::Tags qw(
84     entry title author name link id published updated summary content
85   );
86   my $web_url = $data->{web_url};
87   '  ', <entry>, "\n",
88     '    ', <title>, $data->{title}, </title>, "\n",
89     '    ', <author>, <name>, "Shadowcat Staff", </name>, </author>, "\n",
90     '    ', <link href="${web_url}" />, "\n",
91     '    ', <id>, $self->_id_for($data->{web_url}), </id>, "\n",
92     '    ', <published>, $data->{created}, </published>, "\n",
93     '    ', <updated>, ($data->{created}||$data->{updated}), </updated>, "\n",
94     ($data->{summary_html}
95       ? ('    ', <summary type="html">, \('<![CDATA['.$data->{summary_html}.']]>'), </summary>, "\n")
96       : ()
97     ),
98     '    ', <content type="html">, \('<![CDATA['.$data->{content_html}.']]>'), </content>, "\n",
99   '  ', </entry>, "\n";
100 }
101
102 1;