diff --git a/IkiWiki/CGI.pm b/IkiWiki/CGI.pm index 1d642687b..feed00487 100644 --- a/IkiWiki/CGI.pm +++ b/IkiWiki/CGI.pm @@ -217,7 +217,8 @@ sub cgi_prefs ($$) { #{{{ eval q{use CGI::FormBuilder}; my $form = CGI::FormBuilder->new( title => "preferences", - fields => [qw(do name password confirm_password email locked_pages)], + fields => [qw(do name password confirm_password email + subscriptions locked_pages)], header => 0, method => 'POST', validate => { @@ -242,6 +243,8 @@ sub cgi_prefs ($$) { #{{{ value => $user_name, force => 1); $form->field(name => "password", type => "password"); $form->field(name => "confirm_password", type => "password"); + $form->field(name => "subscriptions", size => 50, + comment => "(".htmllink("", "GlobList", 1).")"); $form->field(name => "locked_pages", size => 50, comment => "(".htmllink("", "GlobList", 1).")"); @@ -252,6 +255,8 @@ sub cgi_prefs ($$) { #{{{ if (! $form->submitted) { $form->field(name => "email", force => 1, value => userinfo_get($user_name, "email")); + $form->field(name => "subscriptions", force => 1, + value => userinfo_get($user_name, "subscriptions")); $form->field(name => "locked_pages", force => 1, value => userinfo_get($user_name, "locked_pages")); } @@ -266,7 +271,7 @@ sub cgi_prefs ($$) { #{{{ return; } elsif ($form->submitted eq "Save Preferences" && $form->validate) { - foreach my $field (qw(password email locked_pages)) { + foreach my $field (qw(password email subscriptions locked_pages)) { if (length $form->field($field)) { userinfo_set($user_name, $field, $form->field($field)) || error("failed to set $field"); } diff --git a/IkiWiki/Rcs/SVN.pm b/IkiWiki/Rcs/SVN.pm index dd74a0577..7d48abb61 100644 --- a/IkiWiki/Rcs/SVN.pm +++ b/IkiWiki/Rcs/SVN.pm @@ -7,6 +7,7 @@ use strict; package IkiWiki; my $svn_log_infoline=qr/^r(\d+)\s+\|\s+([^\s]+)\s+\|\s+(\d+-\d+-\d+\s+\d+:\d+:\d+\s+[-+]?\d+).*/; +my $svn_webcommit=qr/^web commit by (\w+):?(.*)/; sub svn_info ($$) { #{{{ my $field=shift; @@ -134,7 +135,7 @@ sub rcs_recentchanges ($) { #{{{ elsif ($state eq 'body' && /$div/) { my $committype="web"; if (defined $message[0] && - $message[0]->{line}=~/^web commit by (\w+):?(.*)/) { + $message[0]->{line}=~/$svn_webcommit/) { $user="$1"; $message[0]->{line}=$2; } @@ -167,11 +168,12 @@ sub rcs_notify () { #{{{ if (! exists $ENV{REV}) { error("REV is not set, not running from svn post-commit hook, cannot send notifications"); } + my $rev=int(possibly_foolish_untaint($ENV{REV})); my @changed_pages; - foreach my $change (`svnlook changed $config{svnrepo} -r $ENV{REV}`) { - chomp; - if (/^[A-Z]+\s+\Q$config{svnpath}\E\/(.*)/) { + foreach my $change (`svnlook changed $config{svnrepo} -r $rev`) { + chomp $change; + if ($change =~ /^[A-Z]+\s+\Q$config{svnpath}\E\/(.*)/) { push @changed_pages, $1; } } @@ -179,18 +181,45 @@ sub rcs_notify () { #{{{ 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`; + my $diff=`svnlook diff $config{svnrepo} -r $rev --no-diff-deleted`; + + my $user=`svnlook author $config{svnrepo} -r $rev`; + my $message=`svnlook log $config{svnrepo} -r $rev`; + if ($message=~/$svn_webcommit/) { + $user="$1"; + $message=$2; + } + + my $subject="$config{wikiname} update of "; + if (@changed_pages > 2) { + $subject.="$changed_pages[0] $changed_pages[1] etc"; + } + else { + $subject.=join(" ", @changed_pages); + } + $subject.=" by $user"; + + my $template=HTML::Template->new( + filename => "$config{templatedir}/notifymail.tmpl" + ); + $template->param( + wikiname => $config{wikiname}, + diff => $diff, + user => $user, + message => $message, + ); + + eval q{use Mail::Sendmail}; foreach my $email (@email_recipients) { sendmail( To => $email, From => "$config{wikiname} <$config{adminemail}>", - Subject => "$config{wikiname} $ENV{REV} update notification", - Message => $body, + Subject => $subject, + Message => $template->output, ) or error("Failed to send update notification mail"); } } diff --git a/IkiWiki/UserInfo.pm b/IkiWiki/UserInfo.pm index f4e261563..8c27714b8 100644 --- a/IkiWiki/UserInfo.pm +++ b/IkiWiki/UserInfo.pm @@ -70,12 +70,12 @@ 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}; + if (exists $userinfo->{$user}->{subscriptions} && + length $userinfo->{$user}->{subscriptions} && + exists $userinfo->{$user}->{email} && + length $userinfo->{$user}->{email} && + grep { glob_match($_, $userinfo->{$user}->{subscriptions}) } @_) { + push @ret, $userinfo->{$user}->{email}; } } return @ret; diff --git a/IkiWiki/Wrapper.pm b/IkiWiki/Wrapper.pm index 238f71a91..d72368446 100644 --- a/IkiWiki/Wrapper.pm +++ b/IkiWiki/Wrapper.pm @@ -28,7 +28,6 @@ sub gen_wrapper () { #{{{ 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" @@ -36,6 +35,16 @@ sub gen_wrapper () { #{{{ asprintf(&newenviron[i++], "%s=%s", "$var", s); EOF } + if ($config{svn} && $config{notify}) { + # Support running directly as hooks/post-commit by passing + # $2 in REV in the environment. + $envsave.=<<"EOF" + if (argc == 3) + asprintf(&newenviron[i++], "REV=%s", argv[2]); + else if ((s=getenv("REV"))) + asprintf(&newenviron[i++], "%s=%s", "REV", s); +EOF + } $Data::Dumper::Indent=0; # no newlines my $configstring=Data::Dumper->Dump([\%config], ['*config']); @@ -56,7 +65,7 @@ extern char **environ; int main (int argc, char **argv) { /* Sanitize environment. */ char *s; - char *newenviron[$#envsave+4]; + char *newenviron[$#envsave+5]; int i=0; $envsave newenviron[i++]="HOME=$ENV{HOME}"; diff --git a/basewiki/globlist.mdwn b/basewiki/globlist.mdwn index 30bc837ac..5255a3bee 100644 --- a/basewiki/globlist.mdwn +++ b/basewiki/globlist.mdwn @@ -1,5 +1,5 @@ When the wiki stores lists of pages, such as pages that are locked or pages -that you want to be emailed if changed, it uses a GlobList. +whose commit emails you want subscribe to, it uses a GlobList. This is a list of page names, separated by white space. The "glob" bit is that as well as full page names, it can contain glob patterns. "`*`" stands diff --git a/templates/notifymail.tmpl b/templates/notifymail.tmpl new file mode 100644 index 000000000..5a1497a3f --- /dev/null +++ b/templates/notifymail.tmpl @@ -0,0 +1,5 @@ +The following change has been made to +by : + + +