Skip to content

Commit

Permalink
Item13627: Added support for $calc token
Browse files Browse the repository at this point in the history
Added support for topic and excludetopic parameters to make search even faster
Added a more robust check for users input for field name - important
  • Loading branch information
KennethLavrsen committed Aug 19, 2015
1 parent 92e7f11 commit 18f2628
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 8 deletions.
1 change: 1 addition & 0 deletions data/System/MultiSearchPlugin.txt
Expand Up @@ -124,6 +124,7 @@ The plugin requires the CPAN library Time::ParseDate. Redhat/Centos users can ru
---++ Plugin Info

| Change History: | <!-- versions below in reverse order -->&nbsp; |
| 1.2 (19 Aug 2015) | Added support for topic and excludetopic parameters to improve performance. Added support for the $calc() token to enable simple calculations within the plugin. Added more user input check of the field names |
| 1.1 (18 Aug 2015) | Better handling when using month as relative time (same date in next month instead of fixed number of seconds).<br />More checks on input values to avoid infinite loops<br />Support of the delay parameter when using MULTISEARCH inside a nested SEARCH or FORMAT |
| 1.0 (17 Aug 2015) | Initial release |
| Dependencies: | %$DEPENDENCIES% |
Expand Down
8 changes: 8 additions & 0 deletions data/System/VarMULTISEARCH.txt
Expand Up @@ -9,6 +9,11 @@ The =%<nop>MULTISEARCH%= variable is handled by the MultiSearchPlugin
| *Parameter* | *Description* | *Default* |
| ="..."= | Unnamed parameter is not used in this macro | |
| =web= | Web in which the search is performed | current web |
| =topic= | Limit search to topics e.g. <br> \
=topic="%WEBPREFSTOPIC%"= <br /> =topic="*Bug"= <br> =topic="MyTopic,YourTopic"= <br> \
A topic, a topic with asterisk wildcards, or a list of topics separated by comma. <br> *Note* this is a list of *topic names* and must *not* include web names. Adding a topic restriction to a search can greatly improve the search performance. | All topics in a web |
| =excludetopic= | Exclude topics from search e.g. <br> \
=excludetopic="Web*"= <br /> =excludetopic="%HOMETOPIC%, <nop>WebChanges"= <br> A topic, a topic with asterisk wildcards, or a list of topics separated by comma.<br> *Note* this is a list of *topic names* and must *not* include web names. | '' |
| =format= | Format of the resulting search for each index value of interval. Typically defines a bullet point or a table row | '' |
| =header= | The header is output just before the formatted search results. Typically used for table headers. See tokens used in headers below | |
| =footer= | The footer is output just after the formatted search results. Typically used for table footers and for summary texts. See tokens used in headers below | |
Expand Down Expand Up @@ -44,6 +49,7 @@ Format tokens that can be used in the header and footer strings:

| *Name:* | *Expands To:* |
| =$ntopics#= | Number of topics found in current web. The total is calculated AFTER all the searches are complete |
| =$calc(...)= | Perform simple calculations of numbers inside the ( ). Only numbers and +, -, *, and / is allowed. $calc is evaluated after $ntopics# so you can write $calc($ntopics1 - $ntopics2) to get the difference between the two results |

* In addition you can use all the standard format tokens with the =header= and =footer= parameters. See below.

Expand Down Expand Up @@ -75,6 +81,8 @@ Format tokens that can be used in the format string.
| =$list#= | The # is the number of the corresponding search number. $list# displays all the values given by the listformat# parameter which are joined together by the string defined by the listseparator# parameter |
| =$nhits#= | The number of topics found by this search number # for this index value or interval. |
| =$ntopics#= | $ntopics# is the total of topics found in search# in the accumulated indexes or intervals shown until now. NOTE! For intervals the $ntopics value starts at the number of topics found having an indexfield value below/before the =indexstart= parameter value |
| =$calc(...)= | Perform simple calculations of numbers inside the ( ). Only numbers and +, -, *, and / is allowed. $calc is evaluated after all other tokens are done so you can write $calc($ntopics1 - $ntopics2) to get the difference between the two results |


* In addition you can use all the standard format tokens with the =format= parameter. See below.

Expand Down
69 changes: 61 additions & 8 deletions lib/Foswiki/Plugins/MultiSearchPlugin.pm
Expand Up @@ -37,7 +37,7 @@ use Time::ParseDate (); # For relative dates
# v1.2.1_001 -> v1.2.2 -> v1.2.2_001 -> v1.2.3
# 1.21_001 -> 1.22 -> 1.22_001 -> 1.23
#
our $VERSION = '1.1';
our $VERSION = '1.2';

# $RELEASE is used in the "Find More Extensions" automation in configure.
# It is a manually maintained string used to identify functionality steps.
Expand All @@ -52,7 +52,7 @@ our $VERSION = '1.1';
# It is preferred to keep this compatible with $VERSION. At some future
# date, Foswiki will deprecate RELEASE and use the VERSION string.
#
our $RELEASE = '18 Aug 2015';
our $RELEASE = '19 Aug 2015';

# One line description of the module
our $SHORTDESCRIPTION =
Expand Down Expand Up @@ -189,6 +189,44 @@ sub _incrementByInterval {

}


# Perform a safe math only calc
# Note that we use eval below so be careful what you open up for
# if below is changed
sub _safeCalc {

my ($text) = @_;
$text = '' unless defined $text;

# We allow only number and -+/.()
$text =~ s/[^\-\+\*\/0-9\.\(\)]+//g;

# Untaint
$text =~ /(.*)/;
$text = $1;

# If nothing survived we return an empty string
return "" unless ($text);

# Capture any errors
local $SIG{__DIE__} = sub { Foswiki::Func::writeDebug( $_[0] ); warn $_[0] };
my $result = eval $text;

# If we capture an error - present it in short form
if ($@) {
$result = $@;
$result =~ s/[\n\r]//g;
$result =~ s/\[[^\]]+.*view.*?\:\s?//;
$result =~ s/\s?at \(eval.*?\)\sline\s?[0-9]*\.?\s?//g;
$result = "ERROR: $result";
}
else {
$result = 0 unless ($result); # logical false is "0"
}
return $result;
}


# _MULTISEARCH
#
# $session= - a reference to the Foswiki session object
Expand Down Expand Up @@ -250,6 +288,8 @@ sub _MULTISEARCH {
my $indexStart = $params->{indexstart};
my $indexEnd = $params->{indexend};
my $indexStep = $params->{indexstep} || "1";
my $includeTopics = $params->{topic} || '';
my $excludeTopics = $params->{excludetopic} || '';

my $resultString = '';

Expand Down Expand Up @@ -307,10 +347,17 @@ sub _MULTISEARCH {

# First we find all topics that matches the search
# Note that this plugin always assumes a query type search
# Note that the includeTopics and excludeTopics are not documented
# in Foswiki::Func::query. I will raise a proposal to document them
my $matches = Foswiki::Func::query( "$multiSearchStrings[$i]", undef,
{ web => $paramWeb, casesensitive => 0, files_without_match => 0,
type => 'query' }
);
{ web => $paramWeb,
casesensitive => 0,
files_without_match => 0,
type => 'query',
includeTopics => $includeTopics,
excludeTopics => $excludeTopics,
}
);

# For each found topic we fetch the value of the indexField
while ( $matches->hasNext ) {
Expand Down Expand Up @@ -430,11 +477,12 @@ sub _MULTISEARCH {
}
else {
# Limit intervals to max 1000 in the none date case
return "Number of intervals should be less than 1000" if ( abs(($indexEnd-$indexStart)/$indexStep) > 1000 )
return "Number of intervals should be less than 1000" if ( abs(($indexEnd-$indexStart)/$indexStep) > 1000 );
return "Cannot have an index step of 0 or negative" if ($indexStep <= 0);
}

return "End value must be larger or later than start value" if ($indexStart >= $indexEnd);
return "Cannot have an index step of 0 or negative" if ($indexStep <= 0);


# This loops each interval
for ( my $ix = $indexStart; $ix < $indexEnd; $ix = _incrementByInterval( $ix, $indexStep, $indexType ) ) {
Expand Down Expand Up @@ -502,8 +550,13 @@ sub _MULTISEARCH {
# decode the usual format tokens of header and footer
$header = Foswiki::Func::decodeFormatTokens($header);
$footer = Foswiki::Func::decodeFormatTokens($footer);

my $finalResult = $header . $resultString . $footer;

# After all is said and done we go through any $calc left
$finalResult =~ s/\$calc\(\s*([\d+\-\/\*\s]*)\s*\)/_safeCalc($1)/ges;

return $header . $resultString . $footer;
return $finalResult;
}

1;
Expand Down

0 comments on commit 18f2628

Please sign in to comment.