X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/4a6ac6b485c7e6e312e42c3c609df693f5e531ec..c42fd7d7580d081f3e3f624fd74219b0435230f6:/IkiWiki/Plugin/comments.pm diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm index 156d71daf..151e839d0 100644 --- a/IkiWiki/Plugin/comments.pm +++ b/IkiWiki/Plugin/comments.pm @@ -9,7 +9,6 @@ use warnings; use strict; use IkiWiki 3.00; use Encode; -use POSIX qw(strftime); use constant PREVIEW => "Preview"; use constant POST_COMMENT => "Post comment"; @@ -21,7 +20,8 @@ my %commentstate; sub import { hook(type => "checkconfig", id => 'comments', call => \&checkconfig); hook(type => "getsetup", id => 'comments', call => \&getsetup); - hook(type => "preprocess", id => 'comment', call => \&preprocess); + hook(type => "preprocess", id => 'comment', call => \&preprocess, + scan => 1); hook(type => "preprocess", id => 'commentmoderation', call => \&preprocess_moderation); # here for backwards compatability with old comments hook(type => "preprocess", id => '_comment', call => \&preprocess); @@ -90,6 +90,15 @@ sub getsetup () { safe => 0, rebuild => 0, }, + comments_allowformats => { + type => 'string', + default => '', + example => 'mdwn txt', + description => 'Restrict formats for comments to (no restriction if empty)', + safe => 1, + rebuild => 0, + }, + } sub checkconfig () { @@ -101,6 +110,8 @@ sub checkconfig () { unless defined $config{comments_closed_pagespec}; $config{comments_pagename} = 'comment_' unless defined $config{comments_pagename}; + $config{comments_allowformats} = '' + unless defined $config{comments_allowformats}; } sub htmlize { @@ -128,12 +139,18 @@ sub safeurl ($) { } } +sub isallowed ($) { + my $format = shift; + return ! $config{comments_allowformats} || $config{comments_allowformats} =~ /\b$format\b/; +} + sub preprocess { my %params = @_; my $page = $params{page}; my $format = $params{format}; - if (defined $format && ! exists $IkiWiki::hooks{htmlize}{$format}) { + if (defined $format && (! exists $IkiWiki::hooks{htmlize}{$format} || + ! isallowed($format))) { error(sprintf(gettext("unsupported page format %s"), $format)); } @@ -143,22 +160,27 @@ sub preprocess { } $content =~ s/\\"/"/g; - if ($config{comments_allowdirectives}) { - $content = IkiWiki::preprocess($page, $params{destpage}, - $content); - } + if (defined wantarray) { + if ($config{comments_allowdirectives}) { + $content = IkiWiki::preprocess($page, $params{destpage}, + $content); + } - # no need to bother with htmlize if it's just HTML - $content = IkiWiki::htmlize($page, $params{destpage}, $format, $content) - if defined $format; + # no need to bother with htmlize if it's just HTML + $content = IkiWiki::htmlize($page, $params{destpage}, $format, $content) + if defined $format; - IkiWiki::run_hooks(sanitize => sub { - $content = shift->( - page => $page, - destpage => $params{destpage}, - content => $content, - ); - }); + IkiWiki::run_hooks(sanitize => sub { + $content = shift->( + page => $page, + destpage => $params{destpage}, + content => $content, + ); + }); + } + else { + IkiWiki::preprocess($page, $params{destpage}, $content, 1); + } # set metadata, possibly overriding [[!meta]] directives from the # comment itself @@ -200,6 +222,7 @@ sub preprocess { $commentstate{$page}{commentip} = $commentip; $commentstate{$page}{commentauthor} = $commentauthor; $commentstate{$page}{commentauthorurl} = $commentauthorurl; + $commentstate{$page}{commentauthoravatar} = $params{avatar}; if (! defined $pagestate{$page}{meta}{author}) { $pagestate{$page}{meta}{author} = $commentauthor; } @@ -216,7 +239,7 @@ sub preprocess { my $url=$params{url}; eval q{use URI::Heuristic}; - if (! $@) { + if (! $@) { $url=URI::Heuristic::uf_uristr($url); } @@ -295,7 +318,8 @@ sub editcomment ($$) { my @buttons = (POST_COMMENT, PREVIEW, CANCEL); my $form = CGI::FormBuilder->new( - fields => [qw{do sid page subject editcontent type author url}], + fields => [qw{do sid page subject editcontent type author + email url subscribe anonsubscribe}], charset => 'utf-8', method => 'POST', required => [qw{editcontent}], @@ -325,7 +349,7 @@ sub editcomment ($$) { my @page_types; if (exists $IkiWiki::hooks{htmlize}) { - foreach my $key (grep { !/^_/ } keys %{$IkiWiki::hooks{htmlize}}) { + foreach my $key (grep { !/^_/ && isallowed($_) } keys %{$IkiWiki::hooks{htmlize}}) { push @page_types, [$key, $IkiWiki::hooks{htmlize}{$key}{longname} || $key]; } } @@ -340,18 +364,35 @@ sub editcomment ($$) { $form->field(name => "type", value => $type, force => 1, type => 'select', options => \@page_types); - $form->tmpl_param(username => $session->param('name')); + my $username=$session->param('name'); + $form->tmpl_param(username => $username); + + $form->field(name => "subscribe", type => 'hidden'); + $form->field(name => "anonsubscribe", type => 'hidden'); + if (IkiWiki::Plugin::notifyemail->can("subscribe")) { + if (defined $username) { + $form->field(name => "subscribe", type => "checkbox", + options => [gettext("email replies to me")]); + } + elsif (IkiWiki::Plugin::passwordauth->can("anonuser")) { + $form->field(name => "anonsubscribe", type => "checkbox", + options => [gettext("email replies to me")]); + } + } if ($config{comments_allowauthor} and ! defined $session->param('name')) { $form->tmpl_param(allowauthor => 1); $form->field(name => 'author', type => 'text', size => '40'); + $form->field(name => 'email', type => 'text', size => '40'); $form->field(name => 'url', type => 'text', size => '40'); } else { $form->tmpl_param(allowauthor => 0); $form->field(name => 'author', type => 'hidden', value => '', force => 1); + $form->field(name => 'email', type => 'hidden', value => '', + force => 1); $form->field(name => 'url', type => 'hidden', value => '', force => 1); } @@ -364,8 +405,8 @@ sub editcomment ($$) { } # The untaint is OK (as in editpage) because we're about to pass - # it to file_pruned anyway - my $page = $form->field('page'); + # it to file_pruned and wiki_file_regexp anyway. + my ($page) = $form->field('page')=~/$config{wiki_file_regexp}/; $page = IkiWiki::possibly_foolish_untaint($page); if (! defined $page || ! length $page || IkiWiki::file_pruned($page)) { @@ -438,6 +479,12 @@ sub editcomment ($$) { } } + my $avatar=getavatar($session->param('name')); + if (defined $avatar && length $avatar) { + $avatar =~ s/"/"/g; + $content .= " avatar=\"$avatar\"\n"; + } + my $subject = $form->field('subject'); if (defined $subject && length $subject) { $subject =~ s/"/"/g; @@ -447,7 +494,7 @@ sub editcomment ($$) { } $content .= " subject=\"$subject\"\n"; - $content .= " date=\"" . decode_utf8(strftime('%Y-%m-%dT%H:%M:%SZ', gmtime)) . "\"\n"; + $content .= " date=\"" . strftime_utf8('%Y-%m-%dT%H:%M:%SZ', gmtime) . "\"\n"; my $editcontent = $form->field('editcontent'); $editcontent="" if ! defined $editcontent; @@ -478,6 +525,20 @@ sub editcomment ($$) { if ($form->submitted eq POST_COMMENT && $form->validate) { IkiWiki::checksessionexpiry($cgi, $session); + + if (IkiWiki::Plugin::notifyemail->can("subscribe")) { + my $subspec="comment($page)"; + if (defined $username && + length $form->field("subscribe")) { + IkiWiki::Plugin::notifyemail::subscribe( + $username, $subspec); + } + elsif (length $form->field("email") && + length $form->field("anonsubscribe")) { + IkiWiki::Plugin::notifyemail::anonsubscribe( + $form->field("email"), $subspec); + } + } $postcomment=1; my $ok=IkiWiki::check_content(content => $form->field('editcontent'), @@ -504,7 +565,7 @@ sub editcomment ($$) { IkiWiki::saveindex(); IkiWiki::printheader($session); - print IkiWiki::misctemplate(gettext(gettext("comment stored for moderation")), + print IkiWiki::cgitemplate($cgi, gettext(gettext("comment stored for moderation")), "

". gettext("Your comment will be posted after moderator review"). "

"); @@ -561,6 +622,32 @@ sub editcomment ($$) { exit; } +sub getavatar ($) { + my $user=shift; + return undef unless defined $user; + + my $avatar; + eval q{use Libravatar::URL}; + if (! $@) { + my $oiduser = eval { IkiWiki::openiduser($user) }; + my $https=defined $config{url} && $config{url}=~/^https:/; + + if (defined $oiduser) { + eval { + $avatar = libravatar_url(openid => $user, https => $https); + } + } + if (! defined $avatar && + (my $email = IkiWiki::userinfo_get($user, 'email'))) { + eval { + $avatar = libravatar_url(email => $email, https => $https); + } + } + } + return $avatar; +} + + sub commentmoderation ($$) { my $cgi=shift; my $session=shift; @@ -595,9 +682,11 @@ sub commentmoderation ($$) { my $page=IkiWiki::dirname($f); my $file="$config{srcdir}/$f"; + my $filedir=$config{srcdir}; if (! -e $file) { # old location $file="$config{wikistatedir}/comments_pending/".$f; + $filedir="$config{wikistatedir}/comments_pending"; } if ($action eq 'Accept') { @@ -612,7 +701,7 @@ sub commentmoderation ($$) { } require IkiWiki::Render; - IkiWiki::prune($file); + IkiWiki::prune($file, $filedir); } } @@ -660,7 +749,7 @@ sub commentmoderation ($$) { IkiWiki::run_hooks(format => sub { $out = shift->(page => "", content => $out); }); - print IkiWiki::misctemplate(gettext("comment moderation"), $out); + print IkiWiki::cgitemplate($cgi, gettext("comment moderation"), $out); exit; } @@ -755,10 +844,8 @@ sub previewcomment ($$$) { sub commentsshown ($) { my $page=shift; - return ! pagespec_match($page, "comment(*)", - location => $page) && - pagespec_match($page, $config{comments_pagespec}, - location => $page); + return pagespec_match($page, $config{comments_pagespec}, + location => $page); } sub commentsopen ($) { @@ -785,7 +872,7 @@ sub pagetemplate (@) { my $comments = undef; if ($shown) { $comments = IkiWiki::preprocess_inline( - pages => "comment($page)", + pages => "comment($page) and !comment($page/*)", template => 'comment', show => 0, reverse => 'yes', @@ -876,6 +963,11 @@ sub pagetemplate (@) { $commentstate{$page}{commentauthorurl}); } + if ($template->query(name => 'commentauthoravatar')) { + $template->param(commentauthoravatar => + $commentstate{$page}{commentauthoravatar}); + } + if ($template->query(name => 'removeurl') && IkiWiki::Plugin::remove->can("check_canremove") && length $config{cgiurl}) {