Add revamped 'Site and Journal Search' feature.
Patch by mark.
diffs (672 lines):
diff -r eca92edcffa8 -r 111ac3e6b53c bin/upgrading/en.dat
--- a/bin/upgrading/en.dat Sun Oct 11 17:12:18 2009 +0000
+++ b/bin/upgrading/en.dat Tue Oct 13 05:24:02 2009 +0000
@@ -2209,11 +2209,11 @@ menunav.explore.interests=Interests
menunav.explore.directorysearch=Directory Search
-menunav.explore.journalsearch=Journal Search
-
menunav.explore.randomjournal=Random Journal
menunav.explore.randomcommunity=Random Community
+
+menunav.explore.sitesearch=Site and Journal Search
menunav.explore.faq=FAQ
@@ -2449,6 +2449,14 @@ setting.adultcontent.option.self=This jo
setting.adultcontentreason.label=Adult Content Reason
+setting.allowsearchby.label=Allow Search By
+
+setting.allowsearchby.sel.a=Allow everybody to search my journal
+
+setting.allowsearchby.sel.f=Allow people on my access list to search my
journal (default)
+
+setting.allowsearchby.sel.n=Allow nobody else (only me) to search my journal
+
setting.bio.desc|notes=There shouldn't be a description unless the page
specifies one
setting.bio.desc=_none
@@ -2682,6 +2690,12 @@ setting.gender.error.wrongtype=Only pers
setting.gender.error.wrongtype=Only personal or identity journals can have a
gender.
setting.gender.question=What's your gender?
+
+setting.globalsearch.label=Global Search Inclusion
+
+setting.globalsearch.sel.no=No, do not allow my content to be displayed
+
+setting.globalsearch.sel.yes=Yes, display my public content in search results
(default)
setting.graphicpreviews.label=Graphic Previews
diff -r eca92edcffa8 -r 111ac3e6b53c bin/upgrading/proplists.dat
--- a/bin/upgrading/proplists.dat Sun Oct 11 17:12:18 2009 +0000
+++ b/bin/upgrading/proplists.dat Tue Oct 13 05:24:02 2009 +0000
@@ -518,6 +518,14 @@ userproplist.no_mail_alias:
multihomed: 0
prettyname: Disable site e-mail alias
+userproplist.opt_allowsearchby:
+ cldversion: 4
+ datatype: char
+ des: A = everybody, F = access list only, N = nobody (me only).
+ indexed: 0
+ multihomed: 0
+ prettyname: Allow Search By
+
userproplist.opt_bdaymail:
cldversion: 0
datatype: bool
@@ -525,6 +533,14 @@ userproplist.opt_bdaymail:
indexed: 1
multihomed: 0
prettyname: Get Birthday Reminders
+
+userproplist.opt_blockglobalsearch:
+ cldversion: 4
+ datatype: char
+ des: Y: don't allow global search, N: do allow
+ indexed: 0
+ multihomed: 0
+ prettyname: Block Global Search of Content
userproplist.opt_blockrobots:
cldversion: 4
diff -r eca92edcffa8 -r 111ac3e6b53c bin/worker/sphinx-copier
--- a/bin/worker/sphinx-copier Sun Oct 11 17:12:18 2009 +0000
+++ b/bin/worker/sphinx-copier Tue Oct 13 05:24:02 2009 +0000
@@ -103,9 +103,9 @@ sub work {
# already has most of their posts copied and they are just updating one or
two.
foreach my $jitemid ( @copy_jitemids ) {
my $row = $dbfrom->selectrow_hashref(
- qq{SELECT l.journalid, l.jitemid, l.posterid, l.security,
l.eventtime, lt.subject, lt.event
- FROM log2 l INNER JOIN logtext2 lt ON (l.journalid =
lt.journalid AND l.jitemid = lt.jitemid)
- WHERE l.journalid = ? AND l.jitemid = ?},
+ q{SELECT l.journalid, l.jitemid, l.posterid, l.security,
l.allowmask, l.eventtime, lt.subject, lt.event
+ FROM log2 l INNER JOIN logtext2 lt ON (l.journalid =
lt.journalid AND l.jitemid = lt.jitemid)
+ WHERE l.journalid = ? AND l.jitemid = ?},
undef, $u->id, $jitemid
);
die $dbfrom->errstr if $dbfrom->err;
@@ -113,17 +113,25 @@ sub work {
# have to do some more munging
$row->{is_public} = $row->{security} eq 'public' ? 1 : 0;
$row->{edittime} = $db_times->{$jitemid};
+ $row->{allowmask} = join ',', LJ::bit_breakdown( $row->{allowmask} );
+ $row->{allowpublic} = $u->include_in_global_search ? 1 : 0;
# very important, the search engine can't index compressed crap...
foreach ( qw/ subject event / ) {
LJ::text_uncompress( \$row->{$_} );
+
+ # required, we store raw-bytes in our own database but the Sphinx
system expects
+ # things to be proper UTF-8, this does it.
$row->{$_} = Encode::decode( 'utf8', $row->{$_} );
}
# insert
- $dbto->do( 'REPLACE INTO posts_raw (id, journal_id, jitemid,
poster_id, is_public, date_posted, title, data, revtime) ' .
- 'VALUES (NULL, ?, ?, ?, ?, UNIX_TIMESTAMP(?), ?, ?, ?)',
- undef, map { $row->{$_} } qw/ journalid jitemid posterid
is_public eventtime subject event edittime /, );
+ $dbto->do(
+ q{REPLACE INTO posts_raw (id, journal_id, jitemid, poster_id,
is_public, security_bits, allow_global_search, date_posted,
+ title, data, revtime)
+ VALUES (NULL, ?, ?, ?, ?, ?, ?, UNIX_TIMESTAMP(?), ?, ?, ?)},
+ undef, map { $row->{$_} } qw/ journalid jitemid posterid is_public
allowmask allowpublic eventtime subject event edittime /
+ );
die $dbto->errstr if $dbto->err;
# let the viewer know what they missed
diff -r eca92edcffa8 -r 111ac3e6b53c bin/worker/sphinx-search-gm
--- a/bin/worker/sphinx-search-gm Sun Oct 11 17:12:18 2009 +0000
+++ b/bin/worker/sphinx-search-gm Tue Oct 13 05:24:02 2009 +0000
@@ -32,8 +32,10 @@ sub sphinx_search {
my $job = $_[0];
my $args = Storable::thaw( $job->arg ) || {};
- return undef
- unless $args->{userid} && $args->{query};
+ return undef unless $args->{query};
+
+ # a little sanity check, we don't currently allow a global search on
non-public content
+ return undef if $args->{userid} == 0 && $args->{public} != 1;
my $sx = Sphinx::Search->new();
$sx->SetServer( @LJ::SPHINX_SEARCHD );
@@ -41,9 +43,15 @@ sub sphinx_search {
$sx->SetMatchMode( SPH_MATCH_ALL )
->SetSortMode( SPH_SORT_RELEVANCE )
->SetMaxQueryTime( 15_000 )
- ->SetFilter( 'journal_id', [ $args->{userid} ] )
->SetLimits( $args->{offset} || 0, 20 );
+
+ # filter to a journal if we have a userid set; else, filter on
allow_global_search items
+ $sx->SetFilter( 'journal_id', [ $args->{userid} ] )
+ if $args->{userid};
+ $sx->SetFilter( 'allow_global_search', [ 1 ] )
+ unless $args->{userid};
+ # further filter on public items or not
$sx->SetFilter( 'is_public', [ 1 ] )
if $args->{public};
diff -r eca92edcffa8 -r 111ac3e6b53c cgi-bin/DW/Logic/MenuNav.pm
--- a/cgi-bin/DW/Logic/MenuNav.pm Sun Oct 11 17:12:18 2009 +0000
+++ b/cgi-bin/DW/Logic/MenuNav.pm Tue Oct 13 05:24:02 2009 +0000
@@ -201,8 +201,8 @@ sub get_menu_navigation {
},
{
url => "$LJ::SITEROOT/search",
- text => "menunav.explore.journalsearch",
- display => $loggedin_ispaid && @LJ::SPHINX_SEARCHD ? 1 : 0,
+ text => "menunav.explore.sitesearch",
+ display => @LJ::SPHINX_SEARCHD ? 1 : 0,
},
{
url => "$LJ::SITEROOT/random",
diff -r eca92edcffa8 -r 111ac3e6b53c cgi-bin/DW/Logic/UserLinkBar.pm
--- a/cgi-bin/DW/Logic/UserLinkBar.pm Sun Oct 11 17:12:18 2009 +0000
+++ b/cgi-bin/DW/Logic/UserLinkBar.pm Tue Oct 13 05:24:02 2009 +0000
@@ -463,16 +463,13 @@ sub search {
my $u = $self->{u};
my $remote = $self->{remote};
- my $user = $u->user;
# don't show if search is disabled
return undef unless
- @LJ::SPHINX_SEARCHD &&
- ( $u->is_community || ( $u->equals( $remote ) ) ) &&
- $u->is_paid;
+ @LJ::SPHINX_SEARCHD && $u->allow_search_by( $remote );
my $link = {
- url => 'search' . ( $u->is_community ? "?search_user=" . $u->user : ''
),
+ url => 'search?user=' . $u->user,
image => 'search.png',
text_ml => "userlinkbar.search",
title_ml => "userlinkbar.search.title",
diff -r eca92edcffa8 -r 111ac3e6b53c cgi-bin/DW/Setting/AllowSearchBy.pm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cgi-bin/DW/Setting/AllowSearchBy.pm Tue Oct 13 05:24:02 2009 +0000
@@ -0,0 +1,69 @@
+#!/usr/bin/perl
+#
+# DW::Setting::AllowSearchBy
+#
+# Module to set the opt_allowsearchby setting.
+#
+# Authors:
+# Mark Smith <[email protected]>
+#
+# Copyright (c) 2009 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+#
+
+package DW::Setting::AllowSearchBy;
+use base 'LJ::Setting';
+use strict;
+use warnings;
+
+sub should_render {
+ return $_[1] && $_[1]->is_person;
+}
+
+sub label {
+ return $_[0]->ml( 'setting.allowsearchby.label' );
+}
+
+sub option {
+ my ( $class, $u, $errs, $args ) = @_;
+ my $key = $class->pkgkey;
+
+ # the selection values are opposite the text, since the property is an
+ # opt-out property, it basically negates what we're trying to display to
+ # the user ... yes, it's confusing, sorry
+ my $sel = $class->get_arg( $args, "allowsearchby" ) || $u->prop(
'opt_allowsearchby' ) || 'F';
+
+ my $ret .= LJ::html_select(
+ {
+ id => "${key}allowsearchby",
+ name => "${key}allowsearchby",
+ selected => $sel,
+ },
+
+ 'A' => $class->ml( 'setting.allowsearchby.sel.a' ),
+ 'F' => $class->ml( 'setting.allowsearchby.sel.f' ),
+ 'N' => $class->ml( 'setting.allowsearchby.sel.n' ),
+ );
+
+ my $errdiv = $class->errdiv( $errs, 'allowsearchby' );
+ $ret .= "<br />$errdiv" if $errdiv;
+
+ return $ret;
+}
+
+sub save {
+ my ( $class, $u, $args ) = @_;
+
+ # must be defined and Y or N
+ my $val = $class->get_arg( $args, 'allowsearchby' ) || 0;
+ return unless defined $val && $val =~ /^[AFN]$/;
+
+ $u->set_prop( opt_allowsearchby => $val );
+
+ return 1;
+}
+
+1;
diff -r eca92edcffa8 -r 111ac3e6b53c cgi-bin/DW/Setting/GlobalSearch.pm
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/cgi-bin/DW/Setting/GlobalSearch.pm Tue Oct 13 05:24:02 2009 +0000
@@ -0,0 +1,70 @@
+#!/usr/bin/perl
+#
+# DW::Setting::GlobalSearch
+#
+# Module to set the opt_blockglobalsearch setting.
+#
+# Authors:
+# Mark Smith <[email protected]>
+#
+# Copyright (c) 2009 by Dreamwidth Studios, LLC.
+#
+# This program is free software; you may redistribute it and/or modify it under
+# the same terms as Perl itself. For a copy of the license, please reference
+# 'perldoc perlartistic' or 'perldoc perlgpl'.
+#
+
+package DW::Setting::GlobalSearch;
+use base 'LJ::Setting';
+use strict;
+use warnings;
+
+sub should_render {
+ return $_[1] && ( $_[1]->is_person || $_[1]->is_community );
+}
+
+sub label {
+ return $_[0]->ml( 'setting.globalsearch.label' );
+}
+
+sub option {
+ my ( $class, $u, $errs, $args ) = @_;
+ my $key = $class->pkgkey;
+
+ # the selection values are opposite the text, since the property is an
+ # opt-out property, it basically negates what we're trying to display to
+ # the user ... yes, it's confusing, sorry
+ my $sel = $class->get_arg( $args, "globalsearch" );
+ $sel = $u->include_in_global_search ? 'N' : 'Y'
+ unless defined $sel && length $sel;
+
+ my $ret .= LJ::html_select(
+ {
+ id => "${key}globalsearch",
+ name => "${key}globalsearch",
+ selected => $sel,
+ },
+
+ 'N' => $class->ml( 'setting.globalsearch.sel.yes' ),
+ 'Y' => $class->ml( 'setting.globalsearch.sel.no' ),
+ );
+
+ my $errdiv = $class->errdiv( $errs, 'globalsearch' );
+ $ret .= "<br />$errdiv" if $errdiv;
+
+ return $ret;
+}
+
+sub save {
+ my ( $class, $u, $args ) = @_;
+
+ # must be defined and Y or N
+ my $val = $class->get_arg( $args, 'globalsearch' ) || 0;
+ return unless defined $val && $val =~ /^[YN]$/;
+
+ $u->set_prop( opt_blockglobalsearch => $val );
+
+ return 1;
+}
+
+1;
diff -r eca92edcffa8 -r 111ac3e6b53c cgi-bin/LJ/User.pm
--- a/cgi-bin/LJ/User.pm Sun Oct 11 17:12:18 2009 +0000
+++ b/cgi-bin/LJ/User.pm Tue Oct 13 05:24:02 2009 +0000
@@ -1736,6 +1736,31 @@ sub add_to_class {
}
+# 1/0 whether the argument is allowed to search this journal
+sub allow_search_by {
+ my ( $u, $by ) = @_;
+ return 0 unless LJ::isu( $u ) && LJ::isu( $by );
+
+ # the person doing the search has to be an individual
+ return 0 unless $by->is_individual;
+
+ # someone in the equation has to be a paid account
+ return 0 unless $u->is_paid || $by->is_paid;
+
+ # allow searches if this is a community or it's us
+ return 1 if $u->is_community || $u->equals( $by );
+
+ # check the userprop for security access
+ my $whocan = $u->prop( 'opt_allowsearchby' );
+ return 1 if $whocan eq 'A';
+ return 1 if $whocan eq 'F' && $u->trusts( $by );
+ return 1 if $whocan eq 'N' && $u->equals( $by );
+
+ # failing the above, sorry, no search for you
+ return 0;
+}
+
+
sub caps {
my $u = shift;
return $u->{caps};
@@ -1905,6 +1930,27 @@ sub in_class {
sub in_class {
my ($u, $class) = @_;
return LJ::caps_in_group($u->{caps}, $class);
+}
+
+
+# 1/0; whether or not this account should be included in the global search
+# system. this is used by the bin/worker/sphinx-copier mostly.
+sub include_in_global_search {
+ my $u = $_[0];
+
+ # only P/C accounts should be globally searched
+ return 0 unless $u->is_person || $u->is_community;
+
+ # default) check opt_blockglobalsearch and use that if it's defined
+ my $bgs = $u->prop( 'opt_blockglobalsearch' );
+ return $bgs eq 'Y' ? 0 : 1 if defined $bgs && length $bgs;
+
+ # fallback) use their robot blocking value if it's set
+ my $br = $u->prop( 'opt_blockrobots' );
+ return $br ? 0 : 1 if defined $br && length $br;
+
+ # allow search of this user's content
+ return 1;
}
diff -r eca92edcffa8 -r 111ac3e6b53c htdocs/manage/settings/index.bml
--- a/htdocs/manage/settings/index.bml Sun Oct 11 17:12:18 2009 +0000
+++ b/htdocs/manage/settings/index.bml Tue Oct 13 05:24:02 2009 +0000
@@ -118,6 +118,8 @@ body<=
LJ::Setting::Display::BanUsers
DW::Setting::ProfileEmail
DW::Setting::RandomPaidGifts
+ DW::Setting::GlobalSearch
+ DW::Setting::AllowSearchBy
)],
},
history => {
diff -r eca92edcffa8 -r 111ac3e6b53c htdocs/search.bml
--- a/htdocs/search.bml Sun Oct 11 17:12:18 2009 +0000
+++ b/htdocs/search.bml Tue Oct 13 05:24:02 2009 +0000
@@ -33,126 +33,147 @@ body<=
my $remote = LJ::get_remote();
return "<?needlogin?>" unless $remote;
- # okay, now let's make sure the data is valid
- my $su = LJ::load_user( $GET{search_user} || $remote->user );
- return "Invalid search user.\n" unless $su;
- return "You can't search that journal!\n"
- unless $remote->equals( $su ) ||
- $su->is_community;
+ # see what search mode...
+ my $su = LJ::load_user( $POST{mode} || $GET{user} );
+ my $q = LJ::strip_html( LJ::trim( $POST{query} ) );
- # and make sure we're searching a paid account
- return "Sorry, searches are only available for paid accounts.\n"
- unless $su->is_paid;
+ # helper sub for returning the search form
+ my $search_form = sub {
+ my $ret = "<form method='post' action='$LJ::SITEROOT/search'>" .
LJ::form_auth();
- # for later
- my $sulj = $su->ljuser_display;
- my $suu = $su->user;
+ $ret .= LJ::html_check( { type => 'radio', selected => $su ? 0 : 1, id
=> 'm-global', name => 'mode',
+ value => '', label => 'Site Search (Public
Entries)' } );
- # if they posted we might have to do something
- if ( LJ::did_post() ) {
- return "Failauth.\n" unless LJ::check_form_auth();
- # and make sure we got a query
- my $q = LJ::strip_html( LJ::trim( $POST{query} ) );
- return "Query must be shorter than 255 characters, sorry!\n"
- if length( $q ) > 255;
- return "Please enter a search query. <a
href='$LJ::SITEROOT/search'>Search again.</a>\n"
- unless $q;
-
- # if an offset, less than 1000 please
- my $offset = $GET{offset} + 0;
- return "Hey, that offset is nonsensical... :(\n"
- if $offset < 0 || $offset > 1000;
-
- # set a public only flag if this is not your journal
- my $public = ( $remote->equals( $su ) || ( $su->is_community &&
$remote->member_of( $su ) ) ) ? 0 : 1;
-
- # the arguments to the search
- my $args = { userid => $su->id, query => $q, offset => $offset, public
=> $public };
- my $arg = Storable::nfreeze( $args );
-
- # so we know that they're searching something valid, send to gearman
- my $result;
- my $task = Gearman::Task->new(
- 'sphinx_search', \$arg,
- {
- uniq => '-',
- on_complete => sub {
- my $res = $_[0] or return undef;
- $result = Storable::thaw( $$res );
- },
- }
- );
-
- # setup the task set for gearman... really, isn't there a way to make
this
- # simpler? oh well
- my $ts = $gc->new_task_set();
- $ts->add_task( $task );
- $ts->wait( timeout => 20 );
-
- # if we didn't get a result...
- return "Sorry, we were unable to find a result in the time allotted.
This may mean that ".
- "the server is busy or down. Please try your query again
later.\n"
- unless $result;
-
- # if we didn't get any matches...
- return "Sorry, we didn't find any matches for the search
<strong>$q</strong>. We looked for $result->{time} seconds, too!\n"
- if $result->{total} <= 0;
-
- # now we can process the results and do something fascinating!
- my $matches = '';
- foreach my $match ( @{ $result->{matches} } ) {
- my $icon = {
- public => '',
- private => "<img
src='$LJ::IMGPREFIX/silk/entry/private.png'>",
- usemask => "<img
src='$LJ::IMGPREFIX/silk/entry/filtered.png'>",
- access => "<img
src='$LJ::IMGPREFIX/silk/entry/locked.png'>",
- }->{$match->{security}};
-
- my $tags = join( ', ', map { "<strong>" . $match->{tags}->{$_} .
"</strong>" } keys %{ $match->{tags} } );
- $tags = "<br />Tags: $tags"
- if $tags;
-
- my $html = qq(<div class='searchres'>$icon <a
href="$match->{url}">$match->{subject}</a><br />
- <span class='exc'>$match->{excerpt}</span>$tags<br
/>Posted: <strong>$match->{eventtime}</strong><br /><br />
- </div>);
- $matches .= $html;
+ my $tu = $su || $remote;
+ if ( $tu->allow_search_by( $remote ) ) {
+ $ret .= LJ::html_check( { type => 'radio', selected => $su ? 1 :
0, id => 'm-user', name => 'mode',
+ value => $tu->user, label => "Journal
Search: <strong>" . $tu->user . "</strong>", noescape => 1 } );
}
- # build the rest of the search page
- my $ret = "<?p You have searched $sulj... p?>" . $matches;
-
- # put some stats on the output
- my $matchct = scalar( @{ $result->{matches} } );
- my $skip = $offset > 0 ? " (skipped $offset)" : "";
- $ret .= qq(<span class="stats">$matchct results displayed out of
$result->{total} hits total$skip for <strong>$q</strong>.
- $result->{time} seconds.</span>);
-
- if ( $result->{total} > ( $offset + $matchct ) ) {
- my $offsetm = $offset + $matchct;
- my $fa = LJ::form_auth();
- $ret .= qq(<form method="post"
action="$LJ::SITEROOT/search?search_user=$suu&offset=$offsetm">$fa
- <input type="hidden" name="query" value="$q"> <input
type="submit" value="More Results..." />
- </form>);
- }
+ $ret .= '<br /><input type="text" name="query" maxlength="255"
size="60" value="' . LJ::ehtml( $q ) .
+ '"> <input type="submit" value="Search" /></form>';
return $ret;
+ };
+
+ # an error redisplays the form, with an error message
+ my $error = sub {
+ return $search_form->() . "<br /><?p <strong>Error:</strong> $_[0]
p?>";
+ };
+
+ # if no $su, then this is a public search, that's allowed. but if it's a
user,
+ # ensure that it's an account that we CAN search
+ return $error->( "You can't search that journal." )
+ if $su && ! $su->allow_search_by( $remote );
+
+
################################################################################
+
################################################################################
+
+ # give them the form to do a search if they haven't actually posted to us
yet
+ unless ( LJ::did_post() ) {
+ # give them a form to enter their search options
+ return "<?p $LJ::SITENAME content search. Please select where to
search and enter your search terms. p?>" .
+ $search_form->() .
+ '</form><br /> <?p To control who can search your journal, and
whether or not your public ' .
+ 'entries appear in global search results, please adjust your <a
href="' . $LJ::SITEROOT .
+ '/manage/settings/?cat=privacy">account privacy settings</a>.
p?>';
}
- # give them a form to search...
- my $fa = LJ::form_auth();
- return <<EOF;
+
################################################################################
+
################################################################################
-<?p Searching $sulj ... p?>
+ # at this point, they have done a POST, which means they want to search
something
+ return $error->( "Failauth." ) unless LJ::check_form_auth();
-<form method="post" action="$LJ::SITEROOT/search?search_user=$suu">
-$fa
-<input type="text" name="query" maxlength="255" size="60"> <input
type="submit" value="Search!" />
-</form>
+ # and make sure we got a query
+ return $error->( "Query must be shorter than 255 characters, sorry!" )
+ if length( $q ) > 255;
+ return $error->( "Please enter a search query." )
+ unless $q;
-<?p This is a beta search. Things may be slow or broken while we iron out the
kinks
-in the system. If you run into trouble, let us know! p?>
+ # if an offset, less than 1000 please
+ my $offset = $GET{offset} + 0;
+ return $error->( "Hey, that offset is nonsensical... :(" )
+ if $offset < 0 || $offset > 1000;
-EOF
+ # set a public only flag if this is not your journal or a community you
are in
+ my $public = 1;
+ $public = 0 if $su && ( $remote->equals( $su ) || ( $su->is_community &&
$remote->member_of( $su ) ) );
+
+ # the arguments to the search (userid=0 implies global search)
+ my $args = { userid => $su ? $su->id : 0, query => $q, offset => $offset,
public => $public };
+ my $arg = Storable::nfreeze( $args );
+
+ # so we know that they're searching something valid, send to gearman
+ my $result;
+ my $task = Gearman::Task->new(
+ 'sphinx_search', \$arg,
+ {
+ uniq => '-',
+ on_complete => sub {
+ my $res = $_[0] or return undef;
+ $result = Storable::thaw( $$res );
+ },
+ }
+ );
+
+ # setup the task set for gearman... really, isn't there a way to make this
+ # simpler? oh well
+ my $ts = $gc->new_task_set();
+ $ts->add_task( $task );
+ $ts->wait( timeout => 20 );
+
+ # if we didn't get a result...
+ return $error->( "Sorry, we were unable to find a result in the time
allotted. This may mean that ".
+ "the server is busy or down. Please try your query again
later." )
+ unless $result;
+
+ # if we didn't get any matches...
+ return $error->( "Sorry, we didn't find any matches for the search
<strong>$q</strong>. We looked for $result->{time} seconds, too!" )
+ if $result->{total} <= 0;
+
+ # now we can process the results and do something fascinating!
+ my $matches = '<br /><br />';
+ foreach my $match ( @{ $result->{matches} } ) {
+ my $mu = LJ::load_userid( $match->{journal_id} );
+
+ my $icon = {
+ public => '',
+ private => "<img src='$LJ::IMGPREFIX/silk/entry/private.png'>",
+ usemask => "<img
src='$LJ::IMGPREFIX/silk/entry/filtered.png'>",
+ access => "<img src='$LJ::IMGPREFIX/silk/entry/locked.png'>",
+ }->{$match->{security}};
+
+ my $tags = join( ', ', map { "<strong>" . $match->{tags}->{$_} .
"</strong>" } keys %{ $match->{tags} } );
+ $tags = "<br />Tags: $tags"
+ if $tags;
+
+ my $mulj = $mu->ljuser_display;
+ my $html = qq(<div class='searchres'>$mulj: $icon <a
href="$match->{url}">$match->{subject}</a><br />
+ <span class='exc'>$match->{excerpt}</span>$tags<br
/>Posted: <strong>$match->{eventtime}</strong><br /><br />
+ </div>);
+ $matches .= $html;
+ }
+
+ # build the rest of the search page
+ my $ret = $search_form->() . $matches;
+
+ # put some stats on the output
+ my $matchct = scalar( @{ $result->{matches} } );
+ my $skip = $offset > 0 ? " (skipped $offset)" : "";
+ $ret .= qq(<span class="stats">$matchct results displayed out of
$result->{total} hits total$skip for <strong>$q</strong>.
+ $result->{time} seconds.</span>);
+
+ if ( $result->{total} > ( $offset + $matchct ) ) {
+ my $offsetm = $offset + $matchct;
+ $ret .= "<form method='post'
action='$LJ::SITEROOT/search?offset=$offsetm'>" . LJ::form_auth() .
+ "<input type='hidden' name='query' value='" . LJ::ehtml( $q )
. "'>" .
+ "<input type='hidden' name='mode' value='" . ( $su ? $su->user
: '' ) . "'>" .
+ "<input type='submit' value='More Results...' />" .
+ "</form>";
+ }
+
+ return $ret;
}
_code?>
<=body
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog