summaryrefslogtreecommitdiff
path: root/rt/lib/RT/Search/Googleish.pm
diff options
context:
space:
mode:
Diffstat (limited to 'rt/lib/RT/Search/Googleish.pm')
-rw-r--r--rt/lib/RT/Search/Googleish.pm271
1 files changed, 0 insertions, 271 deletions
diff --git a/rt/lib/RT/Search/Googleish.pm b/rt/lib/RT/Search/Googleish.pm
deleted file mode 100644
index a688f582a..000000000
--- a/rt/lib/RT/Search/Googleish.pm
+++ /dev/null
@@ -1,271 +0,0 @@
-# BEGIN BPS TAGGED BLOCK {{{
-#
-# COPYRIGHT:
-#
-# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
-# <sales@bestpractical.com>
-#
-# (Except where explicitly superseded by other copyright notices)
-#
-#
-# LICENSE:
-#
-# This work is made available to you under the terms of Version 2 of
-# the GNU General Public License. A copy of that license should have
-# been provided with this software, but in any event can be snarfed
-# from www.gnu.org.
-#
-# This work is distributed in the hope that it will be useful, but
-# WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-# General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License
-# along with this program; if not, write to the Free Software
-# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-# 02110-1301 or visit their web page on the internet at
-# http://www.gnu.org/licenses/old-licenses/gpl-2.0.html.
-#
-#
-# CONTRIBUTION SUBMISSION POLICY:
-#
-# (The following paragraph is not intended to limit the rights granted
-# to you to modify and distribute this software under the terms of
-# the GNU General Public License and is only of importance to you if
-# you choose to contribute your changes and enhancements to the
-# community by submitting them to Best Practical Solutions, LLC.)
-#
-# By intentionally submitting any modifications, corrections or
-# derivatives to this work, or any other work intended for use with
-# Request Tracker, to Best Practical Solutions, LLC, you confirm that
-# you are the copyright holder for those contributions and you grant
-# Best Practical Solutions, LLC a nonexclusive, worldwide, irrevocable,
-# royalty-free, perpetual, license to use, copy, create derivative
-# works based on those contributions, and sublicense and distribute
-# those contributions and any derivatives thereof.
-#
-# END BPS TAGGED BLOCK }}}
-
-=head1 NAME
-
- RT::Search::Googleish
-
-=head1 SYNOPSIS
-
-=head1 DESCRIPTION
-
-Use the argument passed in as a "Google-style" set of keywords
-
-=head1 METHODS
-
-=cut
-
-package RT::Search::Googleish;
-
-use strict;
-use warnings;
-use base qw(RT::Search);
-
-use Regexp::Common qw/delimited/;
-
-# Only a subset of limit types AND themselves together. "queue:foo
-# queue:bar" is an OR, but "subject:foo subject:bar" is an AND
-our %AND = (
- content => 1,
- subject => 1,
-);
-
-sub _Init {
- my $self = shift;
- my %args = @_;
-
- $self->{'Queues'} = delete( $args{'Queues'} ) || [];
- $self->SUPER::_Init(%args);
-}
-
-sub Describe {
- my $self = shift;
- return ( $self->loc( "Keyword and intuition-based searching", ref $self ) );
-}
-
-sub Prepare {
- my $self = shift;
- my $tql = $self->QueryToSQL( $self->Argument );
-
- $RT::Logger->debug($tql);
-
- $self->TicketsObj->FromSQL($tql);
- return (1);
-}
-
-sub QueryToSQL {
- my $self = shift;
- my $query = shift || $self->Argument;
-
- my %limits;
- $query =~ s/^\s*//;
- while ($query =~ /^\S/) {
- if ($query =~ s/^
- (?:
- (\w+) # A straight word
- (?:\. # With an optional .foo
- ($RE{delimited}{-delim=>q['"]}
- |[\w-]+ # Allow \w + dashes
- ) # Which could be ."foo bar", too
- )?
- )
- : # Followed by a colon
- ($RE{delimited}{-delim=>q['"]}
- |\S+
- ) # And a possibly-quoted foo:"bar baz"
- \s*//ix) {
- my ($type, $extra, $value) = ($1, $2, $3);
- ($value, my ($quoted)) = $self->Unquote($value);
- $extra = $self->Unquote($extra) if defined $extra;
- $self->Dispatch(\%limits, $type, $value, $quoted, $extra);
- } elsif ($query =~ s/^($RE{delimited}{-delim=>q['"]}|\S+)\s*//) {
- # If there's no colon, it's just a word or quoted string
- my($val, $quoted) = $self->Unquote($1);
- $self->Dispatch(\%limits, $self->GuessType($val, $quoted), $val, $quoted);
- }
- }
- $self->Finalize(\%limits);
-
- my @clauses;
- for my $subclause (sort keys %limits) {
- next unless @{$limits{$subclause}};
-
- my $op = $AND{lc $subclause} ? "AND" : "OR";
- push @clauses, "( ".join(" $op ", @{$limits{$subclause}})." )";
- }
-
- return join " AND ", @clauses;
-}
-
-sub Dispatch {
- my $self = shift;
- my ($limits, $type, $contents, $quoted, $extra) = @_;
- $contents =~ s/(['\\])/\\$1/g;
- $extra =~ s/(['\\])/\\$1/g if defined $extra;
-
- my $method = "Handle" . ucfirst(lc($type));
- $method = "HandleDefault" unless $self->can($method);
- my ($key, @tsql) = $self->$method($contents, $quoted, $extra);
- push @{$limits->{$key}}, @tsql;
-}
-
-sub Unquote {
- # Given a word or quoted string, unquote it if it is quoted,
- # removing escaped quotes.
- my $self = shift;
- my ($token) = @_;
- if ($token =~ /^$RE{delimited}{-delim=>q['"]}{-keep}$/) {
- my $quote = $2 || $5;
- my $value = $3 || $6;
- $value =~ s/\\(\\|$quote)/$1/g;
- return wantarray ? ($value, 1) : $value;
- } else {
- return wantarray ? ($token, 0) : $token;
- }
-}
-
-sub Finalize {
- my $self = shift;
- my ($limits) = @_;
-
- # Apply default "active status" limit if we don't have any status
- # limits ourselves, and we're not limited by id
- if (not $limits->{status} and not $limits->{id}
- and RT::Config->Get('OnlySearchActiveTicketsInSimpleSearch', $self->TicketsObj->CurrentUser)) {
- $limits->{status} = [map {s/(['\\])/\\$1/g; "Status = '$_'"} RT::Queue->ActiveStatusArray()];
- }
-
- # Respect the "only search these queues" limit if we didn't
- # specify any queues ourselves
- if (not $limits->{queue} and not $limits->{id}) {
- for my $queue ( @{ $self->{'Queues'} } ) {
- my $QueueObj = RT::Queue->new( $self->TicketsObj->CurrentUser );
- next unless $QueueObj->Load($queue);
- my $name = $QueueObj->Name;
- $name =~ s/(['\\])/\\$1/g;
- push @{$limits->{queue}}, "Queue = '$name'";
- }
- }
-}
-
-our @GUESS = (
- [ 10 => sub { return "subject" if $_[1] } ],
- [ 20 => sub { return "id" if /^#?\d+$/ } ],
- [ 30 => sub { return "requestor" if /\w+@\w+/} ],
- [ 35 => sub { return "domain" if /^@\w+/} ],
- [ 40 => sub {
- return "status" if RT::Queue->new( $_[2] )->IsValidStatus( $_ )
- }],
- [ 40 => sub { return "status" if /^((in)?active|any)$/i } ],
- [ 50 => sub {
- my $q = RT::Queue->new( $_[2] );
- return "queue" if $q->Load($_) and $q->Id and not $q->Disabled
- }],
- [ 60 => sub {
- my $u = RT::User->new( $_[2] );
- return "owner" if $u->Load($_) and $u->Id and $u->Privileged
- }],
- [ 70 => sub { return "owner" if $_ eq "me" } ],
-);
-
-sub GuessType {
- my $self = shift;
- my ($val, $quoted) = @_;
-
- my $cu = $self->TicketsObj->CurrentUser;
- for my $sub (map $_->[1], sort {$a->[0] <=> $b->[0]} @GUESS) {
- local $_ = $val;
- my $ret = $sub->($val, $quoted, $cu);
- return $ret if $ret;
- }
- return "default";
-}
-
-# $_[0] is $self
-# $_[1] is escaped value without surrounding single quotes
-# $_[2] is a boolean of "was quoted by the user?"
-# ensure this is false before you do smart matching like $_[1] eq "me"
-# $_[3] is escaped subkey, if any (see HandleCf)
-sub HandleDefault { return subject => "Subject LIKE '$_[1]'"; }
-sub HandleSubject { return subject => "Subject LIKE '$_[1]'"; }
-sub HandleFulltext { return content => "Content LIKE '$_[1]'"; }
-sub HandleContent { return content => "Content LIKE '$_[1]'"; }
-sub HandleId { $_[1] =~ s/^#//; return id => "Id = $_[1]"; }
-sub HandleStatus {
- if ($_[1] =~ /^active$/i and !$_[2]) {
- return status => map {s/(['\\])/\\$1/g; "Status = '$_'"} RT::Queue->ActiveStatusArray();
- } elsif ($_[1] =~ /^inactive$/i and !$_[2]) {
- return status => map {s/(['\\])/\\$1/g; "Status = '$_'"} RT::Queue->InactiveStatusArray();
- } elsif ($_[1] =~ /^any$/i and !$_[2]) {
- return 'status';
- } else {
- return status => "Status = '$_[1]'";
- }
-}
-sub HandleOwner {
- if (!$_[2] and $_[1] eq "me") {
- return owner => "Owner.id = '__CurrentUser__'";
- }
- elsif (!$_[2] and $_[1] =~ /\w+@\w+/) {
- return owner => "Owner.EmailAddress = '$_[1]'";
- } else {
- return owner => "Owner = '$_[1]'";
- }
-}
-sub HandleWatcher {
- return watcher => (!$_[2] and $_[1] eq "me") ? "Watcher.id = '__CurrentUser__'" : "Watcher = '$_[1]'";
-}
-sub HandleRequestor { return requestor => "Requestor STARTSWITH '$_[1]'"; }
-sub HandleDomain { $_[1] =~ s/^@?/@/; return requestor => "Requestor ENDSWITH '$_[1]'"; }
-sub HandleQueue { return queue => "Queue = '$_[1]'"; }
-sub HandleQ { return queue => "Queue = '$_[1]'"; }
-sub HandleCf { return "cf.$_[3]" => "'CF.{$_[3]}' LIKE '$_[1]'"; }
-
-RT::Base->_ImportOverlays();
-
-1;