[dw-free] convert interests.bml to TT
[commit: http://hg.dwscoalition.org/dw-free/rev/75f310215036]
http://bugs.dwscoalition.org/show_bug.cgi?id=3110
Convert from BML files to TT / controller. Modernize, make cleaner.
Patch by
kareila.
Files modified:
http://bugs.dwscoalition.org/show_bug.cgi?id=3110
Convert from BML files to TT / controller. Modernize, make cleaner.
Patch by
![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Files modified:
- bin/upgrading/en.dat
- cgi-bin/DW/Controller/Search/Interests.pm
- cgi-bin/ljfeed.pl
- htdocs/interests.bml
- htdocs/interests.bml.text
- views/interests/add.tt
- views/interests/add.tt.text
- views/interests/enmasse.tt
- views/interests/enmasse.tt.text
- views/interests/enmasse_do.tt
- views/interests/enmasse_do.tt.text
- views/interests/findsim.tt
- views/interests/findsim.tt.text
- views/interests/index.tt
- views/interests/index.tt.text
- views/interests/int.tt
- views/interests/int.tt.text
- views/interests/popular.tt
- views/interests/popular.tt.text
-------------------------------------------------------------------------------- diff -r 11ed0d63e6fd -r 75f310215036 bin/upgrading/en.dat --- a/bin/upgrading/en.dat Fri Dec 17 01:58:35 2010 +0800 +++ b/bin/upgrading/en.dat Fri Dec 17 02:17:18 2010 +0800 @@ -2147,6 +2147,51 @@ inbox.nomessages=No Messages inbox.refresh=Refresh +interests.add.toomany=You already have [[maxinterests]] interests defined. + +interests.enmasse.btn=Show List + +interests.enmasse.intro=Modify your interests based on those of: + +interests.error.ignored=Sorry, we're unable to help you find users matching the interests you've provided. + +interests.error.longinterest=As [[sitename]] does not support interests longer than [[maxlen]] characters, your search for <b>[[old_int]]</b> was converted into a search for <b>[[new_int]]</b> instead. + +interests.error.nointerests=The selected account hasn't specified any interests. + +interests.findsim_do.account.notallowed=Your account type doesn't let you use this tool. + +interests.findsim_do.nomatch=Nobody similar to [[user]]. + +interests.findsim_do.notdefined=[[user]] has no interests defined. + +interests.interested.btn=Find + +interests.interested.in=Find people interested in: + +interests.popular.disabled=The popular interests feature is unavailable. + +interests.results.added=You've successfully added the selected interests to your interests list. + +interests.results.both=Success. You've successfully added the selected interests to your interests list and removed those you deselected. + +interests.results.deleted=You successfully removed the interests you deselected from your interests list. + +interests.results.del_and_toomany<< +You successfully removed the interests you deselected, but you didn't add +any new interests because you can only list a maximum of [[intcount]] +interests. You may wish to go back and select fewer interests to add or +delete some old interests. +. + +interests.results.nothing=You didn't make any changes. + +interests.results.toomany<< +You didn't add any of your selected interests because you can only list +a maximum of [[intcount]] interests. You may wish to go back and select +fewer interests to add or delete some old interests. +. + invitecodes.userclass.lucky=Lucky users label.screening.all=All comments diff -r 11ed0d63e6fd -r 75f310215036 cgi-bin/DW/Controller/Search/Interests.pm --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cgi-bin/DW/Controller/Search/Interests.pm Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,342 @@ +#!/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::Constants; + +DW::Routing->register_string( '/interests', \&interest_handler, app => 1 ); + +sub interest_handler { + my $r = DW::Request->get; + my $did_post = LJ::did_post(); + my $args = $did_post ? $r->post_args : $r->get_args; + return error_ml( 'bml.badinput.body' ) 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, $authas ) = ( $mode eq "add" ? 0 : 1, 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} } 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 $intid; + if ( $mode eq "add" ) { + # adding an existing interest, so we have an intid to work with + $intid = $args->{intid} + 0; + } else { + # adding a new interest + my @validate = LJ::validate_interest_list( $args->{keyword} ); + $intid = LJ::get_sitekeyword_id( $validate[0] ) if @validate; + } + + return error_ml( 'error.invalidform' ) unless $intid; + + # 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. + + unless ( $did_post || LJ::check_referer( '/interests' ) ) { + my $int = LJ::get_interest( $intid ); + LJ::text_out( \$int ); + $rv->{need_post} = { int => $int, intid => $intid }; + } else { # let the user add the interest + $remote->interest_update( add => [$intid] ); + } + 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 $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 ); + + 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. + $sth = $dbr->prepare( "SELECT userid FROM userinterests WHERE intid=? LIMIT 500" ); + 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; + return error_ml( 'interests.findsim_do.nomatch', + { user => $u->ljuser_display } ) + unless @matches; + + # prepare userid => username hash + $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; + } + + my $count = 1; + my $data = []; + foreach my $uid ( @matches ) { + push @$data, { count => $count++, + user => LJ::ljuser( $username{$uid} ), + magic => sprintf( "%.3f", $magic{$uid} ) }; + } + $rv->{findsim_u} = $u; + $rv->{findsim_data} = $data; + 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 $intarg = LJ::utf8_lc ( $args->{int} ); + my $intid = $args->{intid} ? $args->{intid} + 0 : + LJ::get_sitekeyword_id( $intarg, 0 ) || 0; + 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 = 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 ) { + # if the searched-for interest is too long, we use the short version from here on + my $e_int_long = $e_int; + $e_int = LJ::ehtml( $interest ? $interest : substr( $check_int, 0, LJ::CMAX_SITEKEYWORD ) ); + $rv->{warn_toolong} = + LJ::Lang::ml( 'interests.error.longinterest', + { sitename => $LJ::SITENAMESHORT, + old_int => $e_int_long, new_int => $e_int, + maxlen => LJ::CMAX_SITEKEYWORD } ); + } + $rv->{e_int} = $e_int; + $rv->{interest} = $interest; + $rv->{intid} = $intid; + $rv->{intcount} = $intcount; + + my $dbr = LJ::get_db_reader(); + my $int_query = sub { + my $i = shift; # comminterests or userinterests + my $LIMIT = 500; + my $q = "SELECT $i.userid FROM $i, userusage + WHERE $i.intid = ? AND $i.userid = userusage.userid + ORDER BY userusage.timeupdate DESC LIMIT $LIMIT"; + my $uref = $dbr->selectall_arrayref( $q, undef, $intid ); + return LJ::load_userids( map { $_->[0] } @$uref ); + # can't trust LJ::load_userids to maintain sort order + }; + + my $should_show = sub { + return $_[0]->should_show_in_search_results( for => $remote ); + }; + + # community results + if ( LJ::is_enabled( 'interests-community' ) ) { + my $us = $int_query->( "comminterests" ); + my $updated = LJ::get_timeupdate_multi( keys %$us ); + my @cl = sort { $updated->{$b->id} <=> $updated->{$a->id} || $a->user cmp $b->user } + grep { $_ && $_->is_visible && $should_show->( $_ ) } values %$us; + $rv->{int_comms} = { count => scalar @cl, data => [] }; + foreach ( @cl ) { + my $updated = $updated->{$_->id} + ? LJ::diff_ago_text( $updated->{$_->id} ) + : undef; + my $prop_theme = $_->prop("comm_theme"); + my $theme = LJ::is_enabled('community_themes') && $prop_theme + ? LJ::ehtml( $prop_theme ) + : undef; + push @{ $rv->{int_comms}->{data} }, + { u => $_, updated => $updated, theme => $theme }; + } + } + + # user results + my $us = $int_query->( "userinterests" ); + my @ul = grep { $_ + && $_->is_visible # visible users + && ! $_->is_community # not communities + && ( ! $_->age || $_->age > 13 ) # are over 13 + && $should_show->( $_ ) # and should show to the remote user + } values %$us; + my $navbar; + my $results = + LJ::user_search_display( users => \@ul, + timesort => 1, + perpage => 50, + curpage => exists $args->{page} ? + $args->{page} : 1, + navbar => \$navbar ); + + $rv->{int_users} = { count => scalar( @ul ), navbar => $navbar, + results => $results }; + 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; diff -r 11ed0d63e6fd -r 75f310215036 cgi-bin/ljfeed.pl --- a/cgi-bin/ljfeed.pl Fri Dec 17 01:58:35 2010 +0800 +++ b/cgi-bin/ljfeed.pl Fri Dec 17 02:17:18 2010 +0800 @@ -757,7 +757,7 @@ sub create_view_foaf { foreach my $int (@$intu) { LJ::text_out(\$int->[1]); # 1==interest $ret .= " <foaf:interest dc:title=\"". LJ::exml($int->[1]) . "\" " . - "rdf:resource=\"$LJ::SITEROOT/interests.bml?int=" . LJ::eurl($int->[1]) . "\" />\n"; + "rdf:resource=\"$LJ::SITEROOT/interests?int=" . LJ::eurl($int->[1]) . "\" />\n"; } # check if the user has a "FOAF-knows" group diff -r 11ed0d63e6fd -r 75f310215036 htdocs/interests.bml --- a/htdocs/interests.bml Fri Dec 17 01:58:35 2010 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,526 +0,0 @@ -<?_c -# This code was forked from the LiveJournal project owned and operated -# by Live Journal, Inc. The code has been modified and expanded by -# Dreamwidth Studios, LLC. These files were originally licensed under -# the terms of the license supplied by Live Journal, Inc, which can -# currently be found at: -# -# http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt -# -# In accordance with the original license, this code and all its -# modifications are provided under the GNU General Public License. -# A copy of that license can be found in the LICENSE file included as -# part of this distribution. -_c?> -<?page -title=><?_ml .title _ml?> -head<= -<style> - div.tagcloud a { text-decoration: none; } - ul.contentlist li { padding-bottom: 3px; } -</style> -<=head - -body<= -<?_code -{ - use strict; - use vars qw(%GET %POST); - - LJ::need_res( qw( stc/interests.css ) ); - - LJ::set_active_crumb('searchinterests'); - - return "<?badinput?>" - unless LJ::text_in(\%GET) && LJ::text_in(\%POST); - - my $did_post = LJ::did_post(); - - my $remote = LJ::get_remote(); - - my $maxinterests = $remote ? $remote->count_max_interests : 0; - - my $table = sub { $_[0]->is_community ? 'comminterests' : 'userinterests' }; - - if (!$did_post && $GET{'view'} eq "popular") { - return $ML{'.popular.disabled'} unless LJ::is_enabled('interests-popular'); - my $ret = ''; - $ret .= "<?h1 $ML{'.popular.head'} h1?><?p $ML{'.popular.text'} "; - - $ret .= BML::ml('.popular.textmode', { 'aopts' => "href='$LJ::SITEROOT/interests?view=popular&mode=text'" }) - unless $GET{mode} eq 'text'; - - $ret .= " p?>"; - - my $rows = LJ::Stats::get_popular_interests(); - return $ML{'.error.nodata'} unless @$rows; - - my %interests; - foreach my $int_array (@$rows) - { - my ($int, $count) = @$int_array; - $interests{$int} = { - int => $int, - eint => LJ::ehtml($int), - url => "/interests?int=" . LJ::eurl($int), - value => $count, - }; - } - - unless ($GET{'mode'} eq 'text') { - $ret .= LJ::tag_cloud(\%interests); - } else { - $ret .= "<p><table><tr><th>$ML{'.interest'}</th><th>$ML{'.count'}</th></tr>"; - foreach my $i (sort { $b->{value} <=> $a->{value} } values %interests) { - $ret .= "<tr><td><a href='$i->{url}'>$i->{eint}</a></td><td>$i->{value}</td></tr>"; - } - $ret .= "</table>"; - } - - return $ret; - } - - my $formargs = $did_post ? \%POST : \%GET; - if ( $formargs->{mode} && - ( $formargs->{mode} eq "add" && $formargs->{intid} || - $formargs->{mode} eq "addnew" && $formargs->{keyword} ) ) { - - my $ret = ''; - unless ( $remote ) { - $ret .= "<?h1 $ML{'Error'} h1?><?p $ML{'.error.add.mustlogin'} p?>"; - return $ret; - } - - # account for the case where we bypass the POST due to the referer - return $ML{'error.invalidform'} unless !$did_post || LJ::check_form_auth(); - - my $rints = $remote->get_interests(); - my $count = scalar( @$rints ); - - if ($count >= $maxinterests) { - $ret .= "<?h1 $ML{'.add.toomany.head'} h1?><?p " .BML::ml( ".add.toomany.text", { maxinterests => $maxinterests } ) ." p?>"; - return $ret; - } - - my $intid; - if ( $formargs->{mode} eq "add" ) { - # adding an existing interest, so we have an intid to work with - $intid = $formargs->{intid} + 0; - } else { - # adding a new interest - my @validate = LJ::validate_interest_list( $formargs->{keyword} ); - $intid = LJ::get_sitekeyword_id( $validate[0] ) if @validate; - } - - return $ML{'error.invalidform'} unless $intid; - - # 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. - - unless ( $did_post || LJ::check_referer('/interests.bml') ) - { - my $int = LJ::get_interest( $intid ); - LJ::text_out(\$int); - - $ret .= "<?h1 $ML{'.add.confirm.head'} h1?>"; - $ret .= "<?p " . BML::ml(".add.confirm.text", {'interest' => $int}); - $ret .= "<form method='post' action='interests'><div align='center'>"; - $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 .= "</div></form> p?>"; - return $ret; - } - - $remote->interest_update( add => [$intid] ); - - my $profile_url = $remote->profile_url; - $ret .= "<?h1 $ML{'.add.added.head'} h1?><?p $ML{'.add.added.text'} p?>" . - "<ul><li><a href='$LJ::SITEROOT/interests'>$ML{'.add.added.interestspage'}</a></li>" . - "<li><a href='$LJ::SITEROOT/manage/profile/#interests'>$ML{'.add.added.editinterests'}</a></li>" . - "<li><a href='$profile_url'>$ML{'.add.added.viewprofile'}</a></li>" . - "<li><a href='$LJ::SITEROOT/manage/profile'>$ML{'.add.added.editprofile'}</a></li></ul>"; - return $ret; - } - - if (!$did_post && $GET{'mode'} eq "findsim_do") { - return $ML{'error.tempdisabled'} unless LJ::is_enabled('interests-findsim'); - - return $ML{'.findsim_do.account.notallowed'} unless $remote && $remote->can_find_similar; - - my $ret = ""; - my $u = LJ::load_user($GET{'user'}); - return "<?h1 $ML{'Error'} h1?><?p $ML{'error.username_notfound'} p?>" 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 "<?h1 $ML{'Error'} h1?><?p $msg p?>"; - } - - 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 "reading" - # 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 > $maxinterests) { @matches = @matches[0..( $maxinterests - 1 )]; } - 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 "<?h1 $ML{'.findsim_do.nomatch.head'} h1?><?p " .BML::ml(".findsim_do.nomatch.text", {'user' => LJ::ljuser($u)}) ." p?>"; - } - - $ret .= "<?h1 $ML{'.findsim_do.similar.head'} h1?><?p " .BML::ml(".findsim_do.similar.text", {'user' => LJ::ljuser($u)}) ." p?>"; - - $ret .= "<p><table cellpadding='3'><tr valign='bottom'><th>#</th><th width='250'>$ML{'.findsim_do.user'}</th><td><b>$ML{'.findsim_do.magic'}</b></td></tr>"; - my $count; - foreach my $uid (@matches) - { - $count++; - $ret .= "<tr><td>$count</td><td>"; - $ret .= LJ::ljuser($username{$uid}); - $ret .= sprintf("</td><td>%.3f</td></tr>", $magic{$uid}); - } - $ret .= "</table></p>"; - - $ret .= "<?h1 $ML{'.findsim_do.magic.head'} h1?><?p $ML{'.findsim_do.magic.text'} p?>"; - return $ret; - } - - if (!$did_post && $GET{'mode'} eq "enmasse") - { - return "<?needlogin?>" unless $remote; - - my $authas = $GET{'authas'} || $remote->{'user'}; - my $u = LJ::get_authas_user($authas); - return 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); - - return "<?h1 $ML{'Error'} h1?><?p $ML{'.error.nointerests'} p?>" unless $fromu; - - my %uint; - - my %fromint; - my $fints = $fromu->get_interests(); - foreach (@$fints) { - $fromint{$_->[1]} = $_->[0]+0; - } - - return "<?h1 $ML{'Error'} h1?><?p $ML{'.error.nointerests'} p?>" unless %fromint; - - my $ret = "<?p <form method='get' action='interests'>"; - $ret .= LJ::html_hidden(mode => 'enmasse', fromuser => $fromu->{'user'}); - $ret .= LJ::make_authas_select($remote, { 'authas' => $GET{'authas'} }); - $ret .= "</form> p?><form method='post' action='interests$getextra'>"; - $ret .= "<?h1 $ML{'.enmasse.header'} h1?><?p "; - - if ( $u->equals( $fromu ) ) { - %uint = %fromint; - $ret .= $ML{'.enmasse.body.you'}; - } else { - my $in = join (",", map { $fromint{$_} } keys %fromint); - - my $uints = $u->get_interests(); - 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?><div style='margin-left: 40px; margin-top: 20px;'>"; - $ret .= "<table summary='' cellpadding='0' cellspacing='0' border='0' width='100%'>"; - my @fromintsorted = sort keys %fromint; - my $cols = 3; - my $rows = int((scalar(@fromintsorted) + $cols - 1) / $cols); - for (my $i = 0; $i < $rows; $i++) { - $ret .= "<tr valign='middle'>"; - for (my $j = 0; $j < $cols; $j++) { - my $index = $rows * $j + $i; - if ($index < scalar(@fromintsorted)) { - my $checked = $uint{$fromintsorted[$index]} ? 1 : undef; - $ret .= "<td align='left' nowrap='nowrap'>"; - $ret .= LJ::html_check({name => "int_$fromint{$fromintsorted[$index]}", - id => "int_$fromint{$fromintsorted[$index]}", - selected => $checked, - value => 1}); - my $bold1 = $checked ? "<strong>" : ""; - my $bold2 = $checked ? "</strong>" : ""; - $ret .= " <label for='int_$fromint{$fromintsorted[$index]}'>"; - $ret .= "$bold1$fromintsorted[$index]$bold2</label></td>"; - } else { - $ret .= "<td></td>"; - } - } - $ret .= "</tr>"; - } - $ret .= "</table></div>"; - - $ret .= LJ::html_hidden('mode', 'enmasse_do'); - $ret .= LJ::html_hidden('fromuser', $fromu->{'user'}); - $ret .= LJ::html_hidden('allintids', join (",", values %fromint)); - - $ret .= "<?h1 $ML{'.finished.header'} h1?><?p $ML{'.finished.about'} p?><?standout "; - $ret .= LJ::html_submit(undef, $ML{'.finished.save_button'}) . " standout?></form>"; - - return $ret; - } - - if ($did_post && $POST{'mode'} eq "enmasse_do") { - return "<?needlogin?>" unless $remote; - - my $authas = $GET{'authas'} || $remote->{'user'}; - my $u = LJ::get_authas_user($authas); - return LJ::bad_input($ML{'.error.noauth'}) unless $u; - - my @fromints = map { $_+0 } split (/\s*,\s*/, $POST{'allintids'}); - my $sync = $u->sync_interests( \%POST, @fromints ); - - my $ret = "<?h1 $ML{'.results.header'} h1?><?p "; - if ($sync->{deleted}) { - $ret .= $sync->{added} ? $ML{'.results.both'} - : $sync->{toomany} ? BML::ml('.results.del_and_toomany', {'intcount' => $maxinterests}) - : $ML{'.results.deleted'}; - } else { - $ret .= $sync->{added} ? $ML{'.results.added'} - : $sync->{toomany} ? BML::ml('.results.toomany', {'intcount' => $maxinterests}) - : $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?><?p " . BML::ml('.results.message2', {'aopts' => "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?>"; - return $ret; - } - - if ( ! $did_post && ( $GET{intid} || $GET{int} ) ) { - my $intid = $GET{intid} ? $GET{intid} : - LJ::get_sitekeyword_id( $GET{int}, 0 ); - my ( $interest, $intcount ) = LJ::get_interest( $intid ); - - my $check_int = $GET{int} || $interest; - if (LJ::Hooks::run_hook("interest_search_ignore", query => $check_int, intid => $intid)) { - return "<?h1 $ML{'Error'} h1?><?p $ML{'.error.ignored'} p?>"; - } - - my $e_int = LJ::ehtml( $check_int ); - - my $ret = ''; - - # 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 ) { - - # if the searched-for interest is too long, we use the short version from here on - my $e_int_long = $e_int; - $e_int = LJ::ehtml( $interest ? $interest : substr( $check_int, 0, LJ::CMAX_SITEKEYWORD ) ); - $ret .= "<?p " . BML::ml( '.error.longinterest', { sitename => $LJ::SITENAMESHORT, old_int => $e_int_long, new_int => $e_int, maxlen => LJ::CMAX_SITEKEYWORD } ) . " p?>"; - } - - $ret .= "<table summary=''>"; - $ret .= "<tr valign='middle'><td class='findandmodify'>$ML{'.interested.in'}</td>"; - $ret .= "<td class='findandmodify'><form method='get' action='interests'>"; - $ret .= LJ::html_text({name => 'int', size => 20, value => $interest || $e_int}) . " "; - $ret .= LJ::html_submit(undef, $ML{'.interested.btn.find'}); - $ret .= "</form></td></tr>"; - $ret .= "<tr valign='middle'><td class='findandmodify'>$ML{'.enmasse.intro'}</td>"; - $ret .= "<td class='findandmodify'><form method='get' action='interests'>"; - $ret .= LJ::html_text({name => 'fromuser', size => 20}) . " "; - $ret .= LJ::html_submit(undef, $ML{'.enmasse.btn'}); - $ret .= LJ::html_hidden('mode', 'enmasse'); - $ret .= "</form></td></tr>"; - $ret .= "</table>"; - - # no results - unless ( $interest ) { - $ret .= "<?h1 $ML{'.nocomms.header'} h1?><?p "; - $ret .= BML::ml( '.nocomms.text', { 'int' => $e_int, 'aopts' => qq(href="$LJ::SITEROOT/community/create") } ); - $ret .= " p?><?h1 $ML{'.nousers.header'} h1?><?p "; - $ret .= BML::ml( '.nousers.text2', { int => $e_int, aopts_add => "href='$LJ::SITEROOT/interests?mode=addnew&keyword=$e_int'", aopts_int => "href='$LJ::SITEROOT/interests'" } ); - $ret .= " p?>"; - return $ret; - } - - $intid += 0; - - ### hook - LJ::Hooks::run_hooks("interests_bml", { - 'intid' => $intid, - 'int' => $interest, - 'ret' => \$ret, - }); - - ### communities - my $dbr = LJ::get_db_reader(); - my $LIMIT = 500; - - my $int_query = sub { - my $i = shift; # comminterests or userinterests - my $q = "SELECT $i.userid FROM $i, userusage - WHERE $i.intid = ? AND $i.userid = userusage.userid - ORDER BY userusage.timeupdate DESC LIMIT $LIMIT"; - my $uref = $dbr->selectall_arrayref( $q, undef, $intid ); - return LJ::load_userids( map { $_->[0] } @$uref ); - # can't trust LJ::load_userids to maintain sort order - }; - - my $should_show = sub { - my $u = shift; - return $u->should_show_in_search_results( for => $remote ); - }; - - if ( LJ::is_enabled( 'interests-community' ) ) { - my $us = $int_query->( "comminterests" ); - my $updated = LJ::get_timeupdate_multi( keys %$us ); - 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::is_enabled('community_themes'); - - foreach (@cl) { - my $name = $_->{name}; - LJ::text_out(\$name); - $list .= "<li class='commname'>" . LJ::ljuser($_) . " - " . LJ::ehtml($name); - - $list .= " <small class='lastupdated'>("; - if ($updated->{$_->id} > 0) { - $list .= BML::ml( '.lastupdated.true', { 'time' => LJ::ago_text( time() - $updated->{$_->id} ) } ); - } else { - $list .= BML::ml( '.lastupdated.false' ); - } - $list .= ")</small>"; - - $list .= "<br /> <em>" . LJ::ehtml($_->prop("comm_theme")) . "</em>" - if $show_comm_promos && $_->prop("comm_theme"); - - $list .= "</li>"; - } - - if (@cl) { - $ret .= "<h1>" . BML::ml( ".communities.header", { interest => $e_int } ) ."</h1>"; - $ret .= "<p class='matches'><b>" . BML::ml('.matches2', {'num' => $count}) . "</b><ul class='contentlist'>$list</ul></p>"; - } - } - - ##### users - - $ret .= "<h1>" . BML::ml( ".users.header", { interest => $e_int } ) . "</h1>\n<p class='interestinfo'>"; - if ($remote) { - $ret .= " " . BML::ml('.addint2', {'aopts' => "href='$LJ::SITEROOT/interests?mode=add&intid=$intid'"}); - } - $ret .= " " . BML::ml('.morestuff2', {'aopts' => "href='$LJ::SITEROOT/interests'"}) . "</p>"; - - my $us = $int_query->( "userinterests" ); - 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 .= "<p class='matches'><b>" . BML::ml('.matches2', {'num' => scalar @ul}) . "</b></p>"; - - my $navbar; - my $results = LJ::user_search_display( - users => \@ul, - timesort => 1, - perpage => 50, - curpage => $GET{'page'} || 1, - navbar => \$navbar, - ); - - $ret .= "<div style='text-align: center'>$navbar</div><br />"; - $ret .= $results; - $ret .= "<div style='text-align: center; clear: both'>$navbar</div><br />"; - - return $ret; - } - - my $ret = ""; - $ret .= "<?p $ML{'.interests.text'} p?>"; - $ret .= "<table summary='' cellspacing='5' style='margin-top: 10px; margin-left: 30px; margin-bottom: 10px;'>"; - - if ( LJ::is_enabled('interests-popular') ) { - $ret .= "<tr valign='top'><td colspan='2'>"; - $ret .= "<a href=\"interests?view=popular\">$ML{'.interests.viewpop'}</a></td></tr>"; - } - - $ret .= "<tr valign='top'><td align='left'>$ML{'.interested.in'}</td>"; - $ret .= "<td><form method='get' action='interests'>"; - $ret .= LJ::html_text({name => 'int', size => 20}) . " "; - $ret .= LJ::html_submit(undef, $ML{'.interested.btn.find'}); - $ret .= "</form></td></tr>"; - - if ( LJ::is_enabled('interests-findsim') && $remote && $remote->can_find_similar ) { - $ret .= "<tr valign='top'><td>$ML{'.interests.findsim'}</td><td><form method='get' action='interests'>"; - $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 .= "</form></td></tr>"; - } - - $ret .= "<tr valign='top'><td>$ML{'.enmasse.intro'}</td>"; - $ret .= "<td><form method='get' action='interests'>"; - $ret .= LJ::html_text({name => 'fromuser', size => 20}) . " "; - $ret .= LJ::html_submit(undef, $ML{'.enmasse.btn'}); - $ret .= LJ::html_hidden('mode', 'enmasse'); - $ret .= "</form></td></tr>"; - - $ret .= "</table>"; - $ret .= BML::ml('.nointerests.text2', {'aopts' => "href='$LJ::SITEROOT/manage/profile/'"}); - - return $ret; -} -_code?> -<=body -page?> diff -r 11ed0d63e6fd -r 75f310215036 htdocs/interests.bml.text --- a/htdocs/interests.bml.text Fri Dec 17 01:58:35 2010 +0800 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,156 +0,0 @@ -;; -*- coding: utf-8 -*- -.add.added.head=Added. - -.add.added.editinterests=Edit your interests - -.add.added.editprofile=Edit your profile - -.add.added.interestspage=Return to the Interests page - -.add.added.viewprofile=View your profile - -.add.added.text=The interest has been added to your list. - -.add.btn.text=Add [[interest]] - -.add.confirm.head=Confirm - -.add.confirm.text=To add <strong>[[interest]]</strong> as an interest, click the button below. - -.add.toomany.head=Sorry... - -.add.toomany.text=You already have [[maxinterests]] interests defined. - -.addint2=If you're also interested in this, would you like to be <a [[aopts]]>added to this list</a>? - -.communities.header=Results for communities listing an interest in "[[interest]]" - -.count=Count - -.enmasse.body.other<< -Here are [[user]]'s interests. Select the interests you want -to add to your own and deselect the interests you want to remove. -When you're done, save your changes. -. - -.enmasse.body.other_authas<< -Here are [[user]]'s interests. Select the interests you want -to add to those of [[target]] and deselect the interests you want to remove. -When you're done, save your changes. -. - -.enmasse.body.you<< -Deselect the interests you want to remove. -When you're done, save your changes. -. - -.enmasse.btn=Show List - -.enmasse.header=Add/Remove interests - -.enmasse.intro=Modify your interests based on those of: - -.error.ignored=Sorry, we're unable to help you find users matching the interests you've provided. - -.error.longinterest=As [[sitename]] does not support interests longer than [[maxlen]] characters, your search for <b>[[old_int]]</b> was converted into a search for <b>[[new_int]]</b> instead. - -.error.nodata=Sorry, interest data currently unavailable. - -.error.nointerests=The selected account hasn't specified any interests. - -.findsim_do.account.notallowed=Your account type doesn't let you use this tool. - -.findsim_do.magic=Magic<br />Index - -.findsim_do.magic.head=What's this Magic Index all about? - -.findsim_do.magic.text=We compute a magic index for each matching account. A magic index is a weighting of two factors: the raw number of shared interests and extra points for shared uncommon interests. - -.findsim_do.nomatch.head=No Matches - -.findsim_do.nomatch.text=Nobody similar to [[user]]. - -.findsim_do.notdefined=[[user]] has no interests defined. - -.findsim_do.similar.head=Similar People - -.findsim_do.similar.text=The following people are the most related to [[user]] - -.findsim_do.user=People - -.finished.about=When you're done, save your changes. - -.finished.header=Done? - -.finished.save_button=Save Changes - -.interest=Interest - -.interested.btn.find=Find - -.interested.in=Find people interested in: - -.interests.findsim=Find people or communities with interests similar to those of: - -.interests.head=Interests - -.interests.text=Here are some fun things you can do with interests: - -.interests.viewpop=View popular interests - -.lastupdated.false=Never updated - -.lastupdated.true=Updated [[time]] - -.matches2=[[num]] [[?num|match|matches]]: - -.morestuff2=You can find more fun stuff on the <a [[aopts]]>interests page</a>. - -.nocomms.header=Relevant communities - -.nocomms.text=There are no communities interested in "<b>[[int]]</b>." You can <a [[aopts]]>create one</a>! - -.nointerests.text2=If you don't have any interests listed, you can add some by going to the <a [[aopts]]>Edit Personal Information</a> page. - -.nousers.header=Interested users - -.nousers.text2=There are no users interested in "<b>[[int]]</b>". If you are interested in this, <a [[aopts_add]]>click here to add the interest to your profile</a>. More fun stuff can be found on the <a [[aopts_int]]>interests page</a>. - -.popular.disabled=The popular interests feature is unavailable. - -.popular.head=Popular Interests - -.popular.text=Here are the most popular interests. - -.popular.textmode=<a [[aopts]]>View as a table</a>. - -.results.added=You've successfully added the selected interests to your interests list. - -.results.both=Success. You've successfully added the selected interests to your interests list and removed those you deselected. - -.results.deleted=You successfully removed the interests you deselected from your interests list. - -.results.del_and_toomany<< -You successfully removed the interests you deselected, but you didn't add -any new interests because you can only list a maximum of [[intcount]] -interests. You may wish to go back and select fewer interests to add or -delete some old interests. -. - -.results.goback2=Return to [[user]]'s <a [[aopts]]>profile</a>. - -.results.header=Results - -.results.message2=Return to your revised <a [[aopts]]>profile page</a>. - -.results.nothing=You didn't make any changes. - -.results.toomany<< -You didn't add any of your selected interests because you can only list -a maximum of [[intcount]] interests. You may wish to go back and select -fewer interests to add or delete some old interests. -. - -.title=Interests - -.users.header=Results for people interested in "[[interest]]" diff -r 11ed0d63e6fd -r 75f310215036 views/interests/add.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/add.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,47 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +[%- IF need_post -%] + <h1>[% '.add.confirm.head' | ml %]</h1> + <p>[% '.add.confirm.text' | ml(interest = need_post.int) %] + <form method='post' action='interests'><div align='center'> + [%- dw.form_auth %] + <input type='hidden' name='mode' value='add' /> + <input type='hidden' name='intid' value='[% need_post.intid %]' /> + <input type='submit' value='[% ".add.btn.text" | ml(interest = need_post.int) %]' /> + </div></form></p> +[%- ELSE -%] + <h1>[% '.add.added.head' | ml %]</h1> + <p>[% '.add.added.text' | ml %]</p> + <ul> + <li><a href='[% roots.site %]/interests'> + [%- '.add.added.interestspage' | ml %]</a></li> + <li><a href='[% roots.site %]/manage/profile/#interests'> + [%- '.add.added.editinterests' | ml %]</a></li> + <li><a href='[% remote.profile_url %]'> + [%- '.add.added.viewprofile' | ml %]</a></li> + <li><a href='[% roots.site %]/manage/profile'> + [%- '.add.added.editprofile' | ml %]</a></li> + </ul> +[%- END -%] diff -r 11ed0d63e6fd -r 75f310215036 views/interests/add.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/add.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,20 @@ +;; -*- coding: utf-8 -*- +.add.added.head=Added. + +.add.added.editinterests=Edit your interests + +.add.added.editprofile=Edit your profile + +.add.added.interestspage=Return to the Interests page + +.add.added.text=The interest has been added to your list. + +.add.added.viewprofile=View your profile + +.add.btn.text=Add [[interest]] + +.add.confirm.head=Confirm + +.add.confirm.text=To add <strong>[[interest]]</strong> as an interest, click the button below. + +.title=Interests diff -r 11ed0d63e6fd -r 75f310215036 views/interests/enmasse.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/enmasse.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,62 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +<form method='get' action='interests'> +<input type='hidden' name='mode' value='enmasse' /> +<input type='hidden' name='fromuser' value='[% fromu.user %]' /> +[% authas_html %]</form> +<form method='post' action='interests[% getextra %]'> +[%- dw.form_auth %] +<h1>[% '.enmasse.header' | ml %]</h1> +<p>[% enmasse_body | ml(user = fromu.ljuser_display, + target = u.ljuser_display) %]</p> +<div style='margin-left: 40px; margin-top: 20px;'> +<table summary='' cellpadding='0' cellspacing='0' border='0' width='100%'> +[%- USE table(enmasse_data, cols=3) -%] +[%- FOREACH rows = table.rows %] +<tr valign='middle'> + [%- FOREACH cell = rows -%] + [%- IF cell.int -%] + <td align='left' nowrap='nowrap'> + <input type='checkbox' [% IF cell.is_checked %] checked='checked' [% END %] + name='[% cell.checkid %]' id='[% cell.checkid %]' value='1' /> + <label for='[% cell.checkid %]'> + [%- IF cell.is_checked %] <strong> [% END -%] + [%- cell.int -%] + [%- IF cell.is_checked %] </strong> [% END -%] + </label></td> + [%- ELSE -%] + <td></td> + [%- END -%] + [%- END -%] +</tr> +[%- END -%] +</table></div> +<input type='hidden' name='mode' value='enmasse_do' /> +<input type='hidden' name='fromuser' value='[% fromu.user %]' /> +<input type='hidden' name='allintids' value='[% allintids %]' /> +<h1>[% '.finished.header' | ml %]</h1><p>[% '.finished.about' | ml %]</p> +<div class='standout'><table summary='' class='standout-inner'><tr><td> +<input type='submit' value='[% ".finished.save_button" | ml %]' /> +</td></tr></table></div></form> diff -r 11ed0d63e6fd -r 75f310215036 views/interests/enmasse.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/enmasse.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,27 @@ +;; -*- coding: utf-8 -*- +.enmasse.body.other<< +Here are [[user]]'s interests. Select the interests you want +to add to your own and deselect the interests you want to remove. +When you're done, save your changes. +. + +.enmasse.body.other_authas<< +Here are [[user]]'s interests. Select the interests you want +to add to those of [[target]] and deselect the interests you want to remove. +When you're done, save your changes. +. + +.enmasse.body.you<< +Deselect the interests you want to remove. +When you're done, save your changes. +. + +.enmasse.header=Add/Remove interests + +.finished.about=When you're done, save your changes. + +.finished.header=Done? + +.finished.save_button=Save Changes + +.title=Interests diff -r 11ed0d63e6fd -r 75f310215036 views/interests/enmasse_do.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/enmasse_do.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,32 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +<h1>[% '.results.header' | ml %]</h1> +<p>[% enmasse_do_result | ml(intcount = $toomany) %]</p> +<p>[% '.results.message2' | ml(aopts = "href='$u.profile_url'") %] +[%- IF fromu -%] + [% '.results.goback2' | ml(user = fromu.ljuser_display, + aopts = "href='$fromu.profile_url'") %] +[%- END -%] +</p> diff -r 11ed0d63e6fd -r 75f310215036 views/interests/enmasse_do.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/enmasse_do.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,8 @@ +;; -*- coding: utf-8 -*- +.results.goback2=Return to [[user]]'s <a [[aopts]]>profile</a>. + +.results.header=Results + +.results.message2=Return to your revised <a [[aopts]]>profile page</a>. + +.title=Interests diff -r 11ed0d63e6fd -r 75f310215036 views/interests/findsim.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/findsim.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,41 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +<h1>[% '.findsim_do.similar.head' | ml %]</h1> +<p>[% ".findsim_do.similar.text" | ml(user = findsim_u.ljuser_display) %]</p> +<p><table cellpadding='3'><tr valign='bottom'> + <th>#</th> + <th width='250'>[% 'username' | ml %]</th> + <th>[% '.findsim_do.magic' | ml %]</th> +</tr> +[%- FOREACH findsim_data -%] + <tr> + <td>[% count %]</td> + <td>[% user %]</td> + <td>[% magic %]</td> + </tr> +[%- END -%] +</table></p> +<h1>[% '.findsim_do.magic.head' | ml %]</h1> +<p> [% '.findsim_do.magic.text' | ml %]</p> diff -r 11ed0d63e6fd -r 75f310215036 views/interests/findsim.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/findsim.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,12 @@ +;; -*- coding: utf-8 -*- +.findsim_do.magic=Magic<br />Index + +.findsim_do.magic.head=What's this Magic Index all about? + +.findsim_do.magic.text=We compute a magic index for each matching account. A magic index is a weighting of two factors: the raw number of shared interests and extra points for shared uncommon interests. + +.findsim_do.similar.head=Similar People + +.findsim_do.similar.text=The following people are the most related to [[user]] + +.title=Interests diff -r 11ed0d63e6fd -r 75f310215036 views/interests/index.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/index.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,57 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +<p>[% '.interests.text' | ml %]</p> +<table summary='' cellspacing='5' style='margin-top: 10px; margin-left: 30px; margin-bottom: 10px;'> + +[%- IF can_use_popular -%] +<tr valign='top'><td colspan='2'> +<a href="interests?view=popular">[% '.interests.viewpop' | ml %]</a> +</td></tr> +[%- END -%] + +<tr valign='top'><td align='left'>[% 'interests.interested.in' | ml %]</td> +<td><form method='get' action='interests'> +<input type="text" name="int" size="20" /> +<input type='submit' value='[% "interests.interested.btn" | ml %]' /> +</form></td></tr> + +[%- IF can_use_findsim -%] +<tr valign='top'><td>[% '.interests.findsim' | ml %]</td><td> +<form method='get' action='interests'> +<input type='hidden' name='mode' value='findsim_do' /> +<input type="text" name="user" size="20" value="[% remote.user %]" /> +<input type='submit' value='[% "interests.interested.btn" | ml %]' /> +</form></td></tr> +[%- END -%] + +<tr valign='top'><td>[% 'interests.enmasse.intro' | ml %]</td><td> +<form method='get' action='interests'> +<input type='hidden' name='mode' value='enmasse' /> +<input type="text" name="fromuser" size="20" /> +<input type='submit' value='[% "interests.enmasse.btn" | ml %]' /> +</form></td></tr> + +</table> +[% '.nointerests.text2' | ml(aopts = "href='$roots.site/manage/profile/'") %] diff -r 11ed0d63e6fd -r 75f310215036 views/interests/index.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/index.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,10 @@ +;; -*- coding: utf-8 -*- +.interests.findsim=Find people or communities with interests similar to those of: + +.interests.text=Here are some fun things you can do with interests: + +.interests.viewpop=View popular interests + +.nointerests.text2=If you don't have any interests listed, you can add some by going to the <a [[aopts]]>Edit Personal Information</a> page. + +.title=Interests diff -r 11ed0d63e6fd -r 75f310215036 views/interests/int.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/int.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,80 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +[%- IF warn_toolong %]<p>[% warn_toolong %]</p>[% END -%] +<table summary=''><tr valign='middle'><td class='findandmodify'> +[% 'interests.interested.in' | ml %]</td><td class='findandmodify'> +<form method='get' action='interests'> +<input type="text" name="int" size="20" value=" +[%- interest ? interest : e_int %]" /> +<input type='submit' value='[% "interests.interested.btn" | ml %]' /> +</form></td></tr> +<tr valign='middle'><td class='findandmodify'> +[% 'interests.enmasse.intro' | ml %]</td><td class='findandmodify'> +<form method='get' action='interests'> +<input type='hidden' name='mode' value='enmasse' /> +<input type="text" name="fromuser" size="20" /> +<input type='submit' value='[% "interests.enmasse.btn" | ml %]' /> +</form></td></tr></table> +[%- IF intcount -%] + [%- IF int_comms.count -%] + <h1>[% ".communities.header" | ml(interest = e_int) %]</h1> + <p class='matches'><b>[% '.matches2' | ml(num = int_comms.count) %]</b> + <ul class='contentlist'> + [%- FOREACH int_comms.data -%] + <li class='commname'>[% u.ljuser_display %] - [% u.name_html %] + <small class='lastupdated'>( + [%- IF updated; '.lastupdated.true' | ml(time = updated) -%] + [%- ELSE; '.lastupdated.false' | ml; END -%] + )</small> + [%- IF theme -%] + <br /> <em>[% theme %]</em> + [%- END -%] + </li> + [%- END -%] + </ul></p> + [%- ELSE -%] + <h1>[% '.nocomms.header' | ml %]</h1><p> + [%- '.nocomms.text' | ml(aopts = "href='$roots.site/community/create'", + int = interest) %]</p> + [%- END -%] + <h1>[% ".users.header" | ml(interest = e_int) %]</h1> + <p class='interestinfo'> + [%- IF remote -%] + [%- '.addint2' | ml(aopts = "href='$roots.site/interests?mode=add&intid=$intid'") -%] + [%- END -%] + [% '.morestuff2' | ml(aopts = "href='$roots.site/interests'") %]</p> + <p class='matches'><b>[% '.matches2' | ml(num = int_users.count) %]</b></p> + <div style='text-align: center'>[% int_users.navbar %]</div><br /> + [% int_users.results %] + <div style='text-align: center; clear: both'>[% int_users.navbar %]</div><br /> +[%- ELSE -%] + <h1>[% '.nocomms.header' | ml %]</h1><p> + [%- '.nocomms.text' | ml(aopts = "href='$roots.site/community/create'", + int = e_int) %]</p> + <h1>[% '.nousers.header' | ml %]</h1><p> + [%- '.nousers.text2' | ml(int = e_int, + aopts_add = "href='$roots.site/interests?mode=addnew&keyword=$e_int'", + aopts_int = "href='$roots.site/interests'") %]</p> +[%- END -%] diff -r 11ed0d63e6fd -r 75f310215036 views/interests/int.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/int.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,24 @@ +;; -*- coding: utf-8 -*- +.addint2=If you're also interested in this, would you like to be <a [[aopts]]>added to this list</a>? + +.communities.header=Results for communities listing an interest in "[[interest]]" + +.lastupdated.false=Never updated + +.lastupdated.true=Updated [[time]] + +.matches2=[[num]] [[?num|match|matches]]: + +.morestuff2=You can find more fun stuff on the <a [[aopts]]>interests page</a>. + +.nocomms.header=Relevant communities + +.nocomms.text=There are no communities interested in "<b>[[int]]</b>." You can <a [[aopts]]>create one</a>! + +.nousers.header=Interested users + +.nousers.text2=There are no users interested in "<b>[[int]]</b>". If you are interested in this, <a [[aopts_add]]>click here to add the interest to your profile</a>. More fun stuff can be found on the <a [[aopts_int]]>interests page</a>. + +.title=Interests + +.users.header=Results for people interested in "[[interest]]" diff -r 11ed0d63e6fd -r 75f310215036 views/interests/popular.tt --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/popular.tt Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,46 @@ +[%# 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'. + # +%] + +[%- sections.head = BLOCK %] +<style type='text/css'> + div.tagcloud a { text-decoration: none; } + ul.contentlist li { padding-bottom: 3px; } +</style> +[% END -%] + +[%- dw.need_res( 'stc/interests.css' ) -%] + +[%- sections.title='.title' | ml -%] + +<h1>[% '.popular.head' | ml %]</h1><p>[% '.popular.text' | ml %] +[%- IF no_text_mode -%] + [% '.popular.textmode' + | ml(aopts = "href='$roots.site/interests?view=popular&mode=text'") %] +[%- END -%] +</p> +[%- IF pop_ints -%] + [%- IF no_text_mode; pop_cloud; ELSE -%] + <p><table><tr> + <th width='150' style="text-align: left"> + [% '.interest' | ml %]</th> + <th>[% '.count' | ml %]</th> + </tr> + [%- FOREACH i = pop_ints -%] + <tr> + <td><a href='[% i.url | url %]'>[% i.eint %]</a></td> + <td>[% i.value %]</td> + </tr> + [%- END -%] + </table></p> + [%- END -%] +[%- ELSE; '.error.nodata' | ml; END -%] diff -r 11ed0d63e6fd -r 75f310215036 views/interests/popular.tt.text --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/views/interests/popular.tt.text Fri Dec 17 02:17:18 2010 +0800 @@ -0,0 +1,14 @@ +;; -*- coding: utf-8 -*- +.count=Count + +.error.nodata=Sorry, interest data currently unavailable. + +.interest=Interest + +.popular.head=Popular Interests + +.popular.text=Here are the most popular interests. + +.popular.textmode=<a [[aopts]]>View as a table</a>. + +.title=Interests --------------------------------------------------------------------------------