moved comments pending moderation

* comments: Comments pending moderation are now stored in the srcdir
  alongside accepted comments, but with a `._comment_pending` extension.
* This allows easier byhand moderation, as the "_pending" need
  only be stripped off and the comment be committed to version control.
* The `comment_pending()` pagespec can be used to match such unmoderated
  comments, which makes it easy to add a feed of them, or a counter
  indicating how many there are.
* Belatedly added a `comment()` pagespec.
master
Joey Hess 2010-05-06 19:19:51 -04:00
parent 71b8d2ad41
commit d9d910f676
8 changed files with 121 additions and 44 deletions

View File

@ -2342,12 +2342,12 @@ sub match_glob ($$;@) {
} }
sub match_internal ($$;@) { sub match_internal ($$;@) {
return match_glob($_[0], $_[1], @_, internal => 1) return match_glob(shift, shift, @_, internal => 1)
} }
sub match_page ($$;@) { sub match_page ($$;@) {
my $page=shift; my $page=shift;
my $match=match_glob($page, $_[1], @_); my $match=match_glob($page, shift, @_);
if ($match && ! defined IkiWiki::pagetype($IkiWiki::pagesources{$page})) { if ($match && ! defined IkiWiki::pagetype($IkiWiki::pagesources{$page})) {
return IkiWiki::FailReason->new("$page is not a page"); return IkiWiki::FailReason->new("$page is not a page");
} }

View File

@ -26,8 +26,11 @@ sub import {
hook(type => "preprocess", id => '_comment', call => \&preprocess); hook(type => "preprocess", id => '_comment', call => \&preprocess);
hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi); hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi);
hook(type => "htmlize", id => "_comment", call => \&htmlize); hook(type => "htmlize", id => "_comment", call => \&htmlize);
hook(type => "htmlize", id => "_comment_pending",
call => \&htmlize_pending);
hook(type => "pagetemplate", id => "comments", call => \&pagetemplate); hook(type => "pagetemplate", id => "comments", call => \&pagetemplate);
hook(type => "formbuilder_setup", id => "comments", call => \&formbuilder_setup); hook(type => "formbuilder_setup", id => "comments",
call => \&formbuilder_setup);
# Load goto to fix up user page links for logged-in commenters # Load goto to fix up user page links for logged-in commenters
IkiWiki::loadplugin("goto"); IkiWiki::loadplugin("goto");
IkiWiki::loadplugin("inline"); IkiWiki::loadplugin("inline");
@ -104,6 +107,14 @@ sub htmlize {
return $params{content}; return $params{content};
} }
sub htmlize_pending {
my %params = @_;
return sprintf(gettext("comment pending %s"),
'<a href="'.
IkiWiki::cgiurl(do => "commentmoderation").'">'.
gettext("moderation").'</a>');
}
# FIXME: copied verbatim from meta # FIXME: copied verbatim from meta
sub safeurl ($) { sub safeurl ($) {
my $url=shift; my $url=shift;
@ -462,9 +473,15 @@ sub editcomment ($$) {
$postcomment=0; $postcomment=0;
if (! $ok) { if (! $ok) {
my $penddir=$config{wikistatedir}."/comments_pending"; $location=unique_comment_location($page, $content, $config{srcdir});
$location=unique_comment_location($page, $content, $penddir); writefile("$location._comment_pending", $config{srcdir}, $content);
writefile("$location._comment", $penddir, $content);
# Refresh so anything that deals with pending
# comments can be updated.
require IkiWiki::Render;
IkiWiki::refresh();
IkiWiki::saveindex();
IkiWiki::printheader($session); IkiWiki::printheader($session);
print IkiWiki::misctemplate(gettext(gettext("comment stored for moderation")), print IkiWiki::misctemplate(gettext(gettext("comment stored for moderation")),
"<p>". "<p>".
@ -540,21 +557,24 @@ sub commentmoderation ($$) {
my %vars=$cgi->Vars; my %vars=$cgi->Vars;
my $added=0; my $added=0;
foreach my $id (keys %vars) { foreach my $id (keys %vars) {
if ($id =~ /(.*)\Q._comment\E$/) { if ($id =~ /(.*)\Q._comment(?:_pending)?\E$/) {
my $action=$cgi->param($id); my $action=$cgi->param($id);
next if $action eq 'Defer' && ! $rejectalldefer; next if $action eq 'Defer' && ! $rejectalldefer;
# Make sure that the id is of a legal # Make sure that the id is of a legal
# pending comment before untainting. # pending comment.
my ($f)= $id =~ /$config{wiki_file_regexp}/; my ($f) = $id =~ /$config{wiki_file_regexp}/;
if (! defined $f || ! length $f || if (! defined $f || ! length $f ||
IkiWiki::file_pruned($f)) { IkiWiki::file_pruned($f)) {
error("illegal file"); error("illegal file");
} }
my $page=IkiWiki::possibly_foolish_untaint(IkiWiki::dirname($1)); my $page=IkiWiki::dirname($f);
my $file="$config{wikistatedir}/comments_pending/". my $file="$config{srcdir}/$f";
IkiWiki::possibly_foolish_untaint($id); if (! -e $file) {
# old location
$file="$config{wikistatedir}/comments_pending/".$f;
}
if ($action eq 'Accept') { if ($action eq 'Accept') {
my $content=eval { readfile($file) }; my $content=eval { readfile($file) };
@ -567,9 +587,6 @@ sub commentmoderation ($$) {
$added++; $added++;
} }
# This removes empty subdirs, so the
# .ikiwiki/comments_pending dir will
# go away when all are moderated.
require IkiWiki::Render; require IkiWiki::Render;
IkiWiki::prune($file); IkiWiki::prune($file);
} }
@ -596,15 +613,14 @@ sub commentmoderation ($$) {
} }
my @comments=map { my @comments=map {
my ($id, $ctime)=@{$_}; my ($id, $dir, $ctime)=@{$_};
my $file="$config{wikistatedir}/comments_pending/$id"; my $content=readfile("$dir/$id");
my $content=readfile($file);
my $preview=previewcomment($content, $id, my $preview=previewcomment($content, $id,
IkiWiki::dirname($_), $ctime); $id, $ctime);
{ {
id => $id, id => $id,
view => $preview, view => $preview,
} }
} sort { $b->[1] <=> $a->[1] } comments_pending(); } sort { $b->[1] <=> $a->[1] } comments_pending();
my $template=template("commentmoderation.tmpl"); my $template=template("commentmoderation.tmpl");
@ -635,26 +651,35 @@ sub formbuilder_setup (@) {
} }
sub comments_pending () { sub comments_pending () {
my $dir="$config{wikistatedir}/comments_pending/";
return unless -d $dir;
my @ret; my @ret;
eval q{use File::Find}; eval q{use File::Find};
error($@) if $@; error($@) if $@;
find({
no_chdir => 1, my $find_comments=sub {
wanted => sub { my $dir=shift;
my $file=decode_utf8($_); my $extension=shift;
$file=~s/^\Q$dir\E\/?//; return unless -d $dir;
return if ! length $file || IkiWiki::file_pruned($file) find({
|| -l $_ || -d _ || $file !~ /\Q._comment\E$/; no_chdir => 1,
my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint wanted => sub {
if (defined $f) { my $file=decode_utf8($_);
my $ctime=(stat($_))[10]; $file=~s/^\Q$dir\E\/?//;
push @ret, [$f, $ctime]; return if ! length $file || IkiWiki::file_pruned($file)
|| -l $_ || -d _ || $file !~ /\Q$extension\E$/;
my ($f) = $file =~ /$config{wiki_file_regexp}/; # untaint
if (defined $f) {
my $ctime=(stat($_))[10];
push @ret, [$f, $dir, $ctime];
}
} }
} }, $dir);
}, $dir); };
$find_comments->($config{srcdir}, "._comment_pending");
# old location
$find_comments->("$config{wikistatedir}/comments_pending/",
"._comment");
return @ret; return @ret;
} }
@ -689,7 +714,7 @@ sub previewcomment ($$$) {
sub commentsshown ($) { sub commentsshown ($) {
my $page=shift; my $page=shift;
return ! pagespec_match($page, "internal(*/$config{comments_pagename}*)", return ! pagespec_match($page, "comment(*)",
location => $page) && location => $page) &&
pagespec_match($page, $config{comments_pagespec}, pagespec_match($page, $config{comments_pagespec},
location => $page); location => $page);
@ -719,7 +744,7 @@ sub pagetemplate (@) {
my $comments = undef; my $comments = undef;
if ($shown) { if ($shown) {
$comments = IkiWiki::preprocess_inline( $comments = IkiWiki::preprocess_inline(
pages => "internal($page/$config{comments_pagename}*)", pages => "comment($page)",
template => 'comment', template => 'comment',
show => 0, show => 0,
reverse => 'yes', reverse => 'yes',
@ -847,7 +872,8 @@ sub unique_comment_location ($$$) {
do { do {
$i++; $i++;
$location = "$page/$config{comments_pagename}${i}_${content_md5}"; $location = "$page/$config{comments_pagename}${i}_${content_md5}";
} while (-e "$dir/$location._comment"); } while (-e "$dir/$location._comment" ||
-e "$dir/$location._comment_pending");
return $location; return $location;
} }
@ -873,7 +899,35 @@ sub match_postcomment ($$;@) {
if (! $postcomment) { if (! $postcomment) {
return IkiWiki::FailReason->new("not posting a comment"); return IkiWiki::FailReason->new("not posting a comment");
} }
return match_glob($page, $glob); return match_glob($page, $glob, @_);
}
sub match_comment ($$;@) {
my $page = shift;
my $glob = shift;
my $match=match_glob($page, "$glob/*", @_);
if ($match) {
my $type=IkiWiki::pagetype($IkiWiki::pagesources{$page});
if ($type ne "_comment") {
return IkiWiki::FailReason->new("$page is not a comment");
}
}
return $match;
}
sub match_comment_pending ($$;@) {
my $page = shift;
my $glob = shift;
my $match=match_glob($page, "$glob/*", @_);
if ($match) {
my $type=IkiWiki::pagetype($IkiWiki::pagesources{$page});
if ($type ne "_comment_pending") {
return IkiWiki::FailReason->new("$page is not a pending comment");
}
}
return $match;
} }
1 1

6
debian/NEWS vendored
View File

@ -1,5 +1,11 @@
ikiwiki (3.20100505) UNRELEASED; urgency=low ikiwiki (3.20100505) UNRELEASED; urgency=low
There is a new "comment()" pagespec, that can be used to match a comment
on a page. It is recommended it be used instead of the old
method of using a pagespec such as "internal(comment_*)" to match
things that looked like comments. The old pagespec will now also match
comments that are held for moderation; likely not what you want.
There is a significant change to the page.tmpl template in this version. There is a significant change to the page.tmpl template in this version.
If you have locally modified versions of that template, you will need If you have locally modified versions of that template, you will need
to update it to contain the following in the HTML <head>: to update it to contain the following in the HTML <head>:

8
debian/changelog vendored
View File

@ -4,6 +4,14 @@ ikiwiki (3.20100505) UNRELEASED; urgency=low
a single template, page.tmpl. a single template, page.tmpl.
* If you have a locally customised page.tmpl, it needs to be updated * If you have a locally customised page.tmpl, it needs to be updated
to set <base> when BASEURL or FORCEBAREURL is set. to set <base> when BASEURL or FORCEBAREURL is set.
* comments: Comments pending moderation are now stored in the srcdir
alongside accepted comments, but with a `._comment_pending` extension.
* This allows easier byhand moderation, as the "_pending" need
only be stripped off and the comment be committed to version control.
* The `comment_pending()` pagespec can be used to match such unmoderated
comments, which makes it easy to add a feed of them, or a counter
indicating how many there are.
* Belatedly added a `comment()` pagespec.
-- Joey Hess <joeyh@debian.org> Wed, 05 May 2010 18:07:29 -0400 -- Joey Hess <joeyh@debian.org> Wed, 05 May 2010 18:07:29 -0400

View File

@ -51,6 +51,8 @@ Some more elaborate limits can be added to what matches using these functions:
wiki admins. wiki admins.
* "`ip(address)`" - tests whether a modification is being made from the * "`ip(address)`" - tests whether a modification is being made from the
specified IP address. specified IP address.
* "`comment(glob)`" - matches comments to a page matching the glob.
* "`comment_pending(glob)`" - matches unmoderated, pending comments.
* "`postcomment(glob)`" - matches only when comments are being * "`postcomment(glob)`" - matches only when comments are being
posted to a page matching the specified glob posted to a page matching the specified glob

View File

@ -49,5 +49,5 @@ held for moderation. (Or with the [[moderatedcomments]] plugin, all
comments will be held.) Wiki admins can access the comment moderation queue comments will be held.) Wiki admins can access the comment moderation queue
via a button on their Preferences page. via a button on their Preferences page.
The comments are stored in `.ikiwiki/comments_pending/`, and can be The unmoderated comments are stored in the `srcdir` with a filename ending
deleted, or moved into the wiki's srcdir to be posted. in "._comment_pending". They are not checked into revision control.

View File

@ -3,8 +3,15 @@ blog can have comments added to them. Pages with comments even have special
feeds that can be used to subscribe to those comments. But you'd like to feeds that can be used to subscribe to those comments. But you'd like to
add a feed that contains all the comments posted to any page. Here's how: add a feed that contains all the comments posted to any page. Here's how:
\[[!inline pages="internal(*/comment_*)" template=comment]] \[[!inline pages="comment(*)" template=comment]]
The special [[ikiwiki/PageSpec]] matches all comments. The The special [[ikiwiki/PageSpec]] matches all comments. The
[[template|templates]] causes the comments to be displayed formatted [[template|templates]] causes the comments to be displayed formatted
nicely. nicely.
---
It's also possible to make a feed of comments that are held pending
moderation.
\[[!inline pages="comment_pending(*)" template=comment]]

View File

@ -1,5 +1,5 @@
Name: ikiwiki Name: ikiwiki
Version: 3.20100504 Version: 3.20100505
Release: 1%{?dist} Release: 1%{?dist}
Summary: A wiki compiler Summary: A wiki compiler