From abb60f10ea9fc6b87fea47e1ad08bc4357edd3cf Mon Sep 17 00:00:00 2001 From: Colin Kuskie Date: Thu, 22 Oct 2009 10:26:12 -0700 Subject: [PATCH] Fix autolinking issues in the wiki. Fixes bug #11086. The query for finding titles returns multiple title for each asset. Guarantee that the latest title wins. Do not escape characters in the hash key, since that creates NEW hash entries, and all keys are quotemeta'ed later anyway. --- docs/changelog/7.x.x.txt | 1 + lib/WebGUI/Asset/Wobject/WikiMaster.pm | 35 +++++++++++++++++--------- 2 files changed, 24 insertions(+), 12 deletions(-) diff --git a/docs/changelog/7.x.x.txt b/docs/changelog/7.x.x.txt index 1aa2417e6..48c02a583 100644 --- a/docs/changelog/7.x.x.txt +++ b/docs/changelog/7.x.x.txt @@ -6,6 +6,7 @@ - fixed #11063: template_attachments - fixed #11002: Matrix shows backend stuff on load - added #10082: Unarchive all collaboration posts + - fixed #11086: bad urls in wiki 7.8.2 - Added scheduled vendor payout workflow activity. (Special thanks to Martin @ Oqapi) diff --git a/lib/WebGUI/Asset/Wobject/WikiMaster.pm b/lib/WebGUI/Asset/Wobject/WikiMaster.pm index 1d4d8829d..de7436c7b 100644 --- a/lib/WebGUI/Asset/Wobject/WikiMaster.pm +++ b/lib/WebGUI/Asset/Wobject/WikiMaster.pm @@ -159,7 +159,7 @@ sub appendSearchBoxVars { #------------------------------------------------------------------- -=head2 autolinkHtml ($html) +=head2 autolinkHtml ($html, [options]) Scan HTML for words and phrases that match wiki titles, and automatically link them to those wiki pages. Returns the modified HTML. @@ -168,6 +168,14 @@ link them to those wiki pages. Returns the modified HTML. The HTML to scan. +=head3 options + +Either a hashref, or a hash of options. + +=head4 skipTitles + +An array reference of titles that should not be autolinked. + =cut sub autolinkHtml { @@ -175,18 +183,21 @@ sub autolinkHtml { my $html = shift; # opts is always the last parameter, and a hash ref my %opts = ref $_[-1] eq 'HASH' ? %{pop @_} : (); - my $skipTitles = $opts{skipTitles} || []; + $opts{skipTitles} ||= []; + + # LC all the skip titles once, for efficiency + my @skipTitles = map { lc $_ } @{ $opts{skipTitles} }; # TODO: ignore caching for now, but maybe do it later. - my %mapping = $self->session->db->buildHash("SELECT LOWER(d.title), d.url FROM asset AS i INNER JOIN assetData AS d ON i.assetId = d.assetId WHERE i.parentId = ? and className='WebGUI::Asset::WikiPage' and i.state='published' and d.status='approved'", [$self->getId]); - foreach my $key (keys %mapping) { - if (grep {lc $_ eq $key} @$skipTitles) { - delete $mapping{$key}; - next; - } - $key =~ s{\(}{\\\(}gxms; # escape parens - $key =~ s{\)}{\\\)}gxms; # escape parens - $mapping{$key} = $self->session->url->gateway($mapping{$key}); - } + # This query returns multiple entries for each asset, so we order by revisionDate and count on the hash to only have the + # latest version. + my %mapping = $self->session->db->buildHash("SELECT LOWER(d.title), d.url FROM asset AS i INNER JOIN assetData AS d ON i.assetId = d.assetId WHERE i.parentId = ? and className='WebGUI::Asset::WikiPage' and i.state='published' and d.status='approved' order by d.revisionDate ASC", [$self->getId]); + TITLE: foreach my $title (keys %mapping) { + my $url = delete $mapping{$title}; + ##isIn short circuits and is faster than grep and/or first + next TITLE if isIn($title, @skipTitles); + $mapping{$title} = $self->session->url->gateway($url); + } + return $html unless %mapping; # sort by length so it prefers matching longer titles my $matchString = join('|', map{quotemeta} sort {length($b) <=> length($a)} keys %mapping);