X-Git-Url: https://sipb.mit.edu/gitweb.cgi/ikiwiki.git/blobdiff_plain/3d4aa065d6a689a017c98e7ea8b80da0b65ae361..4ff161ba0b4b2fbb027ee2077330c08bd3a38073:/IkiWiki/Plugin/comments.pm diff --git a/IkiWiki/Plugin/comments.pm b/IkiWiki/Plugin/comments.pm index b57735545..33d8ca8e2 100644 --- a/IkiWiki/Plugin/comments.pm +++ b/IkiWiki/Plugin/comments.pm @@ -17,14 +17,14 @@ sub import { #{{{ hook(type => "getsetup", id => 'comments', call => \&getsetup); hook(type => "preprocess", id => 'comments', call => \&preprocess); hook(type => "sessioncgi", id => 'comment', call => \&sessioncgi); - hook(type => "htmlize", id => "_comment", - call => \&IkiWiki::Plugin::mdwn::htmlize); + hook(type => "htmlize", id => "_comment", call => \&htmlize); + hook(type => "pagetemplate", id => "comments", call => \&pagetemplate); IkiWiki::loadplugin("inline"); IkiWiki::loadplugin("mdwn"); } # }}} sub htmlize { # {{{ - eval { use IkiWiki::Plugin::mdwn; }; + eval q{use IkiWiki::Plugin::mdwn}; error($@) if ($@); return IkiWiki::Plugin::mdwn::htmlize(@_) } # }}} @@ -33,23 +33,66 @@ sub getsetup () { #{{{ return plugin => { safe => 1, + rebuild => 1, + }, + # Pages where comments are shown, but new comments are not + # allowed, will show "Comments are closed". + comments_shown_pagespec => { + type => 'pagespec', + example => 'blog/*', + default => '', + description => 'PageSpec for pages where comments will be shown inline', + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 1, + }, + comments_open_pagespec => { + type => 'pagespec', + example => 'blog/* and created_after(close_old_comments)', + default => '', + description => 'PageSpec for pages where new comments can be posted', + link => 'ikiwiki/PageSpec', + safe => 1, + rebuild => 1, + }, + comments_pagename => { + type => 'string', + example => 'comment_', + default => 'comment_', + description => 'Base name for comments, e.g. "comment_" for pages like "sandbox/comment_12"', + safe => 0, # manual page moving will required rebuild => undef, }, + comments_allowdirectives => { + type => 'boolean', + default => 0, + example => 0, + description => 'Allow directives in newly posted comments?', + safe => 1, + rebuild => 0, + }, + comments_commit => { + type => 'boolean', + example => 1, + default => 1, + description => 'commit comments to the VCS', + # old uncommitted comments are likely to cause + # confusion if this is changed + safe => 0, + rebuild => 0, + }, } #}}} # Somewhat based on IkiWiki::Plugin::inline blog posting support sub preprocess (@) { #{{{ my %params=@_; - unless (length $config{cgiurl}) { - error(gettext("[[!comments plugin requires CGI enabled]]")); - } + return ""; my $page = $params{page}; $pagestate{$page}{comments}{comments} = defined $params{closed} ? (not IkiWiki::yesno($params{closed})) : 1; - $pagestate{$page}{comments}{allowhtml} = IkiWiki::yesno($params{allowhtml}); $pagestate{$page}{comments}{allowdirectives} = IkiWiki::yesno($params{allowdirectives}); $pagestate{$page}{comments}{commit} = defined $params{commit} ? IkiWiki::yesno($params{commit}) @@ -71,9 +114,9 @@ sub preprocess (@) { #{{{ debug("page $params{page} => destpage $params{destpage}"); - my $posts = ''; unless (defined $params{inline} && !IkiWiki::yesno($params{inline})) { - eval { use IkiWiki::Plugin::inline; }; + my $posts = ''; + eval q{use IkiWiki::Plugin::inline}; error($@) if ($@); my @args = ( pages => "internal($params{page}/_comment_*)", @@ -91,10 +134,11 @@ sub preprocess (@) { #{{{ push @args, feedshow => $params{feedshow} if defined $params{feedshow}; push @args, timeformat => $params{timeformat} if defined $params{timeformat}; push @args, feedonly => $params{feedonly} if defined $params{feedonly}; - $posts = "\n" . IkiWiki::preprocess_inline(@args); + $posts = IkiWiki::preprocess_inline(@args); + $formtemplate->param("comments" => $posts); } - return $formtemplate->output . $posts; + return $formtemplate->output; } # }}} # FIXME: logic taken from editpage, should be common code? @@ -107,6 +151,7 @@ sub getcgiuser ($) { # {{{ } # }}} # FIXME: logic adapted from recentchanges, should be common code? +# returns (author URL, pretty-printed version) sub linkuser ($) { # {{{ my $user = shift; my $oiduser = eval { IkiWiki::openiduser($user) }; @@ -122,18 +167,6 @@ sub linkuser ($) { # {{{ } } # }}} -# FIXME: taken from IkiWiki::Plugin::editpage, should be common? -sub checksessionexpiry ($$) { # {{{ - my $session = shift; - my $sid = shift; - - if (defined $session->param("name")) { - if (! defined $sid || $sid ne $session->id) { - error(gettext("Your login session has expired.")); - } - } -} # }}} - # Mostly cargo-culted from IkiWiki::plugin::editpage sub sessioncgi ($$) { #{{{ my $cgi=shift; @@ -187,11 +220,9 @@ sub sessioncgi ($$) { #{{{ error(gettext("bad page name")); } - my $allow_directives = $pagestate{$page}{comments}{allowdirectives}; - my $allow_html = $pagestate{$page}{comments}{allowdirectives}; - my $commit_comments = defined $pagestate{$page}{comments}{commit} - ? $pagestate{$page}{comments}{commit} - : 1; + my $allow_directives = $config{comments_allowdirectives}; + my $commit_comments = $config{comments_commit}; + my $comments_pagename = $config{comments_pagename}; # FIXME: is this right? Or should we be using the candidate subpage # (whatever that might mean) as the base URL? @@ -204,27 +235,29 @@ sub sessioncgi ($$) { #{{{ htmllink($page, $page, 'ikiwiki/formatting', noimageinline => 1, linktext => 'FormattingHelp'), - allowhtml => $allow_html, allowdirectives => $allow_directives); + if ($form->submitted eq CANCEL) { + # bounce back to the page they wanted to comment on, and exit. + # CANCEL need not be considered in future + IkiWiki::redirect($cgi, urlto($page, undef, 1)); + exit; + } + if (not exists $pagesources{$page}) { error(sprintf(gettext( "page '%s' doesn't exist, so you can't comment"), $page)); } - if (not $pagestate{$page}{comments}{comments}) { + + if (not pagespec_match($page, $config{comments_open_pagespec}, + location => $page)) { error(sprintf(gettext( - "comments are not enabled on page '%s'"), + "comments on page '%s' are closed"), $page)); } - if ($form->submitted eq CANCEL) { - # bounce back to the page they wanted to comment on, and exit. - # CANCEL need not be considered in future - IkiWiki::redirect($cgi, urlto($page, undef, 1)); - exit; - } - + IkiWiki::checksessionexpiry($session, $cgi->param('sid')); IkiWiki::check_canedit($page . "[postcomment]", $cgi, $session); my ($authorurl, $author) = linkuser(getcgiuser($session)); @@ -232,23 +265,39 @@ sub sessioncgi ($$) { #{{{ my $body = $form->field('body') || ''; $body =~ s/\r\n/\n/g; $body =~ s/\r/\n/g; - $body = "\n" if $body !~ /\n$/; + $body .= "\n" if $body !~ /\n$/; unless ($allow_directives) { # don't allow new-style directives at all - $body =~ s/(^|[^\\])\[\[!/$1\\[[!/g; + $body =~ s/(^|[^\\])\[\[!/$1[[!/g; # don't allow [[ unless it begins an old-style # wikilink, if prefix_directives is off - $body =~ s/(^|[^\\])\[\[(?![^\n\s\]+]\]\])/$1\\[[!/g + $body =~ s/(^|[^\\])\[\[(?![^\n\s\]+]\]\])/$1[[!/g unless $config{prefix_directives}; } - unless ($allow_html) { - $body =~ s/&(\w|#)/&$1/g; - $body =~ s//>/g; - } + # FIXME: check that the wiki is locked right now, because + # if it's not, there are mad race conditions! + + # FIXME: rather a simplistic way to make the comments... + my $i = 0; + my $file; + my $location; + do { + $i++; + $location = "$page/${comments_pagename}${i}"; + } while (-e "$config{srcdir}/$location._comment"); + + my $anchor = "${comments_pagename}${i}"; + + IkiWiki::run_hooks(sanitize => sub { + $body=shift->( + page => $location, + destpage => $location, + content => $body, + ); + }); # In this template, the [[!meta]] directives should stay at the end, # so that they will override anything the user specifies. (For @@ -258,6 +307,8 @@ sub sessioncgi ($$) { #{{{ $content_tmpl->param(authorurl => $authorurl); $content_tmpl->param(subject => $form->field('subject')); $content_tmpl->param(body => $body); + $content_tmpl->param(anchor => "$anchor"); + $content_tmpl->param(permalink => "$baseurl#$anchor"); my $content = $content_tmpl->output; @@ -268,14 +319,11 @@ sub sessioncgi ($$) { #{{{ # - this means that if they do, rocks fall and everyone dies if ($form->submitted eq PREVIEW) { - # $fake is a location that has the same number of slashes - # as the eventual location of this comment. - my $fake = "$page/_comments_hypothetical"; - my $preview = IkiWiki::htmlize($fake, $page, 'mdwn', + my $preview = IkiWiki::htmlize($location, $page, 'mdwn', IkiWiki::linkify($page, $page, IkiWiki::preprocess($page, $page, - IkiWiki::filter($fake, $page, - $content), + IkiWiki::filter($location, + $page, $content), 0, 1))); IkiWiki::run_hooks(format => sub { $preview = shift->(page => $page, @@ -296,24 +344,10 @@ sub sessioncgi ($$) { #{{{ } if ($form->submitted eq POST_COMMENT && $form->validate) { - # Let's get posting. We don't check_canedit here because - # that somewhat defeats the point of this plugin. - - checksessionexpiry($session, $cgi->param('sid')); - - # FIXME: check that the wiki is locked right now, because - # if it's not, there are mad race conditions! - - # FIXME: rather a simplistic way to make the comments... - my $i = 0; - my $file; - do { - $i++; - $file = "$page/_comment_${i}._comment"; - } while (-e "$config{srcdir}/$file"); + my $file = "$location._comment"; # FIXME: could probably do some sort of graceful retry - # if I could be bothered + # on error? Would require significant unwinding though writefile($file, $config{srcdir}, $content); my $conflict; @@ -322,7 +356,9 @@ sub sessioncgi ($$) { #{{{ my $message = gettext("Added a comment"); if (defined $form->field('subject') && length $form->field('subject')) { - $message .= ": ".$form->field('subject'); + $message = sprintf( + gettext("Added a comment: %s"), + $form->field('subject')); } IkiWiki::rcs_add($file); @@ -343,7 +379,7 @@ sub sessioncgi ($$) { #{{{ error($conflict) if defined $conflict; # Bounce back to where we were, but defeat broken caches - my $anticache = "?updated=$page/_comment_$i"; + my $anticache = "?updated=$page/${comments_pagename}${i}"; IkiWiki::redirect($cgi, urlto($page, undef, 1).$anticache); } else { @@ -354,6 +390,61 @@ sub sessioncgi ($$) { #{{{ exit; } #}}} +sub pagetemplate (@) { #{{{ + my %params = @_; + + my $page = $params{page}; + my $template = $params{template}; + + if ($template->query(name => 'comments')) { + my $comments = undef; + + my $comments_pagename = $config{comments_pagename}; + + my $open = 0; + my $shown = pagespec_match($page, + $config{comments_shown_pagespec}, + location => $page); + + if (pagespec_match($page, "*/${comments_pagename}*", + location => $page)) { + $shown = 0; + $open = 0; + } + + if (length $config{cgiurl}) { + $open = pagespec_match($page, + $config{comments_open_pagespec}, + location => $page); + } + + if ($shown) { + eval q{use IkiWiki::Plugin::inline}; + error($@) if $@; + + my @args = ( + pages => "internal($page/${comments_pagename}*)", + template => 'comments_display', + show => 0, + reverse => 'yes', + page => $page, + destpage => $params{destpage}, + ); + $comments = IkiWiki::preprocess_inline(@args); + } + + if (defined $comments && length $comments) { + $template->param(comments => $comments); + } + + if ($open) { + my $commenturl = IkiWiki::cgiurl(do => 'comment', + page => $page); + $template->param(commenturl => $commenturl); + } + } +} # }}} + package IkiWiki::PageSpec; sub match_postcomment ($$;@) {