504 lines
18 KiB
Perl
504 lines
18 KiB
Perl
|
|
#!/usr/bin/perl
|
||
|
|
#
|
||
|
|
# DW::Controller::Search::Interests
|
||
|
|
#
|
||
|
|
# Interest search, based on code from LiveJournal.
|
||
|
|
#
|
||
|
|
# Authors:
|
||
|
|
# Jen Griffin <kareila@livejournal.com>
|
||
|
|
#
|
||
|
|
# Copyright (c) 2010 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::Controller::Search::Interests;
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
use warnings;
|
||
|
|
|
||
|
|
use DW::Routing;
|
||
|
|
use DW::Template;
|
||
|
|
use DW::Controller;
|
||
|
|
|
||
|
|
use LJ::Global::Constants;
|
||
|
|
use LJ::Stats;
|
||
|
|
|
||
|
|
DW::Routing->register_string( '/interests', \&interest_handler, app => 1 );
|
||
|
|
|
||
|
|
sub interest_handler {
|
||
|
|
my $r = DW::Request->get;
|
||
|
|
my $did_post = $r->did_post;
|
||
|
|
my $args = $did_post ? $r->post_args : $r->get_args;
|
||
|
|
return error_ml('bml.badinput.body1') unless LJ::text_in($args);
|
||
|
|
return error_ml('error.invalidform')
|
||
|
|
if $did_post && !LJ::check_form_auth( $args->{lj_form_auth} );
|
||
|
|
|
||
|
|
# do mode logic first, to save typing later
|
||
|
|
my $mode = '';
|
||
|
|
$mode = 'int' if $args->{int} || $args->{intid};
|
||
|
|
$mode = 'popular' if $args->{view} && $args->{view} eq "popular";
|
||
|
|
if ( $args->{mode} ) {
|
||
|
|
$mode = 'add' if $args->{mode} eq "add" && $args->{intid};
|
||
|
|
$mode = 'addnew' if $args->{mode} eq "addnew" && $args->{keyword};
|
||
|
|
$mode = 'findsim_do' if !$did_post && $args->{mode} eq "findsim_do";
|
||
|
|
$mode = 'enmasse' if !$did_post && $args->{mode} eq "enmasse";
|
||
|
|
$mode = 'enmasse_do' if $did_post && $args->{mode} eq "enmasse_do";
|
||
|
|
}
|
||
|
|
|
||
|
|
# check whether authentication is needed or authas is allowed
|
||
|
|
# default is to allow anonymous users, except for certain modes
|
||
|
|
my $anon = ( $mode eq "add" || $mode eq "addnew" ) ? 0 : 1;
|
||
|
|
my $authas = 0;
|
||
|
|
( $anon, $authas ) = ( 0, 1 )
|
||
|
|
if $mode eq ( $did_post ? "enmasse_do" : "enmasse" );
|
||
|
|
|
||
|
|
my ( $ok, $rv ) = controller( anonymous => $anon, authas => $authas );
|
||
|
|
return $rv unless $ok;
|
||
|
|
|
||
|
|
my $remote = $rv->{remote};
|
||
|
|
my $maxinterests = $remote ? $remote->count_max_interests : 0;
|
||
|
|
$rv->{can_use_popular} = LJ::is_enabled('interests-popular');
|
||
|
|
$rv->{can_use_findsim} =
|
||
|
|
LJ::is_enabled('interests-findsim')
|
||
|
|
&& $remote
|
||
|
|
&& $remote->can_find_similar;
|
||
|
|
|
||
|
|
# now do argument checking and database work for each mode
|
||
|
|
|
||
|
|
if ( $mode eq 'popular' ) {
|
||
|
|
return error_ml('interests.popular.disabled')
|
||
|
|
unless $rv->{can_use_popular};
|
||
|
|
$rv->{no_text_mode} = 1
|
||
|
|
unless $args->{mode} && $args->{mode} eq 'text';
|
||
|
|
|
||
|
|
my $rows = LJ::Stats::get_popular_interests();
|
||
|
|
my %interests;
|
||
|
|
foreach my $int_array (@$rows) {
|
||
|
|
my ( $int, $count ) = @$int_array;
|
||
|
|
$interests{$int} = {
|
||
|
|
eint => LJ::ehtml($int),
|
||
|
|
url => "/interests?int=" . LJ::eurl($int),
|
||
|
|
value => $count
|
||
|
|
};
|
||
|
|
}
|
||
|
|
$rv->{pop_cloud} = LJ::tag_cloud( \%interests );
|
||
|
|
$rv->{pop_ints} =
|
||
|
|
[ sort { $b->{value} <=> $a->{value} || $a->{eint} cmp $b->{eint} } values %interests ]
|
||
|
|
if %interests;
|
||
|
|
return DW::Template->render_template( 'interests/popular.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $mode eq 'add' || $mode eq 'addnew' ) {
|
||
|
|
my $rints = $remote->get_interests();
|
||
|
|
return error_ml( "interests.add.toomany", { maxinterests => $maxinterests } )
|
||
|
|
if scalar(@$rints) >= $maxinterests;
|
||
|
|
|
||
|
|
my @intids;
|
||
|
|
if ( $mode eq "add" ) {
|
||
|
|
|
||
|
|
# adding an existing interest, so we have an intid to work with
|
||
|
|
@intids = ( $args->{intid} + 0 );
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
# adding a new interest
|
||
|
|
my @keywords = LJ::interest_string_to_list( $args->{keyword} );
|
||
|
|
my @validate = LJ::validate_interest_list(@keywords);
|
||
|
|
@intids = map { LJ::get_sitekeyword_id($_) } @validate;
|
||
|
|
}
|
||
|
|
|
||
|
|
@intids = grep { $_ } @intids; # ignore any zeroes
|
||
|
|
return error_ml('error.invalidform') unless @intids;
|
||
|
|
|
||
|
|
# force them to either come from the interests page, or have posted the request.
|
||
|
|
# if both fail, ask them to confirm with a post form.
|
||
|
|
# (only uses first interest; edge case not worth the trouble to fix)
|
||
|
|
|
||
|
|
unless ( $did_post || LJ::check_referer('/interests') ) {
|
||
|
|
my $int = LJ::get_interest( $intids[0] );
|
||
|
|
LJ::text_out( \$int );
|
||
|
|
$rv->{need_post} = { int => $int, intid => $intids[0] };
|
||
|
|
}
|
||
|
|
else { # let the user add the interest
|
||
|
|
$remote->interest_update( add => \@intids );
|
||
|
|
}
|
||
|
|
return DW::Template->render_template( 'interests/add.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $mode eq 'findsim_do' ) {
|
||
|
|
return error_ml('error.tempdisabled')
|
||
|
|
unless LJ::is_enabled('interests-findsim');
|
||
|
|
return error_ml('interests.findsim_do.account.notallowed')
|
||
|
|
unless $rv->{can_use_findsim};
|
||
|
|
my $u = LJ::load_user( $args->{user} )
|
||
|
|
or return error_ml('error.username_notfound');
|
||
|
|
my $uitable = $u->is_comm ? 'comminterests' : 'userinterests';
|
||
|
|
|
||
|
|
my $dbr = LJ::get_db_reader();
|
||
|
|
my $sth =
|
||
|
|
$dbr->prepare( "SELECT i.intid, i.intcount "
|
||
|
|
. "FROM $uitable ui, interests i "
|
||
|
|
. "WHERE ui.userid=? AND ui.intid=i.intid" );
|
||
|
|
$sth->execute( $u->userid );
|
||
|
|
|
||
|
|
my ( @ints, %intcount, %pt_count, %pt_weight );
|
||
|
|
while ( my ( $intid, $count ) = $sth->fetchrow_array ) {
|
||
|
|
push @ints, $intid;
|
||
|
|
$intcount{$intid} = $count || 1;
|
||
|
|
}
|
||
|
|
return error_ml( 'interests.findsim_do.notdefined', { user => $u->ljuser_display } )
|
||
|
|
unless @ints;
|
||
|
|
|
||
|
|
# the magic's in this limit clause. that's what makes this work.
|
||
|
|
# perfect results? no. but who cares if somebody that lists "music"
|
||
|
|
# or "reading" doesn't get an extra point towards matching you.
|
||
|
|
# we care about more unique interests.
|
||
|
|
|
||
|
|
foreach (qw( userinterests comminterests )) {
|
||
|
|
$sth = $dbr->prepare("SELECT userid FROM $_ WHERE intid=? LIMIT 300");
|
||
|
|
foreach my $int (@ints) {
|
||
|
|
$sth->execute($int);
|
||
|
|
while ( my $uid = $sth->fetchrow_array ) {
|
||
|
|
next if $uid == $u->userid;
|
||
|
|
$pt_weight{$uid} += ( 1 / log( $intcount{$int} + 1 ) );
|
||
|
|
$pt_count{$uid}++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
my %magic; # balanced points
|
||
|
|
$magic{$_} = $pt_weight{$_} * 10 + $pt_count{$_} foreach keys %pt_count;
|
||
|
|
my @matches = sort { $magic{$b} <=> $magic{$a} } keys %magic;
|
||
|
|
@matches = @matches[ 0 .. ( $maxinterests - 1 ) ]
|
||
|
|
if scalar(@matches) > $maxinterests;
|
||
|
|
|
||
|
|
# load user objects
|
||
|
|
my $users = LJ::load_userids(@matches);
|
||
|
|
|
||
|
|
my $nocircle = $remote && $args->{nocircle};
|
||
|
|
my $count = { P => 0, C => 0, I => 0 };
|
||
|
|
my $data = { P => [], C => [], I => [] };
|
||
|
|
foreach my $uid (@matches) {
|
||
|
|
my $match_u = $users->{$uid};
|
||
|
|
next unless $match_u && $match_u->is_visible;
|
||
|
|
if ($nocircle) {
|
||
|
|
next if $remote->watches($match_u);
|
||
|
|
next if $match_u->is_person && $remote->trusts($match_u);
|
||
|
|
next if $match_u->is_comm && $remote->member_of($match_u);
|
||
|
|
}
|
||
|
|
my $j = $match_u->journaltype;
|
||
|
|
push @{ $data->{$j} },
|
||
|
|
{
|
||
|
|
count => ++$count->{$j},
|
||
|
|
user => $match_u->ljuser_display,
|
||
|
|
magic => sprintf( "%.3f", $magic{$uid} )
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
return error_ml( 'interests.findsim_do.nomatch', { user => $u->ljuser_display } )
|
||
|
|
unless grep { $_ } values %$count;
|
||
|
|
|
||
|
|
$rv->{findsim_u} = $u;
|
||
|
|
$rv->{findsim_count} = $count;
|
||
|
|
$rv->{findsim_data} = $data;
|
||
|
|
$rv->{nocircle} = $nocircle;
|
||
|
|
$rv->{circle_link} = LJ::page_change_getargs( nocircle => $nocircle ? '' : 1 );
|
||
|
|
|
||
|
|
return DW::Template->render_template( 'interests/findsim.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $mode eq 'enmasse' ) {
|
||
|
|
my $u = $rv->{u};
|
||
|
|
my $username = $u->user;
|
||
|
|
my $altauthas = $remote->user ne $username;
|
||
|
|
$rv->{getextra} = $altauthas ? "?authas=$username" : '';
|
||
|
|
|
||
|
|
my $fromu = LJ::load_user( $args->{fromuser} || $username )
|
||
|
|
or return error_ml('error.username_notfound');
|
||
|
|
$rv->{fromu} = $fromu;
|
||
|
|
|
||
|
|
my %uint;
|
||
|
|
my %fromint = %{ $fromu->interests }
|
||
|
|
or return error_ml('interests.error.nointerests');
|
||
|
|
$rv->{allintids} = join( ",", values %fromint );
|
||
|
|
|
||
|
|
if ( $u->equals($fromu) ) {
|
||
|
|
%uint = %fromint;
|
||
|
|
$rv->{enmasse_body} = '.enmasse.body.you';
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
%uint = %{ $u->interests };
|
||
|
|
my $other = $altauthas ? 'other_authas' : 'other';
|
||
|
|
$rv->{enmasse_body} = ".enmasse.body.$other";
|
||
|
|
}
|
||
|
|
|
||
|
|
my @checkdata;
|
||
|
|
foreach my $fint ( sort keys %fromint ) {
|
||
|
|
push @checkdata,
|
||
|
|
{
|
||
|
|
checkid => "int_$fromint{$fint}",
|
||
|
|
is_checked => $uint{$fint} ? 1 : 0,
|
||
|
|
int => $fint
|
||
|
|
};
|
||
|
|
}
|
||
|
|
$rv->{enmasse_data} = \@checkdata;
|
||
|
|
return DW::Template->render_template( 'interests/enmasse.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $mode eq 'enmasse_do' ) {
|
||
|
|
my $u = $rv->{u};
|
||
|
|
|
||
|
|
# $args is actually an object so we want a plain hashref
|
||
|
|
my $argints = {};
|
||
|
|
foreach my $key ( keys %$args ) {
|
||
|
|
$argints->{$key} = $args->{$key} if $key =~ /^int_\d+$/;
|
||
|
|
}
|
||
|
|
|
||
|
|
my @fromints = map { $_ + 0 }
|
||
|
|
split /\s*,\s*/, $args->{allintids};
|
||
|
|
my $sync = $u->sync_interests( $argints, @fromints );
|
||
|
|
|
||
|
|
my $result_ml = 'interests.results.';
|
||
|
|
if ( $sync->{deleted} ) {
|
||
|
|
$result_ml .=
|
||
|
|
$sync->{added} ? 'both'
|
||
|
|
: $sync->{toomany} ? 'del_and_toomany'
|
||
|
|
: 'deleted';
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
$result_ml .=
|
||
|
|
$sync->{added} ? 'added'
|
||
|
|
: $sync->{toomany} ? 'toomany'
|
||
|
|
: 'nothing';
|
||
|
|
}
|
||
|
|
$rv->{enmasse_do_result} = $result_ml;
|
||
|
|
$rv->{toomany} = $sync->{toomany} || 0;
|
||
|
|
$rv->{fromu} = LJ::load_user( $args->{fromuser} )
|
||
|
|
unless !$args->{fromuser}
|
||
|
|
or $u->user eq $args->{fromuser};
|
||
|
|
return DW::Template->render_template( 'interests/enmasse_do.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
if ( $mode eq 'int' ) {
|
||
|
|
my $trunc_check = sub {
|
||
|
|
my ( $check_int, $interest ) = @_;
|
||
|
|
my $e_int = LJ::ehtml($check_int);
|
||
|
|
|
||
|
|
# Determine whether the interest is too long:
|
||
|
|
# 1. If the interest already exists, a long interest will result
|
||
|
|
# in $check_int and $interest not matching.
|
||
|
|
# 2. If it didn't already exist, we fall back on just checking
|
||
|
|
# the length of $check_int.
|
||
|
|
|
||
|
|
if ( ( $interest && $check_int ne $interest )
|
||
|
|
|| length($check_int) > LJ::CMAX_SITEKEYWORD )
|
||
|
|
{
|
||
|
|
|
||
|
|
# The searched-for interest is too long, so use the short version.
|
||
|
|
my $e_int_long = $e_int;
|
||
|
|
$e_int = LJ::ehtml(
|
||
|
|
$interest
|
||
|
|
? $interest
|
||
|
|
: substr( $check_int, 0, LJ::CMAX_SITEKEYWORD )
|
||
|
|
);
|
||
|
|
|
||
|
|
$rv->{warn_toolong} = ( $rv->{warn_toolong} ? $rv->{warn_toolong} . "<br />" : '' )
|
||
|
|
. LJ::Lang::ml(
|
||
|
|
'interests.error.longinterest',
|
||
|
|
{
|
||
|
|
sitename => $LJ::SITENAMESHORT,
|
||
|
|
old_int => $e_int_long,
|
||
|
|
new_int => $e_int,
|
||
|
|
maxlen => LJ::CMAX_SITEKEYWORD
|
||
|
|
}
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
return $e_int;
|
||
|
|
};
|
||
|
|
|
||
|
|
my ( @intids, @intargs );
|
||
|
|
if ( $args->{intid} ) {
|
||
|
|
@intids = ( $args->{intid} + 0 );
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
@intargs = LJ::interest_string_to_list( $args->{int} );
|
||
|
|
@intids = map { LJ::get_sitekeyword_id( $_, 0 ) || 0 } @intargs;
|
||
|
|
}
|
||
|
|
|
||
|
|
my $max_search = 3;
|
||
|
|
if ( scalar @intids > $max_search ) {
|
||
|
|
return error_ml( 'interests.error.toomany', { num => $max_search } );
|
||
|
|
}
|
||
|
|
|
||
|
|
my ( @intdata, @no_users, @not_interested );
|
||
|
|
my $index = 0; # for referencing @intargs
|
||
|
|
my $remote_interests = $remote ? $remote->interests : {};
|
||
|
|
|
||
|
|
foreach my $intid (@intids) {
|
||
|
|
my $intarg = @intargs ? $intargs[ $index++ ] : '';
|
||
|
|
my ( $interest, $intcount ) = LJ::get_interest($intid);
|
||
|
|
my $check_int = $intarg || $interest;
|
||
|
|
|
||
|
|
if (
|
||
|
|
LJ::Hooks::run_hook(
|
||
|
|
"interest_search_ignore",
|
||
|
|
query => $check_int,
|
||
|
|
intid => $intid
|
||
|
|
)
|
||
|
|
)
|
||
|
|
{
|
||
|
|
return error_ml('interests.error.ignored');
|
||
|
|
}
|
||
|
|
|
||
|
|
my $e_int = $trunc_check->( $check_int, $interest );
|
||
|
|
push @intdata, $e_int;
|
||
|
|
push @no_users, $e_int unless $intcount;
|
||
|
|
|
||
|
|
$rv->{allcount} = $intcount if scalar @intids == 1;
|
||
|
|
|
||
|
|
# check to see if the remote user already has the interest
|
||
|
|
push @not_interested, { int => $e_int, intid => $intid }
|
||
|
|
if defined $interest && !$remote_interests->{$interest};
|
||
|
|
}
|
||
|
|
|
||
|
|
$rv->{interest} = join ', ', @intdata;
|
||
|
|
$rv->{query_count} = scalar @intdata;
|
||
|
|
$rv->{no_users} = join ', ', @no_users;
|
||
|
|
$rv->{no_users_count} = scalar @no_users;
|
||
|
|
$rv->{not_interested} = $remote ? \@not_interested : [];
|
||
|
|
|
||
|
|
# if any one interest is unused, the search can't succeed
|
||
|
|
undef @intids if @no_users;
|
||
|
|
|
||
|
|
# filtering by account type
|
||
|
|
my @type_args = ( 'none', 'P', 'C', 'I' );
|
||
|
|
push @type_args, 'F' if $remote; # no circle if not logged in
|
||
|
|
$rv->{type_list} = \@type_args;
|
||
|
|
|
||
|
|
my $type = $args->{type};
|
||
|
|
$type = 'none' unless $type && $type =~ /^[PCIF]$/;
|
||
|
|
$type = 'none' if $type eq 'F' && !$remote; # just in case
|
||
|
|
|
||
|
|
$rv->{filtered} = $type ne 'none' ? 1 : 0;
|
||
|
|
|
||
|
|
# constructor for filter links
|
||
|
|
$rv->{type_link} = sub {
|
||
|
|
return '' if $type eq $_[0]; # no link for active selection
|
||
|
|
my $typearg = $_[0] eq 'none' ? '' : $_[0];
|
||
|
|
return LJ::page_change_getargs( type => $typearg );
|
||
|
|
};
|
||
|
|
|
||
|
|
# determine which account types we need to search for
|
||
|
|
my $type_opts = {};
|
||
|
|
my %opt_map = (
|
||
|
|
C => 'nousers',
|
||
|
|
P => 'nocomms',
|
||
|
|
I => 'nocomms',
|
||
|
|
F => 'circle'
|
||
|
|
);
|
||
|
|
$type_opts = { $opt_map{$type} => 1 } if defined $opt_map{$type};
|
||
|
|
|
||
|
|
my @uids = LJ::users_with_all_ints( \@intids, $type_opts );
|
||
|
|
|
||
|
|
# determine the count of the full set for comparison
|
||
|
|
# (already set to intcount, unless we have multiple ints)
|
||
|
|
if ( $opt_map{$type} ) {
|
||
|
|
$rv->{allcount} ||= scalar LJ::users_with_all_ints( \@intids );
|
||
|
|
$rv->{allcount} //= 0; # scalar(undef) isn't zero
|
||
|
|
}
|
||
|
|
else {
|
||
|
|
# we just did the full search; count the existing list
|
||
|
|
$rv->{allcount} ||= scalar @uids;
|
||
|
|
}
|
||
|
|
|
||
|
|
# limit results to 500 most recently updated journals
|
||
|
|
if ( scalar @uids > 500 ) {
|
||
|
|
my $dbr = LJ::get_db_reader();
|
||
|
|
my $qs = join ',', map { '?' } @uids;
|
||
|
|
my $uref = $dbr->selectall_arrayref(
|
||
|
|
"SELECT userid FROM userusage WHERE userid IN ($qs)
|
||
|
|
ORDER BY timeupdate DESC LIMIT 500", undef, @uids
|
||
|
|
);
|
||
|
|
die $dbr->errstr if $dbr->err;
|
||
|
|
@uids = map { $_->[0] } @$uref;
|
||
|
|
}
|
||
|
|
|
||
|
|
my $us = LJ::load_userids(@uids);
|
||
|
|
|
||
|
|
# prepare to filter and sort the results into @ul
|
||
|
|
|
||
|
|
my $typefilter = sub {
|
||
|
|
$rv->{comm_count}++ if $_[0]->is_community;
|
||
|
|
return 1 if $type eq 'none';
|
||
|
|
return 1 if $type eq 'F'; # already filtered
|
||
|
|
return $_[0]->journaltype eq $type;
|
||
|
|
};
|
||
|
|
|
||
|
|
my $should_show = sub {
|
||
|
|
return $_[0]->should_show_in_search_results( for => $remote );
|
||
|
|
};
|
||
|
|
|
||
|
|
my $updated = LJ::get_timeupdate_multi( keys %$us );
|
||
|
|
my $def_upd = sub { $updated->{ $_[0]->userid } || 0 };
|
||
|
|
|
||
|
|
# let undefined values be zero for sorting purposes
|
||
|
|
|
||
|
|
my @ul = sort { $def_upd->($b) <=> $def_upd->($a) || $a->user cmp $b->user }
|
||
|
|
grep { $_ && $typefilter->($_) && $should_show->($_) } values %$us;
|
||
|
|
$rv->{type_count} = scalar @ul if $rv->{allcount} != scalar @ul;
|
||
|
|
$rv->{comm_count} = 1 if $type_opts->{nocomms}; # doesn't count
|
||
|
|
|
||
|
|
if (@ul) {
|
||
|
|
|
||
|
|
# pagination
|
||
|
|
my $curpage = $args->{page} || 1;
|
||
|
|
my %items = LJ::paging( \@ul, $curpage, 30 );
|
||
|
|
my @data;
|
||
|
|
|
||
|
|
# subset of users to display on this page
|
||
|
|
foreach my $u ( @{ $items{items} } ) {
|
||
|
|
my $desc = LJ::ehtml( $u->prop('journaltitle') );
|
||
|
|
my $label = LJ::Lang::ml('search.user.journaltitle');
|
||
|
|
|
||
|
|
# community promo desc overrides journal title
|
||
|
|
if ( $u->is_comm
|
||
|
|
&& LJ::is_enabled('community_themes')
|
||
|
|
&& ( my $prop_theme = $u->prop("comm_theme") ) )
|
||
|
|
{
|
||
|
|
$label = LJ::Lang::ml('search.user.commdesc');
|
||
|
|
$desc = LJ::ehtml($prop_theme);
|
||
|
|
}
|
||
|
|
|
||
|
|
my $userpic = $u->userpic;
|
||
|
|
$userpic = $userpic ? $userpic->imgtag_lite : '';
|
||
|
|
|
||
|
|
my $updated =
|
||
|
|
$updated->{ $u->id }
|
||
|
|
? LJ::diff_ago_text( $updated->{ $u->id } )
|
||
|
|
: undef;
|
||
|
|
push @data,
|
||
|
|
{
|
||
|
|
u => $u,
|
||
|
|
updated => $updated,
|
||
|
|
icon => $userpic,
|
||
|
|
desc => $desc,
|
||
|
|
desclabel => $label
|
||
|
|
};
|
||
|
|
}
|
||
|
|
|
||
|
|
$rv->{navbar} = LJ::paging_bar( $items{page}, $items{pages} );
|
||
|
|
$rv->{data} = \@data;
|
||
|
|
}
|
||
|
|
|
||
|
|
return DW::Template->render_template( 'interests/int.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
# if we got to this point, we need to render the default template
|
||
|
|
return DW::Template->render_template( 'interests/index.tt', $rv );
|
||
|
|
}
|
||
|
|
|
||
|
|
1;
|