summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoey Hess <joey@gnu.kitenet.net>2009-01-25 18:49:57 -0500
committerJoey Hess <joey@gnu.kitenet.net>2009-01-25 18:49:57 -0500
commit731fc9e7a2ce818f0b7069cf0353931ec2dc8b43 (patch)
tree83397a721ef88fcb4d003330e2afccd72795bf90
parent2ecb9e8e797d14dbb65c8ad71afb485d89bb6757 (diff)
comments: Add a moderation web interface.
-rw-r--r--IkiWiki/Plugin/comments.pm196
-rw-r--r--debian/changelog1
-rw-r--r--templates/commentmoderation.tmpl23
3 files changed, 193 insertions, 27 deletions
diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm
index 4d225b90a..388a983f7 100644
--- a/IkiWiki/Plugin/comments.pm
+++ b/IkiWiki/Plugin/comments.pm
@@ -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;
diff --git a/debian/changelog b/debian/changelog
index 002ae12c1..c9ebcd1e9 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -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
diff --git a/templates/commentmoderation.tmpl b/templates/commentmoderation.tmpl
new file mode 100644
index 000000000..3dadb791b
--- /dev/null
+++ b/templates/commentmoderation.tmpl
@@ -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>