comments: Add a moderation web interface.

master
Joey Hess 2009-01-25 18:49:57 -05:00
parent 2ecb9e8e79
commit 731fc9e7a2
3 changed files with 193 additions and 27 deletions

View File

@ -134,8 +134,8 @@ sub preprocess {
}
# no need to bother with htmlize if it's just HTML
$content = IkiWiki::htmlize($page, $params{destpage}, $format,
$content) if defined $format;
$content = IkiWiki::htmlize($page, $params{destpage}, $format, $content)
if defined $format;
IkiWiki::run_hooks(sanitize => sub {
$content = shift->(
@ -263,13 +263,23 @@ sub linkcgi ($) {
}
}
# Mostly cargo-culted from IkiWiki::plugin::editpage
sub sessioncgi ($$) {
my $cgi=shift;
my $session=shift;
my $do = $cgi->param('do');
return unless $do eq 'comment';
if ($do eq 'comment') {
editcomment($cgi, $session);
}
elsif ($do eq 'commentmoderation') {
commentmoderation($cgi, $session);
}
}
# Mostly cargo-culted from IkiWiki::plugin::editpage
sub editcomment ($$) {
my $cgi=shift;
my $session=shift;
IkiWiki::decode_cgi_utf8($cgi);
@ -431,29 +441,8 @@ sub sessioncgi ($$) {
# - this means that if they do, rocks fall and everyone dies
if ($form->submitted eq PREVIEW) {
my $preview = IkiWiki::htmlize($location, $page, '_comment',
IkiWiki::linkify($location, $page,
IkiWiki::preprocess($location, $page,
IkiWiki::filter($location,
$page, $content),
0, 1)));
IkiWiki::run_hooks(format => sub {
$preview = shift->(page => $page,
content => $preview);
});
my $template = template("comment.tmpl");
$template->param(content => $preview);
$template->param(title => $form->field('subject'));
$template->param(ctime => displaytime(time));
IkiWiki::run_hooks(pagetemplate => sub {
shift->(page => $location,
destpage => $page,
template => $template);
});
$form->tmpl_param(page_preview => $template->output);
$form->tmpl_param(page_preview =>
previewcomment($content, $location, $page, time));
}
else {
$form->tmpl_param(page_preview => "");
@ -480,6 +469,7 @@ sub sessioncgi ($$) {
my $penddir=$config{wikistatedir}."/comments_pending";
$location=unique_comment_location($page, $penddir);
writefile("$location._comment", $penddir, $content);
IkiWiki::printheader($session);
print IkiWiki::misctemplate(gettext(gettext("comment stored for moderation")),
"<p>".
gettext("Your comment will be posted after moderator review"),
@ -534,6 +524,158 @@ sub sessioncgi ($$) {
exit;
}
sub commentmoderation ($$) {
my $cgi=shift;
my $session=shift;
IkiWiki::needsignin($cgi, $session);
if (! IkiWiki::is_admin($session->param("name"))) {
error(gettext("you are not logged in as an admin"));
}
IkiWiki::decode_cgi_utf8($cgi);
if (defined $cgi->param('sid')) {
IkiWiki::checksessionexpiry($cgi, $session);
my %vars=$cgi->Vars;
my $added=0;
foreach my $id (keys %vars) {
if ($id =~ /(.*)\Q._comment\E$/) {
my $action=$cgi->param($id);
next if $action eq 'Defer';
# Make sure that the id is of a legal
# pending comment before untainting.
my ($f)= $id =~ /$config{wiki_file_regexp}/;
if (! defined $f || ! length $f ||
IkiWiki::file_pruned($f, $config{srcdir})) {
error("illegal file");
}
my $page=IkiWiki::possibly_foolish_untaint(IkiWiki::dirname($1));
my $file="$config{wikistatedir}/comments_pending/".
IkiWiki::possibly_foolish_untaint($id);
if ($action eq 'Accept') {
my $content=eval { readfile($file) };
next if $@; # file vanished since form was displayed
my $dest=unique_comment_location($page, $config{srcdir})."._comment";
writefile($dest, $config{srcdir}, $content);
if ($config{rcs} and $config{comments_commit}) {
IkiWiki::rcs_add($dest);
}
$added++;
}
# This removes empty subdirs, so the
# .ikiwiki/comments_pending dir will
# go away when all are moderated.
require IkiWiki::Render;
IkiWiki::prune($file);
}
}
if ($added) {
my $conflict;
if ($config{rcs} and $config{comments_commit}) {
my $message = gettext("Comment moderation");
IkiWiki::disable_commit_hook();
$conflict=IkiWiki::rcs_commit_staged($message,
$session->param('name'), $ENV{REMOTE_ADDR});
IkiWiki::enable_commit_hook();
IkiWiki::rcs_update();
}
# Now we need a refresh
require IkiWiki::Render;
IkiWiki::refresh();
IkiWiki::saveindex();
error($conflict) if defined $conflict;
}
}
my @comments=map {
my $id=$_;
my $file="$config{wikistatedir}/comments_pending/$id";
my $content=readfile($file);
my $ctime=(stat($file))[10];
{
id => $id,
view => previewcomment($content, $id,
IkiWiki::dirname($_), $ctime),
}
} comments_pending();
my $template=template("commentmoderation.tmpl");
$template->param(
sid => $session->id,
comments => \@comments,
);
IkiWiki::printheader($session);
print IkiWiki::misctemplate(gettext("comment moderation"), $template->output);
exit;
}
sub comments_pending () {
my $dir="$config{wikistatedir}/comments_pending/";
return unless -d $dir;
my @ret;
eval q{use File::Find};
error($@) if $@;
find({
no_chdir => 1,
wanted => sub {
$_=decode_utf8($_);
if (IkiWiki::file_pruned($_, $dir)) {
$File::Find::prune=1;
}
elsif (! -l $_ && ! -d _) {
$File::Find::prune=0;
my ($f)=/$config{wiki_file_regexp}/; # untaint
if (defined $f && $f =~ /\Q._comment\E$/) {
$f=~s/^\Q$dir\E\/?//;
push @ret, $f;
}
}
}
}, $dir);
return @ret;
}
sub previewcomment ($$$) {
my $content=shift;
my $location=shift;
my $page=shift;
my $time=shift;
my $preview = IkiWiki::htmlize($location, $page, '_comment',
IkiWiki::linkify($location, $page,
IkiWiki::preprocess($location, $page,
IkiWiki::filter($location,
$page, $content),
0, 1)));
IkiWiki::run_hooks(format => sub {
$preview = shift->(page => $page,
content => $preview);
});
my $template = template("comment.tmpl");
$template->param(content => $preview);
$template->param(ctime => displaytime($time));
IkiWiki::run_hooks(pagetemplate => sub {
shift->(page => $location,
destpage => $page,
template => $template);
});
return $template->output;
}
sub commentsshown ($) {
my $page=shift;

1
debian/changelog vendored
View File

@ -8,6 +8,7 @@ ikiwiki (3.03) UNRELEASED; urgency=low
config settings.
* comments: If comment content checks fail, store the comment
(in .ikiwiki/comments_pending) for moderator review.
* comments: Add a moderation web interface.
-- Joey Hess <joeyh@debian.org> Sun, 18 Jan 2009 14:50:57 -0500

View File

@ -0,0 +1,23 @@
<TMPL_IF NAME="COMMENTS">
<br />
<form action="<TMPL_VAR CGIURL>" method="post">
<input type="hidden" name="do" value="commentmoderation" />
<input type="hidden" name="sid" value="<TMPL_VAR SID>" />
<TMPL_LOOP NAME="COMMENTS">
<div>
<div>
<TMPL_VAR VIEW>
</div>
<input type="radio" value="Defer" name="<TMPL_VAR ID>" checked>Defer</input>
<input type="radio" value="Accept" name="<TMPL_VAR ID>">Accept</input>
<input type="radio" value="Reject" name="<TMPL_VAR ID>">Reject</input>
</div>
<br />
</TMPL_LOOP>
<input type="submit" value="Submit" />
</form>
<TMPL_ELSE>
<p>
No comments need moderation at this time.
</p>
</TMPL_IF>