]> sipb.mit.edu Git - ikiwiki.git/blobdiff - IkiWiki/Plugin/comments.pm
comments: render comments/commenturl in page.tmpl
[ikiwiki.git] / IkiWiki / Plugin / comments.pm
index b5773554560cb155d2c576d7f5aaac5787a8cd48..33d8ca8e212aaf4b907c922b6e75cc6897b6b86a 100644 (file)
@@ -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/</&lt;/g;
-               $body =~ s/>/&gt;/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 ($$;@) {