use warnings;
use strict;
+use IkiWiki::UserInfo;
package IkiWiki;
);
eval q{use Mail::Sendmail};
- my ($fromhost) = $config{cgiurl} =~ m!/([^/]+)!;
sendmail(
To => userinfo_get($user_name, "email"),
- From => "$config{wikiname} admin <".(getpwuid($>))[0]."@".$fromhost.">",
+ From => "$config{wikiname} admin <$config{adminemail}>",
Subject => "$config{wikiname} information",
Message => $template->output,
) or error("Failed to send mail");
if (-d "$config{srcdir}/.svn") {
my $svn_url=svn_info("URL", $config{srcdir});
- # FIXME: currently assumes that the wiki is somewhere
- # under trunk in svn, doesn't support other layouts.
- my ($svn_base)=$svn_url=~m!(/trunk(?:/.*)?)$!;
-
my $div=qr/^--------------------+$/;
my $state='start';
my ($rev, $user, $when, @pages, @message);
$user=$2;
$when=concise(ago(time - str2time($3)));
}
- elsif ($state eq 'header' && /^\s+[A-Z]\s+\Q$svn_base\E\/([^ ]+)(?:$|\s)/) {
+ elsif ($state eq 'header' && /^\s+[A-Z]+\s+\/\Q$config{svnpath}\E\/([^ ]+)(?:$|\s)/) {
my $file=$1;
my $diffurl=$config{diffurl};
$diffurl=~s/\[\[file\]\]/$file/g;
return @ret;
} #}}}
+sub rcs_notify () { #{{{
+ if (! exists $ENV{REV}) {
+ error("REV is not set, not running from svn post-commit hook, cannot send notifications");
+ }
+
+ my @changed_pages;
+ foreach my $change (`svnlook changed $config{svnrepo} -r $ENV{REV}`) {
+ chomp;
+ if (/^[A-Z]+\s+\Q$config{svnpath}\E\/(.*)/) {
+ push @changed_pages, $1;
+ }
+ }
+
+ require IkiWiki::UserInfo;
+ my @email_recipients=page_subscribers(@changed_pages);
+ if (@email_recipients) {
+ eval q{use Mail::Sendmail};
+ # TODO: if a commit spans multiple pages, this will send
+ # subscribers a diff that might contain pages they did not
+ # sign up for. Should separate the diff per page and
+ # reassemble into one mail with just the pages subscribed to.
+ my $body=`LANG=C svnlook diff $config{svnrepo} -r $ENV{REV} --no-diff-deleted`;
+ foreach my $email (@email_recipients) {
+ sendmail(
+ To => $email,
+ From => "$config{wikiname} <$config{adminemail}>",
+ Subject => "$config{wikiname} $ENV{REV} update notification",
+ Message => $body,
+ ) or error("Failed to send update notification mail");
+ }
+ }
+} #}}}
+
sub rcs_getctime () { #{{{
eval q{use Date::Parse};
foreach my $page (keys %pagectime) {
sub rcs_recentchanges ($) {
}
+sub rcs_notify () {
+}
+
sub rcs_getctime () {
error "getctime not implemented";
}
+#!/usr/bin/perl
+
package IkiWiki;
use warnings;
--- /dev/null
+#!/usr/bin/perl
+
+use warnings;
+use strict;
+use Storable;
+
+package IkiWiki;
+
+sub userinfo_retrieve () { #{{{
+ my $userinfo=eval{ Storable::lock_retrieve("$config{wikistatedir}/userdb") };
+ return $userinfo;
+} #}}}
+
+sub userinfo_store ($) { #{{{
+ my $userinfo=shift;
+
+ my $oldmask=umask(077);
+ my $ret=Storable::lock_store($userinfo, "$config{wikistatedir}/userdb");
+ umask($oldmask);
+ return $ret;
+} #}}}
+
+sub userinfo_get ($$) { #{{{
+ my $user=shift;
+ my $field=shift;
+
+ my $userinfo=userinfo_retrieve();
+ if (! defined $userinfo ||
+ ! exists $userinfo->{$user} || ! ref $userinfo->{$user} ||
+ ! exists $userinfo->{$user}->{$field}) {
+ return "";
+ }
+ return $userinfo->{$user}->{$field};
+} #}}}
+
+sub userinfo_set ($$$) { #{{{
+ my $user=shift;
+ my $field=shift;
+ my $value=shift;
+
+ my $userinfo=userinfo_retrieve();
+ if (! defined $userinfo ||
+ ! exists $userinfo->{$user} || ! ref $userinfo->{$user}) {
+ return "";
+ }
+
+ $userinfo->{$user}->{$field}=$value;
+ return userinfo_store($userinfo);
+} #}}}
+
+sub userinfo_setall ($$) { #{{{
+ my $user=shift;
+ my $info=shift;
+
+ my $userinfo=userinfo_retrieve();
+ if (! defined $userinfo) {
+ $userinfo={};
+ }
+ $userinfo->{$user}=$info;
+ return userinfo_store($userinfo);
+} #}}}
+
+sub is_admin ($) { #{{{
+ my $user_name=shift;
+
+ return grep { $_ eq $user_name } @{$config{adminuser}};
+} #}}}
+
+sub page_subscribers (@) { #{{{
+ my @ret;
+ my $userinfo=userinfo_retrieve();
+ foreach my $user (keys %{$userinfo}) {
+ if (exists $user->{subscriptions} &&
+ length $user->{subscriptions} &&
+ exists $user->{email} &&
+ length $user->{email} &&
+ grep { globmatch($_, $user->{subscriptions}) } @_) {
+ push @ret, $user->{email};
+ }
+ }
+ return @ret;
+} #}}}
+
+1
push @envsave, qw{REMOTE_ADDR QUERY_STRING REQUEST_METHOD REQUEST_URI
CONTENT_TYPE CONTENT_LENGTH GATEWAY_INTERFACE
HTTP_COOKIE} if $config{cgi};
+ push @envsave, qw{REV} if $config{svn};
my $envsave="";
foreach my $var (@envsave) {
$envsave.=<<"EOF"
-ikiwiki (0.1) unstable; urgency=low
+ikiwiki (0.2) unstable; urgency=low
* Initial release.
# Change this when some incompatible change is made that requires
# rebuilding all wikis.
-firstcompat=0.1
+firstcompat=0.2
wikilist=/etc/ikiwiki/wikilist
default_pageext => ".mdwn",
cgi => 0,
svn => 1,
+ notify => 0,
url => '',
cgiurl => '',
historyurl => '',
hyperestraier => 0,
wrapper => undef,
wrappermode => undef,
+ svnrepo => undef,
+ svnpath => "trunk",
srcdir => undef,
destdir => undef,
templatedir => "/usr/share/ikiwiki/templates",
underlaydir => "/usr/share/ikiwiki/basewiki",
setup => undef,
adminuser => undef,
+ adminemail => undef,
);
eval q{use Getopt::Long};
"hyperestraier" => \$config{hyperestraier},
"rss!" => \$config{rss},
"cgi!" => \$config{cgi},
+ "notify!" => \$config{notify},
"url=s" => \$config{url},
"cgiurl=s" => \$config{cgiurl},
"historyurl=s" => \$config{historyurl},
"diffurl=s" => \$config{diffurl},
+ "svnrepo" => \$config{svnrepo},
+ "svnpath" => \$config{svnpath},
+ "adminemail=s" => \$config{adminemail},
"exclude=s@" => sub {
$config{wiki_file_prune_regexp}=qr/$config{wiki_file_prune_regexp}|$_[1]/;
},
return $template->output;
}#}}}
-sub userinfo_get ($$) { #{{{
- my $user=shift;
- my $field=shift;
-
- eval q{use Storable};
- my $userdata=eval{ Storable::lock_retrieve("$config{wikistatedir}/userdb") };
- if (! defined $userdata || ! ref $userdata ||
- ! exists $userdata->{$user} || ! ref $userdata->{$user} ||
- ! exists $userdata->{$user}->{$field}) {
- return "";
- }
- return $userdata->{$user}->{$field};
-} #}}}
-
-sub userinfo_set ($$$) { #{{{
- my $user=shift;
- my $field=shift;
- my $value=shift;
-
- eval q{use Storable};
- my $userdata=eval{ Storable::lock_retrieve("$config{wikistatedir}/userdb") };
- if (! defined $userdata || ! ref $userdata ||
- ! exists $userdata->{$user} || ! ref $userdata->{$user}) {
- return "";
- }
-
- $userdata->{$user}->{$field}=$value;
- my $oldmask=umask(077);
- my $ret=Storable::lock_store($userdata, "$config{wikistatedir}/userdb");
- umask($oldmask);
- return $ret;
-} #}}}
-
-sub userinfo_setall ($$) { #{{{
- my $user=shift;
- my $info=shift;
-
- eval q{use Storable};
- my $userdata=eval{ Storable::lock_retrieve("$config{wikistatedir}/userdb") };
- if (! defined $userdata || ! ref $userdata) {
- $userdata={};
- }
- $userdata->{$user}=$info;
- my $oldmask=umask(077);
- my $ret=Storable::lock_store($userdata, "$config{wikistatedir}/userdb");
- umask($oldmask);
- return $ret;
-} #}}}
-
-sub is_admin ($) { #{{{
- my $user_name=shift;
-
- return grep { $_ eq $user_name } @{$config{adminuser}};
-} #}}}
-
sub glob_match ($$) { #{{{
my $page=shift;
my $glob=shift;
loadindex();
require IkiWiki::Render;
rcs_update();
+ rcs_notify() if $config{notify};
rcs_getctime() if $config{getctime};
refresh();
saveindex();