add support for generating per-page rss feeds
authorjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Thu, 23 Mar 2006 21:00:51 +0000 (21:00 +0000)
committerjoey <joey@0fa5a96a-9a0e-0410-b3b2-a0fd24251071>
Thu, 23 Mar 2006 21:00:51 +0000 (21:00 +0000)
IkiWiki/Render.pm
doc/features.mdwn
doc/ikiwiki.setup
doc/usage.mdwn
ikiwiki
templates/page.tmpl
templates/rsspage.tmpl [new file with mode: 0644]

index df24fd5680ab13a3bc74f3a35bd979bfd93553ba..646e254a59cba73e84db87b291d53546e7631741 100644 (file)
@@ -79,7 +79,13 @@ sub parentlinks ($) { #{{{
        return @ret;
 } #}}}
 
-sub finalize ($$$) { #{{{
+sub rsspage ($) { #{{{
+       my $page=shift;
+
+       return $page.".rss";
+} #}}}
+
+sub genpage ($$$) { #{{{
        my $content=shift;
        my $page=shift;
        my $mtime=shift;
@@ -102,6 +108,10 @@ sub finalize ($$$) { #{{{
                $u=~s/\[\[file\]\]/$pagesources{$page}/g;
                $template->param(historyurl => $u);
        }
+
+       if ($config{rss}) {
+               $template->param(rssurl => rsspage($page));
+       }
        
        $template->param(
                title => $title,
@@ -116,6 +126,59 @@ sub finalize ($$$) { #{{{
        return $template->output;
 } #}}}
 
+sub date_822 ($) { #{{{
+       my $time=shift;
+
+       eval q{use POSIX};
+       return POSIX::strftime("%a, %d %b %Y %H:%M:%S %z", localtime($time));
+} #}}}
+
+sub absolute_urls ($$) { #{{{
+       my $content=shift;
+       my $url=shift;
+
+       $url=~s/[^\/]+$//;
+       
+       $content=~s{<a\s+href="([^"]+)"}{
+               "<a href=\"$url$1\""
+       }ieg;
+       $content=~s{<img\s+src="([^"]+)"}{
+               "<img src=\"$url$1\""
+       }ieg;
+       return $content;
+} #}}}
+
+sub genrss ($$$) { #{{{
+       my $content=shift;
+       my $page=shift;
+       my $mtime=shift;
+
+       my $url="$config{url}/".htmlpage($page);
+       
+       my $template=HTML::Template->new(blind_cache => 1,
+               filename => "$config{templatedir}/rsspage.tmpl");
+       
+       # Regular page gets a feed that is updated every time the
+       # page is changed, so the mtime is encoded in the guid.
+       my @items=(
+               {
+                       itemtitle => pagetitle(basename($page)),
+                       itemguid => "$url?mtime=$mtime",
+                       itemurl => $url,
+                       itempubdate => date_822($mtime),
+                       itemcontent => absolute_urls($content, $url), # rss sucks
+               },
+       );
+       
+       $template->param(
+               title => pagetitle(basename($page)),
+               pageurl => $url,
+               items => \@items,
+       );
+       
+       return $template->output;
+} #}}}
+
 sub check_overwrite ($$) { #{{{
        # Important security check. Make sure to call this before saving
        # any files to the source directory.
@@ -161,13 +224,20 @@ sub render ($) { #{{{
                
                $content=linkify($content, $page);
                $content=htmlize($type, $content);
-               $content=finalize($content, $page,
-                       mtime("$config{srcdir}/$file"));
                
                check_overwrite("$config{destdir}/".htmlpage($page), $page);
-               writefile("$config{destdir}/".htmlpage($page), $content);
+               writefile("$config{destdir}/".htmlpage($page),
+                       genpage($content, $page, mtime("$config{srcdir}/$file")));              
                $oldpagemtime{$page}=time;
                $renderedfiles{$page}=htmlpage($page);
+
+               # TODO: should really add this to renderedfiles and call
+               # check_overwrite, as above, but currently renderedfiles
+               # only supports listing one file per page.
+               if ($config{rss}) {
+                       writefile("$config{destdir}/".rsspage($page),
+                               genrss($content, $page, mtime("$config{srcdir}/$file")));
+               }
        }
        else {
                $links{$file}=[];
index c20da504db7d90e0d1c21e511f78291a4fa06d30..4699f309676b899cae6aa79965673691c7b22e78 100644 (file)
@@ -27,6 +27,13 @@ Currently implemented:
   and is quite smart about converting it to html. The only additional markup
   provided by ikiwiki aside from regular markdown is the [[WikiLink]].
 
+* [[RSS]]
+
+  ikiwiki supports generating RSS (2.0) feed for individual pages. These
+  feeds can be subscribed to, to get an update when a page is changed.
+
+  (Support for proper blogs is also planned.)
+
 * support for other file types
 
   ikiwiki also supports files of any other type, including raw html, text,
index 374093a5e91ce5db6417e196dd765d2b8a64b4c7..b81983080fdd73830bdd2bffc1d2210edebc9339 100644 (file)
@@ -44,4 +44,6 @@ use IkiWiki::Setup::Standard {
        
        # Can anonymous web users edit pages?
        #anonok => 1,
+       # Generate rss feeds for pages?
+       #rss => 1,
 }
index b9744438bd8bfb7817bc288b6100b01149d7fe86..02d01f49c0d4d7ce455d63f8f692ac93a04d0e6a 100644 (file)
@@ -64,6 +64,12 @@ flags such as --verbose can be negated with --no-verbose.
 
   By default, anonymous users cannot edit the wiki.
 
+* --rss, --norss
+
+  If rss is set, along with every html page rendered by ikiwiki, an rss
+  page will also be rendered, to allow users to subscribe to a rss feed of
+  changes to that page.
+
 * --cgi
 
   Enable [[CGI]] mode. In cgi mode ikiwiki runs as a cgi script, and supports editing pages, signing in, registration, and displaying [[RecentChanges]].
diff --git a/ikiwiki b/ikiwiki
index 3540f86675c9d449f41a09b3075b7c17012fd43d..5c708919a9288c460c1094adf367b27e2f8777f8 100755 (executable)
--- a/ikiwiki
+++ b/ikiwiki
@@ -30,6 +30,7 @@ sub getconfig () { #{{{
                        historyurl => '',
                        diffurl => '',
                        anonok => 0,
+                       rss => 0,
                        rebuild => 0,
                        wrapper => undef,
                        wrappermode => undef,
@@ -49,6 +50,7 @@ sub getconfig () { #{{{
                        "wrappermode=i" => \$config{wrappermode},
                        "svn!" => \$config{svn},
                        "anonok!" => \$config{anonok},
+                       "rss!" => \$config{rss},
                        "cgi!" => \$config{cgi},
                        "url=s" => \$config{url},
                        "cgiurl=s" => \$config{cgiurl},
@@ -85,7 +87,10 @@ sub getconfig () { #{{{
 
 sub checkconfig () { #{{{
        if ($config{cgi} && ! length $config{url}) {
-               error("Must specify url to wiki with --url when using --cgi");
+               error("Must specify url to wiki with --url when using --cgi\n");
+       }
+       if ($config{rss} && ! length $config{url}) {
+               error("Must specify url to wiki with --url when using --rss\n");
        }
        
        $config{wikistatedir}="$config{srcdir}/.ikiwiki"
index 1e484056ee6f4f68bf60136df84cee27bf26b0f9..5a7450af7b7e19e69f060c1fbf3733ce0f5b8dca 100644 (file)
 
 <p>
 <!-- from <TMPL_VAR NAME=WIKINAME> -->
-last edited <TMPL_VAR NAME=MTIME>
+Last edited <TMPL_VAR NAME=MTIME>
+<TMPL_IF NAME="RSSURL">
+; <a type="application/rss+xml" href="<TMPL_VAR NAME=RSSURL>">RSS</a>
+</TMPL_IF>
 </p>
 
 </body>
diff --git a/templates/rsspage.tmpl b/templates/rsspage.tmpl
new file mode 100644 (file)
index 0000000..cbfeb54
--- /dev/null
@@ -0,0 +1,21 @@
+<?xml version="1.0"?>
+<rss version="2.0">
+       <channel>
+               <title><TMPL_VAR TITLE ESCAPE=HTML></title>
+               <link><TMPL_VAR PAGEURL></link>
+               <description><TMPL_VAR TITLE ESCAPE=HTML></description>
+               <TMPL_LOOP NAME="ITEMS">
+               <item>
+                       <title><TMPL_VAR ITEMTITLE ESCAPE=HTML></title>
+                       <TMPL_IF NAME="ITEMGUID">
+                       <guid isPermaLink="false"><TMPL_VAR ITEMGUID></guid>
+                       <TMPL_ELSE>
+                       <guid><TMPL_VAR ITEMURL></guid>
+                       </TMPL_IF>
+                       <link><TMPL_VAR ITEMURL></link>
+                       <pubDate><TMPL_VAR ITEMPUBDATE></pubDate>
+                       <description><![CDATA[<TMPL_VAR ITEMCONTENT>]]></description>
+               </item>
+               </TMPL_LOOP>
+       </channel>
+</rss>