head<= <=head body<= 'bml.interests', ljadwrapper => 1 }); return $ad_box . $str; }; LJ::set_active_crumb('searchinterests'); return $print_with_ad->("") unless LJ::text_in(\%GET) && LJ::text_in(\%POST); my $did_post = LJ::did_post(); my $remote = LJ::get_remote(); my $table = sub { $_[0]->{'journaltype'} eq 'C' ? 'comminterests' : 'userinterests' }; if (!$did_post && $GET{'view'} eq "popular") { return $print_with_ad->($ML{'.popular.disabled'}) if $LJ::DISABLED{'interests-popular'}; my $ret = ''; $ret .= " "href='$LJ::SITEROOT/interests.bml?view=popular&mode=text'" }) unless $GET{mode} eq 'text'; $ret .= " p?>"; my $rows = LJ::Stats::get_popular_interests(); return $print_with_ad->("Sorry, interest data currently unavailable.") unless @$rows; my %interests; foreach my $int_array (@$rows) { my ($int, $count) = @$int_array; $interests{$int} = { int => $int, eint => LJ::ehtml($int), url => "/interests.bml?int=" . LJ::eurl($int), value => $count, }; } unless ($GET{'mode'} eq 'text') { $ret .= LJ::tag_cloud(\%interests); } else { $ret .= "

"; foreach my $i (sort { $b->{value} <=> $a->{value} } values %interests) { $ret .= ""; } $ret .= "
$ML{'.interest'}$ML{'.count'}
$i->{eint}$i->{value}
"; } return $print_with_ad->($ret); } if ((!$did_post && $GET{'mode'} eq "add" && $GET{'intid'}) || ($did_post && $POST{'mode'} eq "add" && $POST{'intid'})) { my $intid = $did_post ? $POST{'intid'}+0 : $GET{'intid'}+0; my $ret = ''; unless ($remote) { $ret .= ""; return $print_with_ad->($ret); } # force them to either come from the interests.bml page, or have posted the request. # if both fail, ask them to confirm with a post form. my $dbr = LJ::get_db_reader(); unless ($did_post || BML::get_client_header('Referer') =~ /^\Q$LJ::SITEROOT\E\/interests\.bml\?/) { my ($int) = $dbr->selectrow_array("SELECT interest FROM interests WHERE intid=?", undef, $intid); LJ::text_out(\$int); $ret .= ""; $ret .= " $int}); $ret .= "

"; $ret .= LJ::html_hidden('mode' => 'add', 'intid' => $intid); $ret .= LJ::html_submit(undef, BML::ml(".add.btn.text", {'interest' => $int})); $ret .= LJ::form_auth(); $ret .= "
p?>"; return $print_with_ad->($ret); } my $rints = LJ::get_interests($remote); my $count = scalar(@$rints); # account for the case where we bypass the POST due to the referer return $print_with_ad->($ML{'error.invalidform'}) unless !$did_post || LJ::check_form_auth(); if ($count >= 150) { $ret .= " "150"}) ." p?>"; return $print_with_ad->($ret); } my $dbh = LJ::get_db_writer(); my $uitable = $table->($remote); $dbh->do("INSERT INTO $uitable (userid, intid) VALUES (?, ?)", undef, $remote->{'userid'}, $intid); LJ::memcache_kill($remote, "intids"); unless ($dbh->err) { $dbh->do("UPDATE interests SET intcount=intcount+1 WHERE intid=?", undef, $intid); } # if a community, remove any old rows from userinterests if ($remote->{'journaltype'} eq 'C') { $dbh->do("DELETE FROM userinterests WHERE userid=?", undef, $remote->{'userid'}); } $ret .= ""; return $print_with_ad->($ret); } if (!$did_post && $GET{'mode'} eq "findsim_do") { return $print_with_ad->($ML{'error.tempdisabled'}) if $LJ::DISABLED{'interests-findsim'}; return $print_with_ad->($ML{'.findsim_do.account.notallowed'}) unless LJ::get_cap($remote, "findsim"); my $ret = ""; my $u = LJ::load_user($GET{'user'}); return $print_with_ad->("") unless $u; my @ints; my %intcount; my $dbr = LJ::get_db_reader(); my $sth = $dbr->prepare("SELECT i.intid, i.intcount FROM userinterests ui, interests i ". "WHERE ui.userid=? AND ui.intid=i.intid"); $sth->execute($u->{'userid'}); while (my ($intid, $count) = $sth->fetchrow_array) { push @ints, $intid; $intcount{$intid} = $count || 1; } unless (@ints) { my $msg = BML::ml('.findsim_do.notdefined', { 'user' => LJ::ljuser($u) }); return $print_with_ad->(""); } my %pt_count; my %pt_weight; foreach my $int (@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 "women" # doesn't get an extra point towards matching you. we care about more unique interests. my $sth = $dbr->prepare("SELECT userid FROM userinterests WHERE intid=? LIMIT 500"); $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 foreach (keys %pt_count) { $magic{$_} = $pt_weight{$_}*10 + $pt_count{$_}; } my @matches = sort { $magic{$b} <=> $magic{$a} } keys %magic; if (@matches > 150) { @matches = @matches[0..149]; } my $sth = $dbr->prepare("SELECT userid, user FROM useridmap WHERE userid IN (" . join(",",@matches) . ")"); $sth->execute; my %username; while (my ($id, $name) = $sth->fetchrow_array) { $username{$id} = $name; } unless (@matches) { return $print_with_ad->(" LJ::ljuser($u)}) ." p?>"); } $ret .= " LJ::ljuser($u)}) ." p?>"; $ret .= "

"; my $count; foreach my $uid (@matches) { $count++; $ret .= "", $magic{$uid}); } $ret .= "
#$ML{'User'}$ML{'.findsim_do.magic'}
$count"; $ret .= LJ::ljuser($username{$uid}); $ret .= sprintf("%.3f

"; $ret .= ""; return $print_with_ad->($ret); } if (!$did_post && $GET{'mode'} eq "enmasse") { return $print_with_ad->("") unless $remote; my $authas = $GET{'authas'} || $remote->{'user'}; my $u = LJ::get_authas_user($authas); return $print_with_ad->(LJ::bad_input(BML::ml('.error.enmasse.noaccess', {'user' => LJ::ljuser($authas)}))) unless $u; my $altauthas = $remote->{'user'} ne $u->{'user'}; my $getextra = $altauthas ? "?authas=$u->{'user'}" : ''; my $userid = $u->{'userid'}; my $username = $u->{'user'}; my $fromu = LJ::load_user($GET{'fromuser'} || $username); my %uint; my %fromint; my $fints = LJ::get_interests($fromu); foreach (@$fints) { $fromint{$_->[1]} = $_->[0]+0; } return $print_with_ad->("") unless %fromint; my $ret = ""; $ret .= LJ::html_hidden(mode => 'enmasse', fromuser => $fromu->{'user'}); $ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }); $ret .= " p?>
"; $ret .= "{'userid'} == $fromu->{'userid'}) { %uint = %fromint; $ret .= $ML{'.enmasse.body.you'}; } else { my $in = join (",", map { $fromint{$_} } keys %fromint); my $uints = LJ::get_interests($u); foreach (@$uints) { $uint{$_->[1]} = $_->[0]; } if ($altauthas) { $ret .= BML::ml('.enmasse.body.other_authas', { 'user' => LJ::ljuser($fromu), 'target' => LJ::ljuser($u) }); } else { $ret .= BML::ml('.enmasse.body.other', { 'user' => LJ::ljuser($fromu) }); } } $ret .= " p?>
"; $ret .= ""; my @fromintsorted = sort keys %fromint; my $cols = 3; my $rows = int((scalar(@fromintsorted) + $cols - 1) / $cols); for (my $i = 0; $i < $rows; $i++) { $ret .= ""; for (my $j = 0; $j < $cols; $j++) { my $index = $rows * $j + $i; if ($index < scalar(@fromintsorted)) { my $checked = $uint{$fromintsorted[$index]} ? 1 : undef; $ret .= ""; } else { $ret .= ""; } } $ret .= ""; } $ret .= "
"; $ret .= LJ::html_check({name => "int_$fromint{$fromintsorted[$index]}", id => "int_$fromint{$fromintsorted[$index]}", selected => $checked, value => 1}); my $bold1 = $checked ? "" : ""; my $bold2 = $checked ? "" : ""; $ret .= " 
"; $ret .= LJ::html_hidden('mode', 'enmasse_do'); $ret .= LJ::html_hidden('fromuser', $fromu->{'user'}); $ret .= LJ::html_hidden('allintids', join (",", values %fromint)); $ret .= "
"; return $ret; } if ($did_post && $POST{'mode'} eq "enmasse_do") { return $print_with_ad->("") unless $remote; my $authas = $GET{'authas'} || $remote->{'user'}; my $u = LJ::get_authas_user($authas); return $print_with_ad->(LJ::bad_input($ML{'.error.noauth'})) unless $u; my $uitable = $table->($u); my %uint; my $intcount = 0; my $uints = LJ::get_interests($u); foreach (@$uints) { $uint{$_->[0]} = $_->[1]; # uint{intid} = interest $intcount++; } my @fromints = map { $_+0 } split (/\s*,\s*/, $POST{'allintids'}); my @todel; my @toadd; foreach my $fromint (@fromints) { next unless $fromint > 0; # prevent adding zero or negative intid push (@todel, $fromint) if $uint{$fromint} && !$POST{'int_'.$fromint}; push (@toadd, $fromint) if !$uint{$fromint} && $POST{'int_'.$fromint}; } my ($deleted, $added, $toomany) = (0, 0, 0); if (@todel) { my $intid_in = join(",", @todel); my $dbh = LJ::get_db_writer(); $dbh->do("DELETE FROM $uitable WHERE userid=? AND intid IN ($intid_in)", undef, $u->{'userid'}); $dbh->do("UPDATE interests SET intcount=intcount-1 WHERE intid IN ($intid_in)"); $deleted = 1; } if (@toadd) { if ($intcount + scalar @toadd > 150) { $toomany = 1; } else { my $dbh = LJ::get_db_writer(); my $sqlp = "(?,?)" . (",(?,?)" x (scalar(@toadd) - 1)); my @bindvars = map { ($u->{'userid'}, $_) } @toadd; $dbh->do("REPLACE INTO $uitable (userid, intid) VALUES $sqlp", undef, @bindvars); my $intid_in = join(",", @toadd); $dbh->do("UPDATE interests SET intcount=intcount+1 WHERE intid IN ($intid_in)"); $added = 1; } } # if a community, remove any old rows from userinterests if ($u->{'journaltype'} eq 'C') { my $dbh = LJ::get_db_writer(); $dbh->do("DELETE FROM userinterests WHERE userid=?", undef, $u->{'userid'}); } my $ret = " 150}) : $ML{'.results.deleted'}; } else { $ret .= $added ? $ML{'.results.added'} : $toomany ? BML::ml('.results.toomany', {'intcount' => 150}) : $ML{'.results.nothing'}; } my $profile_url = $u->profile_url; my $u_other = LJ::load_user($POST{'fromuser'}); my $profile_url_other = $u_other ? $u_other->profile_url : ""; $ret .= " p?> "href='$profile_url'"}); $ret .= " " . BML::ml('.results.goback2', {'user' => LJ::ljuser($POST{'fromuser'}), 'aopts' => "href='$profile_url_other'"}) if ($POST{'fromuser'} ne "" && $POST{'fromuser'} ne $u->{'user'}); $ret .= " p?>"; LJ::memcache_kill($u, "intids"); return $print_with_ad->($ret); } if (!$did_post && ($GET{'intid'} || $GET{'int'})) { my $sth; my $dbr = LJ::get_db_reader(); my ($interest, $intid, $intcount); if ($GET{'intid'}) { ($interest, $intid, $intcount) = $dbr->selectrow_array("SELECT interest, intid, intcount FROM interests WHERE intid=?", undef, $GET{'intid'}); } else { ($interest, $intid, $intcount) = $dbr->selectrow_array("SELECT interest, intid, intcount FROM interests WHERE interest=?", undef, $GET{'int'}); } my $check_int = $GET{int} || $interest; if (LJ::run_hook("interest_search_ignore", query => $check_int, intid => $intid)) { return $print_with_ad->(""); } my $search_ad = LJ::search_ads(query => $GET{int}, count => 2) if $GET{int}; my $e_int = LJ::ehtml($GET{int}); my $ret = ''; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= ""; $ret .= "
$ML{'.interested.in'}
"; $ret .= LJ::html_text({name => 'int', size => 20, value => $interest || $e_int}) . " "; $ret .= LJ::html_submit(undef, $ML{'.interested.btn.find'}); $ret .= "
$ML{'.enmasse.intro'}
"; $ret .= LJ::html_text({name => 'fromuser', size => 20}) . " "; $ret .= LJ::html_submit(undef, $ML{'.enmasse.btn'}); $ret .= LJ::html_hidden('mode', 'enmasse'); $ret .= "
"; # no results return $print_with_ad->(qq { $ret $search_ad "$e_int." You can create one! p?> $e_int. If you are interested in this and would like to be added to this list, click here. More fun stuff can be found on the interests page. p?> }) unless $interest; $intid += 0; ### hook my $hide_ad = 0; LJ::run_hooks("interests_bml", { 'intid' => $intid, 'int' => $interest, 'ret' => \$ret, 'hide_ad' => \$hide_ad, }); $ret .= $search_ad unless $hide_ad; ### communities my $LIMIT = 500; my $should_show = sub { my $u = shift; return $u->should_show_in_search_results( for => $remote ); }; unless ($LJ::DISABLED{'interests-community'}) { my @uids; $sth = $dbr->prepare("SELECT userid FROM comminterests WHERE intid=? LIMIT $LIMIT"); $sth->execute($intid); push @uids, $_ while $_ = $sth->fetchrow_array; my @other_uids = LJ::run_hook("get_other_interested_comms", $interest, $remote); foreach my $uid (@other_uids) { push @uids, $uid; } my $updated = LJ::get_timeupdate_multi(@uids); my $us = LJ::load_userids(@uids); my @cl = sort { $updated->{$b->id} <=> $updated->{$a->id} || $a->user cmp $b->user } grep { $_ && $_->is_visible && $should_show->($_) } values %$us; my $count = @cl; my $list; my $show_comm_promos = !LJ::conf_test($LJ::DISABLED{"community_themes"}); foreach (@cl) { my $name = $_->{name}; LJ::text_out(\$name); $list .= "
  • " . LJ::ljuser($_) . " - " . LJ::ehtml($name); $list .= " ("; if ($updated->{$_->id} > 0) { $list .= "Updated "; $list .= LJ::ago_text(time() - $updated->{$_->id}); } else { $list .= "Never updated"; } $list .= ")"; $list .= "
       " . LJ::ehtml($_->prop("comm_theme")) . "" if $show_comm_promos && $_->prop("comm_theme"); $list .= "
  • "; } if (@cl) { $ret .= "

    " . BML::ml(".communities.header", {'interest' => $interest}) ."

    "; $ret .= "

    " . BML::ml('.matches2', {'num' => $count}) . "

    "; } } ##### users $ret .= "

    " . BML::ml(".users.header", {'interest' => $interest}) . "

    \n

    "; if ($remote) { $ret .= " " . BML::ml('.addint2', {'aopts' => "href='$LJ::SITEROOT/interests.bml?mode=add&intid=$intid'"}); } $ret .= " " . BML::ml('.morestuff2', {'aopts' => "href='$LJ::SITEROOT/interests.bml'"}) . "

    "; my @uids; $sth = $dbr->prepare("SELECT userid FROM userinterests WHERE intid=? LIMIT $LIMIT"); $sth->execute($intid); push @uids, $_ while $_ = $sth->fetchrow_array; my $us = LJ::load_userids(@uids); my @ul = grep { $_ && $_->is_visible # visible users && !$_->is_community # that aren't communities && (!$_->age || $_->age > 13) # are over 13 && $should_show->($_) # and should show to the remote user } values %$us; $ret .= "

    " . BML::ml('.matches2', {'num' => scalar @ul}) . "

    "; my $navbar; my $results = LJ::user_search_display( users => \@ul, timesort => 1, perpage => 50, curpage => $GET{'page'} || 1, navbar => \$navbar, ); $ret .= "
    $navbar

    "; $ret .= $results; return $hide_ad ? $ret : $print_with_ad->($ret); } my $ret = ""; $ret .= ""; $ret .= ""; unless ($LJ::DISABLED{'interests-popular'}) { $ret .= ""; } $ret .= ""; $ret .= ""; if (!$LJ::DISABLED{'interests-findsim'} && $remote && LJ::get_cap($remote, "findsim")) { $ret .= ""; } $ret .= ""; $ret .= ""; $ret .= "
    "; $ret .= "$ML{'.interests.viewpop'}
    $ML{'.interested.in'}
    "; $ret .= LJ::html_text({name => 'int', size => 20}) . " "; $ret .= LJ::html_submit(undef, $ML{'.interested.btn.find'}); $ret .= "
    $ML{'.interests.findsim'}
    "; $ret .= LJ::html_hidden('mode', 'findsim_do'); $ret .= LJ::html_text({name => 'user', value => $remote->{'user'}, size => 20}) . " "; $ret .= LJ::html_submit(undef, $ML{'.interested.btn.find'}); $ret .= "
    $ML{'.enmasse.intro'}
    "; $ret .= LJ::html_text({name => 'fromuser', size => 20}) . " "; $ret .= LJ::html_submit(undef, $ML{'.enmasse.btn'}); $ret .= LJ::html_hidden('mode', 'enmasse'); $ret .= "
    "; $ret .= BML::ml('.nointerests.text2', {'aopts' => "href='$LJ::SITEROOT/manage/profile/'"}); return $print_with_ad->($ret); } _code?>  "; $ret .= LJ::search_ads(query => $GET{int}, count => 2) if $GET{int}; return $ret; } _code?> <=body page?> link: htdocs/interests.bml, htdocs/manage/profile/index.bml post: htdocs/interests.bml form: htdocs/interests.bml _c?>