]> git.ipfire.org Git - thirdparty/bugzilla.git/commitdiff
Bug 364254: Add hook to Bugzilla::Template::quoteUrls
authormkanat%bugzilla.org <>
Wed, 30 Sep 2009 23:42:49 +0000 (23:42 +0000)
committermkanat%bugzilla.org <>
Wed, 30 Sep 2009 23:42:49 +0000 (23:42 +0000)
Patch by Max Kanat-Alexander <mkanat@bugzilla.org> r=dkl, a=mkanat

Bugzilla/Hook.pm
Bugzilla/Template.pm
extensions/example/code/bug-format_comment.pl [new file with mode: 0644]
extensions/example/lib/Bugzilla/ExampleHook.pm [new file with mode: 0644]
template/en/default/bug/comments.html.tmpl
template/en/default/bug/edit.html.tmpl

index 42f3583c5c6dd8d9804be890c13a07afa88232cb..2cd99c3e7cdbc09132ba791c99c30e2127575f67 100644 (file)
@@ -313,6 +313,71 @@ your column name(s) onto the array.
 
 =back
 
+=head2 bug-format_comment
+
+Allows you to do custom parsing on comments before they are displayed. You do
+this by returning two regular expressions: one that matches the section you
+want to replace, and then another that says what you want to replace that
+match with.
+
+The matching and replacement will be run with the C</g> switch on the regex.
+
+Params:
+
+=over
+
+=item C<regexes>
+
+An arrayref of hashrefs.
+
+You should push a hashref containing two keys (C<match> and C<replace>)
+in to this array. C<match> is the regular expression that matches the
+text you want to replace, C<replace> is what you want to replace that
+text with. (This gets passed into a regular expression like 
+C<s/$match/$replace/>.)
+
+Instead of specifying a regular expression for C<replace> you can also
+return a coderef (a reference to a subroutine). If you want to use
+backreferences (using C<$1>, C<$2>, etc. in your C<replace>), you have to use
+this method--it won't work if you specify C<$1>, C<$2> in a regular expression
+for C<replace>. Your subroutine will get a hashref as its only argument. This
+hashref contains a single key, C<matches>. C<matches> is an arrayref that
+contains C<$1>, C<$2>, C<$3>, etc. in order, up to C<$10>. Your subroutine
+should return what you want to replace the full C<match> with. (See the code
+example for this hook if you want to see how this actually all works in code.
+It's simpler than it sounds.)
+
+B<You are responsible for HTML-escaping your returned data.> Failing to
+do so could open a security hole in Bugzilla.
+
+=item C<text>
+
+A B<reference> to the exact text that you are parsing.
+
+Generally you should not modify this yourself. Instead you should be 
+returning regular expressions using the C<regexes> array.
+
+The text has already been word-wrapped, but has not been parsed in any way
+otherwise. (So, for example, it is not HTML-escaped. You get "&", not 
+"&amp;".)
+
+=item C<bug>
+
+The L<Bugzilla::Bug> object that this comment is on. Sometimes this is
+C<undef>, meaning that we are parsing text that is not on a bug.
+
+=item C<comment>
+
+A hashref representing the comment you are about to parse, including
+all of the fields that comments contain when they are returned by
+by L<Bugzilla::Bug/longdescs>.
+
+Sometimes this is C<undef>, meaning that we are parsing text that is
+not a bug comment (but could still be some other part of a bug, like
+the summary line).
+
+=back
+
 =head2 buglist-columns
 
 This happens in buglist.cgi after the standard columns have been defined and
index bea1639f32c00a0633ec51d32a3c25219e2d5a68..f94cb2e3805b642d9524c69a476096b5461acccb 100644 (file)
@@ -140,7 +140,7 @@ sub get_format {
 # If you want to modify this routine, read the comments carefully
 
 sub quoteUrls {
-    my ($text, $curr_bugid, $already_wrapped) = (@_);
+    my ($text, $bug, $comment) = (@_);
     return $text unless $text;
 
     # We use /g for speed, but uris can have other things inside them
@@ -157,7 +157,8 @@ sub quoteUrls {
 
     # If the comment is already wrapped, we should ignore newlines when
     # looking for matching regexps. Else we should take them into account.
-    my $s = $already_wrapped ? qr/\s/ : qr/[[:blank:]]/;
+    my $s = ($comment && $comment->{already_wrapped}) 
+            ? qr/\s/ : qr/[[:blank:]]/;
 
     # However, note that adding the title (for buglinks) can affect things
     # In particular, attachment matches go before bug titles, so that titles
@@ -172,6 +173,26 @@ sub quoteUrls {
     my $count = 0;
     my $tmp;
 
+    my @hook_regexes;
+    Bugzilla::Hook::process('bug-format_comment',
+        { text => \$text, bug => $bug, regexes => \@hook_regexes,
+          comment => $comment });
+
+    foreach my $re (@hook_regexes) {
+        my ($match, $replace) = @$re{qw(match replace)};
+        if (ref($replace) eq 'CODE') {
+            $text =~ s/$match/($things[$count++] = $replace->({matches => [
+                                                               $1, $2, $3, $4,
+                                                               $5, $6, $7, $8, 
+                                                               $9, $10]}))
+                               && ("\0\0" . ($count-1) . "\0\0")/egx;
+        }
+        else {
+            $text =~ s/$match/($things[$count++] = $replace) 
+                              && ("\0\0" . ($count-1) . "\0\0")/egx;
+        }
+    }
+
     # Provide tooltips for full bug links (Bug 74355)
     my $urlbase_re = '(' . join('|',
         map { qr/$_/ } grep($_, Bugzilla->params->{'urlbase'}, 
@@ -219,7 +240,7 @@ sub quoteUrls {
               ~egmxi;
 
     # Current bug ID this comment belongs to
-    my $current_bugurl = $curr_bugid ? "show_bug.cgi?id=$curr_bugid" : "";
+    my $current_bugurl = $bug ? ("show_bug.cgi?id=" . $bug->id) : "";
 
     # This handles bug a, comment b type stuff. Because we're using /g
     # we have to do this in one pattern, and so this is semi-messy.
@@ -541,10 +562,10 @@ sub create {
             css_class_quote => \&Bugzilla::Util::css_class_quote ,
 
             quoteUrls => [ sub {
-                               my ($context, $bug, $already_wrapped) = @_;
+                               my ($context, $bug, $comment) = @_;
                                return sub {
                                    my $text = shift;
-                                   return quoteUrls($text, $bug, $already_wrapped);
+                                   return quoteUrls($text, $bug, $comment);
                                };
                            },
                            1
diff --git a/extensions/example/code/bug-format_comment.pl b/extensions/example/code/bug-format_comment.pl
new file mode 100644 (file)
index 0000000..c11e8ca
--- /dev/null
@@ -0,0 +1,45 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Example Plugin.
+#
+# The Initial Developer of the Original Code is Canonical Ltd.
+# Portions created by Canonical Ltd. are Copyright (C) 2009
+# Canonical Ltd. All Rights Reserved.
+#
+# Contributor(s):
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+
+use strict;
+use warnings;
+use Bugzilla;
+use Bugzilla::ExampleHook qw(replace_bar);
+
+# This replaces every occurrence of the word "foo" with the word
+# "bar"
+
+my $regexes = Bugzilla->hook_args->{'regexes'};
+push(@$regexes, { match => qr/\bfoo\b/, replace => 'bar' });
+
+# And this links every occurrence of the word "bar" to example.com,
+# but it won't affect "foo"s that have already been turned into "bar"
+# above (because each regex is run in order, and later regexes don't modify
+# earlier matches, due to some cleverness in Bugzilla's internals).
+#
+# For example, the phrase "foo bar" would become:
+# bar <a href="http://example.com/bar">bar</a>
+#
+# See lib/Bugzilla/ExampleHook.pm in this extension for the code of 
+# "replace_bar".
+my $bar_match = qr/\b(bar)\b/;
+push(@$regexes, { match => $bar_match, replace => \&replace_bar });
diff --git a/extensions/example/lib/Bugzilla/ExampleHook.pm b/extensions/example/lib/Bugzilla/ExampleHook.pm
new file mode 100644 (file)
index 0000000..6452e8f
--- /dev/null
@@ -0,0 +1,43 @@
+# -*- Mode: perl; indent-tabs-mode: nil -*-
+#
+# The contents of this file are subject to the Mozilla Public
+# License Version 1.1 (the "License"); you may not use this file
+# except in compliance with the License. You may obtain a copy of
+# the License at http://www.mozilla.org/MPL/
+#
+# Software distributed under the License is distributed on an "AS
+# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
+# implied. See the License for the specific language governing
+# rights and limitations under the License.
+#
+# The Original Code is the Bugzilla Example Plugin.
+#
+# The Initial Developer of the Original Code is Everything Solved, Inc.
+# Portions created by the Initial Developer are Copyright (C) 2009 the
+# Initial Developer. All Rights Reserved.
+#
+# Contributor(s): 
+#   Max Kanat-Alexander <mkanat@bugzilla.org>
+
+package Bugzilla::ExampleHook;
+use strict;
+use base qw(Exporter);
+our @EXPORT_OK = qw(
+    replace_bar
+);
+
+use Bugzilla::Util qw(html_quote);
+
+# Used by bug-format_comment--see its code for an explanation.
+sub replace_bar {
+    my $params = shift;
+    # $match is the first parentheses match in the $bar_match regex 
+    # in bug-format_comment.pl. We get up to 10 regex matches as 
+    # arguments to this function.
+    my $match = $params->{matches}->[0];
+    # Remember, you have to HTML-escape any data that you are returning!
+    $match = html_quote($match);
+    return qq{<a href="http://example.com/">$match</a>};
+};
+
+1;
index 177c6f985c66e6b5d6431413550a06aa359571ae..2f9eeebf65f913300a97c6b283c41e1ae16127cc 100644 (file)
 [% END %]
 <pre class="bz_comment_text" 
      [% ' id="comment_text_' _ count _ '"' IF mode == "edit" %]>
-  [%- wrapped_comment FILTER quoteUrls(bug.bug_id, comment.already_wrapped) -%]
+  [%- wrapped_comment FILTER quoteUrls(bug, comment) -%]
 </pre>
     </div>
   [% END %]
index e050ee64c24541245a7c423deb59fd38239c604b..d8a7fa4d759edcfb2b72de986fc9567d8a013451 100644 (file)
           (<span id="alias_nonedit_display">[% bug.alias FILTER html %]</span>) 
         [% END %]
       [% END %]
-      <span id="short_desc_nonedit_display">[% bug.short_desc FILTER quoteUrls(bug.bug_id) %]</span>
+      <span id="short_desc_nonedit_display">[% bug.short_desc FILTER quoteUrls(bug) %]</span>
       [% IF bug.check_can_change_field('short_desc', 0, 1) || 
             bug.check_can_change_field('alias', 0, 1)  %]
         <small class="editme">(<a href="#" id="editme_action">edit</a>)</small>