Better rssing, now with tags!
[blerg.git] / rss.cgi
1 #!/usr/bin/perl
2 use CGI::Fast qw/:cgi/;
3 use Blerg::Database;
4 use URI::Escape;
5 use POSIX qw/strftime/;
6 use strict;
7
8 my $baseurl = Blerg::Database::constant('BASEURL');
9
10 sub xml_escape {
11     local $_ = shift;
12     s/&/&/g;
13     s/</&lt;/g;
14     s/>/&gt;/g;
15     return $_;
16 }
17
18 sub print_404 {
19     print header(-type => 'text/html',
20                  -status => '404 Not Found');
21     print <<DOC;
22 <!DOCTYPE html>
23 <h1>404 Not Found</h1>
24 Not Found
25 DOC
26 }
27
28 sub print_rss {
29     my ($type, $name, @items) = @_;
30
31     my ($title, $link);
32     if ($type eq 'user') {
33         $title = "${name}'s blĂ«rg";
34         $link = "${baseurl}#$name";
35     } elsif ($type eq 'tag' || $type eq 'ref') {
36         $title = $name;
37         my $basename = $name;
38         $basename =~ s/^.//;
39         $link = "${baseurl}#/$type/$basename";
40     }
41
42     print <<HEADER;
43 <?xml version="1.0" encoding="utf-8" ?>
44 <rss version="2.0">
45   <channel>
46     <title>$title</title>
47     <link>$link</link>
48     <description>Textual vomit</description>
49 HEADER
50
51     for my $i (@items) {
52         my $data = xml_escape($i->{data});
53         my $post_time = strftime("%a, %d %b %Y %H:%M:%S %Z", localtime($i->{timestamp}));
54         my $author = defined $i->{author} ? $i->{author} : $name;
55         print <<ITEM;
56     <item>
57       <pubDate>$post_time</pubDate>
58       <guid>${baseurl}get/$author/$i->{record}</guid>
59       <description>$data</description>
60     </item>
61 ITEM
62     }
63
64     print <<'FOOTER'
65   </channel>
66 </rss>
67 FOOTER
68 }
69
70 REQUEST:
71 while (my $q = new CGI::Fast) {
72     my @path = split('/', $ENV{PATH_INFO});
73     shift @path;
74
75     if (@path == 1) {
76         # Assume this is a username; redirect to /user/<username>
77         my $username = $path[0];
78         my $b = Blerg::Database->open_existing($username);
79         if (!defined $b) {
80             print_404;
81             next REQUEST;
82         }
83         print header(-type => 'application/rss+xml',
84                      -charset => 'utf8',
85                      -status => '301 Moved Permanently',
86                      -location => "${baseurl}rss/user/$username");
87         # And present the content in case their client is broken
88         my $i = {
89             record => '?failed_redirect',
90                 timestamp => time,
91             data => qq{Your RSS aggregator is dumb and isn't following 301 redirects.  Please manually redirect it here: ${baseurl}rss/user/$username}
92         };
93         print_rss(user => $username, $i);
94     } elsif ($path[0] eq 'user') {
95         my $username = $path[1];
96         my $b = Blerg::Database->open_existing($username);
97         if (!defined $b) {
98             print_404;
99             next REQUEST;
100         }
101         print header(-type => 'application/rss+xml');
102         my $n = $b->record_count - 1;
103         my @list = reverse map {
104             {
105                 record    => $_,
106                 data      => $b->fetch($_),
107                 timestamp => $b->timestamp($_),
108             }
109         } ($n > 50 ? $n - 50 : 0)..$n;
110         $b->close;
111         print_rss(user => $username, @list);
112     } elsif ($path[0] eq 'tag') {
113         my $tag = $path[1];
114         $tag =~ s/^H/#/;
115         my @list = Blerg::Database::tag_list($tag, 0, -1);
116         @list = map {
117             my $b = Blerg::Database->open_existing($_->{author});
118             my $data = $b->fetch($_->{record});
119             my $timestamp = $b->timestamp($_->{record});
120             $b->close;
121             {
122                 author => $_->{author},
123                 record => $_->{record},
124                 data => $data,
125                 timestamp => $timestamp,
126             };
127         } @list;
128         print header(-type => 'application/rss+xml');
129         if (substr($tag, 0, 1) eq '#') {
130             print_rss(tag => $tag, @list);
131         } else {
132             print_rss(ref => $tag, @list);
133         }
134     } elsif ($path[0] eq 'ref') {
135     } elsif ($path[0] eq 'feed') {
136     }
137 }