fu: Close-up of Fu, bringing a scoop of water to her mouth (Default)
fu ([personal profile] fu) wrote in [site community profile] changelog2010-12-16 06:17 pm

[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 [personal profile] kareila.

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 .= "&nbsp;<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}) . "&nbsp;";
-        $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}) . "&nbsp;";
-        $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&amp;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 />&nbsp;&nbsp;&nbsp;<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&amp;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}) . "&nbsp;";
-    $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}) . "&nbsp;";
-        $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}) . "&nbsp;";
-    $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" />&nbsp;
+<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 %]" />&nbsp;
+<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" />&nbsp;
+<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 %]" />&nbsp;
+<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" />&nbsp;
+<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 />&nbsp;&nbsp;&nbsp;<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&amp;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&amp;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
--------------------------------------------------------------------------------