Merge branch 'master' of git://github.com/joeyh/ikiwiki
[ikiwiki] / IkiWiki / Plugin / recentchanges.pm
1 #!/usr/bin/perl
2 package IkiWiki::Plugin::recentchanges;
3
4 use warnings;
5 use strict;
6 use IkiWiki 3.00;
7 use Encode;
8 use HTML::Entities;
9
10 sub import {
11         hook(type => "getsetup", id => "recentchanges", call => \&getsetup);
12         hook(type => "checkconfig", id => "recentchanges", call => \&checkconfig);
13         hook(type => "refresh", id => "recentchanges", call => \&refresh);
14         hook(type => "pagetemplate", id => "recentchanges", call => \&pagetemplate);
15         hook(type => "htmlize", id => "_change", call => \&htmlize);
16         # Load goto to fix up links from recentchanges
17         IkiWiki::loadplugin("goto");
18 }
19
20 sub getsetup () {
21         return
22                 plugin => {
23                         safe => 1,
24                         rebuild => 1,
25                 },
26                 recentchangespage => {
27                         type => "string",
28                         example => "recentchanges",
29                         description => "name of the recentchanges page",
30                         safe => 1,
31                         rebuild => 1,
32                 },
33                 recentchangesnum => {
34                         type => "integer",
35                         example => 100,
36                         description => "number of changes to track",
37                         safe => 1,
38                         rebuild => 0,
39                 },
40 }
41
42 sub checkconfig () {
43         $config{recentchangespage}='recentchanges' unless defined $config{recentchangespage};
44         $config{recentchangesnum}=100 unless defined $config{recentchangesnum};
45 }
46
47 sub refresh ($) {
48         my %seen;
49
50         # add new changes
51         foreach my $change (IkiWiki::rcs_recentchanges($config{recentchangesnum})) {
52                 $seen{store($change, $config{recentchangespage})}=1;
53         }
54         
55         # delete old and excess changes
56         foreach my $page (keys %pagesources) {
57                 if ($pagesources{$page} =~ /\._change$/ && ! $seen{$page}) {
58                         unlink($config{srcdir}.'/'.$pagesources{$page});
59                 }
60         }
61 }
62
63 # Enable the recentchanges link on wiki pages.
64 sub pagetemplate (@) {
65         my %params=@_;
66         my $template=$params{template};
67         my $page=$params{page};
68
69         if (defined $config{recentchangespage} && $config{rcs} &&
70             $page ne $config{recentchangespage} &&
71             $template->query(name => "recentchangesurl")) {
72                 $template->param(recentchangesurl => urlto($config{recentchangespage}, $page));
73                 $template->param(have_actions => 1);
74         }
75 }
76
77 # Pages with extension _change have plain html markup, pass through.
78 sub htmlize (@) {
79         my %params=@_;
80         return $params{content};
81 }
82
83 sub store ($$$) {
84         my $change=shift;
85
86         my $page="$config{recentchangespage}/change_".titlepage($change->{rev});
87
88         # Optimisation to avoid re-writing pages. Assumes commits never
89         # change (or that any changes are not important).
90         return $page if exists $pagesources{$page} && ! $config{rebuild};
91
92         # Limit pages to first 10, and add links to the changed pages.
93         my $is_excess = exists $change->{pages}[10];
94         delete @{$change->{pages}}[10 .. @{$change->{pages}}] if $is_excess;
95         $change->{pages} = [
96                 map {
97                         if (length $config{cgiurl}) {
98                                 $_->{link} = "<a href=\"".
99                                         IkiWiki::cgiurl(
100                                                 do => "goto",
101                                                 page => $_->{page}
102                                         ).
103                                         "\" rel=\"nofollow\">".
104                                         pagetitle($_->{page}).
105                                         "</a>"
106                         }
107                         else {
108                                 $_->{link} = pagetitle($_->{page});
109                         }
110                         $_->{baseurl}="$config{url}/" if length $config{url};
111
112                         $_;
113                 } @{$change->{pages}}
114         ];
115         push @{$change->{pages}}, { link => '...' } if $is_excess;
116
117         # See if the committer is an openid.
118         $change->{author}=$change->{user};
119         my $oiduser=eval { IkiWiki::openiduser($change->{user}) };
120         if (defined $oiduser) {
121                 $change->{authorurl}=$change->{user};
122                 $change->{user}=$oiduser;
123         }
124         elsif (length $config{cgiurl}) {
125                 $change->{authorurl} = IkiWiki::cgiurl(
126                         do => "goto",
127                         page => (length $config{userdir} ? "$config{userdir}/" : "").$change->{author},
128                 );
129         }
130
131         if (ref $change->{message}) {
132                 foreach my $field (@{$change->{message}}) {
133                         if (exists $field->{line}) {
134                                 # escape html
135                                 $field->{line} = encode_entities($field->{line});
136                                 # escape links and preprocessor stuff
137                                 $field->{line} = encode_entities($field->{line}, '\[\]');
138                         }
139                 }
140         }
141
142         # Fill out a template with the change info.
143         my $template=template("change.tmpl", blind_cache => 1);
144         $template->param(
145                 %$change,
146                 commitdate => displaytime($change->{when}, "%X %x"),
147                 wikiname => $config{wikiname},
148         );
149         
150         $template->param(permalink => "$config{url}/$config{recentchangespage}/#change-".titlepage($change->{rev}))
151                 if exists $config{url};
152         
153         IkiWiki::run_hooks(pagetemplate => sub {
154                 shift->(page => $page, destpage => $page,
155                         template => $template, rev => $change->{rev});
156         });
157
158         my $file=$page."._change";
159         writefile($file, $config{srcdir}, $template->output);
160         utime $change->{when}, $change->{when}, "$config{srcdir}/$file";
161
162         return $page;
163 }
164
165 1