More refactoring. Make sure icons are sorted by upload order.

        Patch by kareila. 

diffs (948 lines):

diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/Apache/LiveJournal.pm
--- a/cgi-bin/Apache/LiveJournal.pm     Wed Sep 08 15:10:03 2010 +0800
+++ b/cgi-bin/Apache/LiveJournal.pm     Wed Sep 08 15:46:13 2010 +0800
@@ -40,6 +40,7 @@ use LJ::URI;
 use LJ::URI;
 use DW::Routing;
 use DW::Template;
+use LJ::Talk;
 
 BEGIN {
     $LJ::OPTMOD_ZLIB = eval "use Compress::Zlib (); 1;";
@@ -1137,7 +1138,7 @@ sub userpic_content
     return NOT_FOUND unless $u && ! ( $u->is_expunged || $u->is_suspended );
 
     my %upics;
-    LJ::load_userpics(\%upics, [ $u, $picid ]);
+    LJ::Talk::load_userpics(\%upics, [ $u, $picid ]);
     my $pic = $upics{$picid} or return NOT_FOUND;
     return NOT_FOUND if $pic->{'userid'} != $userid || $pic->{state} eq 'X';
 
diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/LJ/Talk.pm
--- a/cgi-bin/LJ/Talk.pm        Wed Sep 08 15:10:03 2010 +0800
+++ b/cgi-bin/LJ/Talk.pm        Wed Sep 08 15:46:13 2010 +0800
@@ -1168,10 +1168,103 @@ sub load_comments
                 $post->{'picid'} = $id;
                 push @load_pic, [ $pu, $id ];
             }
-            LJ::load_userpics($opts->{'userpicref'}, \...@load_pic);
+            load_userpics( $opts->{'userpicref'}, \...@load_pic );
         }
     }
     return map { $posts->{$_} } @top_replies;
+}
+
+# <LJFUNC>
+# name: LJ::Talk::load_userpics
+# des: Loads a bunch of userpics at once.
+# args: dbarg?, upics, idlist
+# des-upics: hashref to load pictures into, keys being the picids.
+# des-idlist: [$u, $picid] or [[$u, $picid], [$u, $picid], +] objects
+#             also supports deprecated old method, of an array ref of picids.
+# </LJFUNC>
+sub load_userpics {
+    my ($upics, $idlist) = @_;
+
+    return undef unless ref $idlist eq 'ARRAY' && $idlist->[0];
+
+    # $idlist needs to be an arrayref of arrayrefs,
+    # HOWEVER, there's a special case where it can be
+    # an arrayref of 2 items:  $u (which is really an arrayref)
+    # as well due to 'fields' and picid which is an integer.
+    #
+    # [$u, $picid] needs to map to [[$u, $picid]] while allowing
+    # [[$u1, $picid1], [$u2, $picid2], [etc...]] to work.
+    if (scalar @$idlist == 2 && ! ref $idlist->[1]) {
+        $idlist = [ $idlist ];
+    }
+
+    my @load_list;
+    foreach my $row (@{$idlist})
+    {
+        my ($u, $id) = @$row;
+        next unless ref $u;
+
+        if ($LJ::CACHE_USERPIC{$id}) {
+            $upics->{$id} = $LJ::CACHE_USERPIC{$id};
+        } elsif ($id+0) {
+            push @load_list, [$u, $id+0];
+        }
+    }
+    return unless @load_list;
+
+    if (@LJ::MEMCACHE_SERVERS) {
+        my @mem_keys = map { [$_->[1],"userpic.$_->[1]"] } @load_list;
+        my $mem = LJ::MemCache::get_multi(@mem_keys) || {};
+        while (my ($k, $v) = each %$mem) {
+            next unless $v && $k =~ /(\d+)/;
+            my $id = $1;
+            $upics->{$id} = LJ::MemCache::array_to_hash("userpic", $v);
+        }
+        @load_list = grep { ! $upics->{$_->[1]} } @load_list;
+        return unless @load_list;
+    }
+
+    my %db_load;
+    foreach my $row (@load_list) {
+        # ignore users on clusterid 0
+        next unless $row->[0]->{clusterid};
+
+        push @{$db_load{$row->[0]->{clusterid}}}, $row;
+    }
+
+    foreach my $cid (keys %db_load) {
+        my $dbcr = LJ::get_cluster_def_reader($cid);
+        unless ($dbcr) {
+            print STDERR "Error: LJ::Talk::load_userpics unable to get handle; 
cid = $cid\n";
+            next;
+        }
+
+        my (@bindings, @data);
+        foreach my $row (@{$db_load{$cid}}) {
+            push @bindings, "(userid=? AND picid=?)";
+            push @data, ($row->[0]->{userid}, $row->[1]);
+        }
+        next unless @data && @bindings;
+
+        my $sth = $dbcr->prepare("SELECT userid, picid, width, height, fmt, 
state, ".
+                                 "       UNIX_TIMESTAMP(picdate) AS 'picdate', 
location, flags ".
+                                 "FROM userpic2 WHERE " . join(' OR ', 
@bindings));
+        $sth->execute(@data);
+
+        while (my $ur = $sth->fetchrow_hashref) {
+            my $id = delete $ur->{'picid'};
+            $upics->{$id} = $ur;
+
+            # force into numeric context so they'll be smaller in memcache:
+            foreach my $k (qw(userid width height flags picdate)) {
+                $ur->{$k} += 0;
+            }
+            $ur->{location} = uc(substr($ur->{location}, 0, 1));
+
+            $LJ::CACHE_USERPIC{$id} = $ur;
+            LJ::MemCache::set([$id,"userpic.$id"], 
LJ::MemCache::hash_to_array("userpic", $ur));
+        }
+    }
 }
 
 # XXX these strings should be in talk, but moving them means we have
diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/LJ/Userpic.pm
--- a/cgi-bin/LJ/Userpic.pm     Wed Sep 08 15:10:03 2010 +0800
+++ b/cgi-bin/LJ/Userpic.pm     Wed Sep 08 15:46:13 2010 +0800
@@ -125,17 +125,10 @@ sub new_from_md5 {
 
 sub preload_default_userpics {
     my ($class, @us) = @_;
-    my %upics;
-    LJ::load_userpics(\%upics, [
-                                map { [ $_, $_->{defaultpicid} ] }
-                                grep { $_->{defaultpicid} }
-                                @us
-                                ]);
+
     foreach my $u (@us) {
-        my $up = $u->userpic       or next;
-        my $row = $upics{$up->id}  or next;
-        $row->{picid} = $up->id;
-        $up->absorb_row($row);
+        my $up = $u->userpic or next;
+        $up->load_row;
     }
 }
 
@@ -160,8 +153,7 @@ sub new_from_keyword
 # instance methods
 
 sub valid {
-    my $self = shift;
-    return defined $self->state;
+    return defined $_[0]->state;
 }
 
 sub absorb_row {
@@ -209,35 +201,35 @@ sub inactive {
 }
 
 sub state {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{state} if defined $self->{state};
     $self->load_row;
     return $self->{state};
 }
 
 sub comment {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{comment} if exists $self->{comment};
     $self->load_row;
     return $self->{comment};
 }
 
 sub description {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{description} if exists $self->{description};
     $self->load_row;
     return $self->{description};
 }
 
 sub width {
-    my $self = shift;
+    my $self = $_[0];
     my @dims = $self->dimensions;
     return undef unless @dims;
     return $dims[0];
 }
 
 sub height {
-    my $self = shift;
+    my $self = $_[0];
     my @dims = $self->dimensions;
     return undef unless @dims;
     return $dims[1];
@@ -251,19 +243,18 @@ sub flags {
 }
 
 sub md5base64 {
-    my $self = shift;
-    return $self->{md5base64};
+    return $_[0]->{md5base64};
 }
 
 sub extension {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{_ext} if $self->{_ext};
     $self->load_row;
     return $self->{_ext};
 }
 
 sub location {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{location} if $self->{location};
     $self->load_row;
     return $self->{location};
@@ -271,7 +262,7 @@ sub location {
 
 # returns (width, height)
 sub dimensions {
-    my $self = shift;
+    my $self = $_[0];
 
     # width and height probably loaded from DB
     return ($self->{width}, $self->{height}) if ($self->{width} && 
$self->{height});
@@ -289,7 +280,7 @@ sub max_allowed_bytes {
 
 # Returns the direct link to the uploaded userpic
 sub url {
-    my $self = shift;
+    my $self = $_[0];
 
     if (my $hook_path = LJ::Hooks::run_hook('construct_userpic_url', $self)) {
         return $hook_path;
@@ -303,7 +294,7 @@ sub url {
 # FIXME: Is this ever used? If not, should be deleted. If so,
 # should be renamed to source_url
 sub fullurl {
-    my $self = shift;
+    my $self = $_[0];
     return $self->{url} if $self->{url};
     $self->load_row;
     return $self->{url};
@@ -333,8 +324,7 @@ sub alttext {
 # optional parameters (which must be explicitly passed) include
 # width, keyword, and user (object)
 sub imgtag {
-    my $self = shift;
-    my %opts = @_;
+    my ( $self, %opts ) = @_;
 
     # if the width and keyword have been passed in  as explicit
     # parameters, set them. Otherwise, take what ever is set in
@@ -368,22 +358,22 @@ sub imgtag {
 
 # FIXME: should have alt text, if it should be kept
 sub imgtag_lite {
-    my $self = shift;
+    my $self = $_[0];
     return '<img src="' . $self->url . '" width="' . $self->width . '" 
height="' . $self->height .
         '" class="userpic-img" />';
 }
 
 # FIXME: should have alt text, if it should be kept
 sub imgtag_nosize {
-    my $self = shift;
+    my $self = $_[0];
     return '<img src="' . $self->url . '" class="userpic-img" />';
 }
 
 # pass the decimal version of a percentage that you want to shrink/increase 
the userpic by
 # default is 50% of original size
 sub imgtag_percentagesize {
-    my $self = shift;
-    my $percentage = shift || 0.5;
+    my ( $self, $percentage ) = @_;
+    $percentage ||= 0.5;
 
     my $width = int($self->width * $percentage);
     my $height = int($self->height * $percentage);
@@ -395,8 +385,7 @@ sub imgtag_percentagesize {
 # must include either a height or width, if both are given the smaller of the 
two is used
 # returns the width and height attributes as a string to insert into an img tag
 sub img_fixedsize {
-    my $self = shift;
-    my %opts = @_;
+    my ( $self, %opts ) = @_;
 
     my $width = $opts{width} || 0;
     my $height = $opts{height} || 0;
@@ -422,8 +411,7 @@ sub img_fixedsize {
 # in list context returns list of keywords ( (pic#12345) if none defined )
 # opts: 'raw' = return '' instead of 'pic#12345'
 sub keywords {
-    my $self = shift;
-    my %opts = @_;
+    my ( $self, %opts ) = @_;
 
     my $raw = delete $opts{raw} || undef;
 
@@ -450,47 +438,41 @@ sub keywords {
 }
 
 sub imagedata {
-    my $self = shift;
+    my $self = $_[0];
 
-    my %upics;
+    $self->load_row or return undef;
     my $u = $self->owner;
-    LJ::load_userpics(\%upics, [ $u, $self->{picid} ]);
-    my $pic = $upics{$self->{picid}} or
-        return undef;
 
-    return undef if $pic->{'userid'} != $self->{userid} || $pic->{state} eq 
'X';
+    return undef if $self->state eq 'X';
 
-    if ($pic->{location} eq "M") {
-        my $key = $u->mogfs_userpic_key( $self->{picid} );
+    # check mogile
+    if ( $self->location eq "M" ) {
+        my $key = $u->mogfs_userpic_key( $self->picid );
         my $data = LJ::mogclient()->get_file_data( $key );
         return $$data;
     }
 
-    my %MimeTypeMapd6 = (
-                         'G' => 'gif',
-                         'J' => 'jpg',
-                         'P' => 'png',
-                         );
-
+    # check blobserver
     my $data;
     if ($LJ::USERPIC_BLOBSERVER) {
-        my $fmt = $MimeTypeMapd6{ $pic->{fmt} };
-        $data = LJ::Blob::get($u, "userpic", $fmt, $self->{picid});
+        my $fmt = $self->extension;
+        $data = LJ::Blob::get( $u, "userpic", $fmt, $self->picid );
         return $data if $data;
     }
 
+    # check userpicblob2 table
     my $dbb = LJ::get_cluster_reader($u)
         or return undef;
 
-    $data = $dbb->selectrow_array("SELECT imagedata FROM userpicblob2 WHERE ".
-                                  "userid=? AND picid=?", undef, 
$self->{userid},
-                                  $self->{picid});
+    $data = $dbb->selectrow_array( "SELECT imagedata FROM userpicblob2 WHERE ".
+                                   "userid=? AND picid=?", undef, 
$self->userid,
+                                   $self->picid );
     return $data ? $data : undef;
 }
 
 # get : class :: load_row : object
 sub load_row {
-    my $self = shift;
+    my $self = $_[0];
 
     # use class method
     return $self->get( $self->owner, $self->picid );
@@ -500,8 +482,7 @@ sub load_row {
 # returns: undef if nothing in cache
 #          arrayref of LJ::Userpic instances if found in cache
 sub get_cache {
-    my $class = shift;
-    my $u = shift;
+    my ( $class, $u ) = @_;
 
     # check request cache first!
     # -- this gets populated when a ->load_user_userpics call happens,
@@ -537,9 +518,7 @@ sub memkey {
 }
 
 sub set_cache {
-    my $class = shift;
-    my $u = shift;
-    my $rows = shift;
+    my ( $class, $u, $rows ) = @_;
 
     my $memkey = $class->memkey( $u );
     my @vals = map { LJ::MemCache::hash_to_array( 'userpic2', $_ ) } @$rows;
@@ -567,7 +546,7 @@ sub load_user_userpics {
     die "Error loading userpics: clusterid=$u->{clusterid}, errstr=" . 
$u->errstr
         if $u->err;
 
-    my @ret = values %$data;
+    my @ret = sort { $a->{picid} <=> $b->{picid} } values %$data;
 
     # set cache if reasonable
     $class->set_cache($u, \...@ret);
@@ -587,7 +566,7 @@ sub create {
     croak("Unknown options: " . join(", ", scalar keys %opts)) if %opts;
 
     my $err = sub {
-        my $msg = shift;
+        my $msg = $_[0];
     };
 
     eval "use Image::Size;";
@@ -794,23 +773,17 @@ sub _get_upf_scaled
 
     # converts an ImageMagick object to the form returned to our callers
     my $imageParams = sub {
-        my $im = shift;
+        my $im = $_[0];
         my $blob = $im->ImageToBlob;
         return [\$blob, $im->Get('MIME'), $im->Get('width'), 
$im->Get('height')];
     };
 
     # compute new width and height while keeping aspect ratio
     my $getSizedCoords = sub {
-        my $newsize = shift;
+        my ( $newsize, $img ) = @_;
 
-        my $fromw = $ow;
-        my $fromh = $oh;
-
-        my $img = shift;
-        if ($img) {
-            $fromw = $img->Get('width');
-            $fromh = $img->Get('height');
-        }
+        my $fromw = $img ? $img->Get('width') : $ow;
+        my $fromh = $img ? $img->Get('height') : $oh;
 
         return (int($newsize * $fromw/$fromh), $newsize) if $fromh > $fromw;
         return ($newsize, int($newsize * $fromh/$fromw));
@@ -931,7 +904,7 @@ sub delete_cache {
 # delete this userpic
 # TODO: error checking/throw errors on failure
 sub delete {
-    my $self = shift;
+    my $self = $_[0];
     local $LJ::THROW_ERRORS = 1;
 
     my $fail = sub {
@@ -1103,9 +1076,7 @@ sub set_keywords {
 # of existing pics is done asynchonously via TheSchwartz using the
 # DW::Worker::UserpicRenameWorker.
 sub set_and_rename_keywords {
-    my $self = shift;
-    my $new_keyword_string = $_[0];
-    my $orig_keyword_string = $_[1];
+    my ( $self, $new_keyword_string, $orig_keyword_string ) = @_;
 
     my $sclient = LJ::theschwartz();
     
@@ -1255,17 +1226,17 @@ sub fields      { qw(userpic lost); }
 sub fields      { qw(userpic lost); }
 
 sub number_lost {
-    my $self = shift;
+    my $self = $_[0];
     return scalar @{ $self->field("lost") };
 }
 
 sub lost_keywords_as_html {
-    my $self = shift;
+    my $self = $_[0];
     return join(", ", map { LJ::ehtml($_) } @{ $self->field("lost") });
 }
 
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     my $num_words = $self->number_lost;
     return BML::ml("/editicons.bml.error.toomanykeywords", {
         numwords => $self->number_lost,
@@ -1278,7 +1249,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(size max); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml('/editicons.bml.error.filetoolarge',
                    { 'maxsize' => $self->{'max'} .
                          BML::ml('/editicons.bml.kilobytes')} );
@@ -1288,7 +1259,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(w h); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml('/editicons.bml.error.imagetoolarge', {
         imagesize => $self->{'w'} . 'x' . $self->{'h'}
         });
@@ -1298,7 +1269,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(type); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml("/editicons.bml.error.unsupportedtype",
                           { 'filetype' => $self->{'type'} });
 }
@@ -1307,7 +1278,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(origkw newkw); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml("/editicons.bml.error.rename.mismatchedlength",
                           { 'origkw' => $self->{'origkw'},
                             'newkw' => $self->{'newkw'} });
@@ -1317,7 +1288,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(origkw newkw); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml("/editicons.bml.error.rename.blankkw",
                           { 'origkw' => $self->{'origkw'},
                             'newkw' => $self->{'newkw'} });
@@ -1327,7 +1298,7 @@ sub user_caused { 1 }
 sub user_caused { 1 }
 sub fields      { qw(keyword); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml("/editicons.bml.error.rename.keywordexists",
                           { 'keyword' => $self->{'keyword'} });
 }
@@ -1336,7 +1307,7 @@ sub user_caused { 0 }
 sub user_caused { 0 }
 sub fields      { qw(origkw newkw); }
 sub as_html {
-    my $self = shift;
+    my $self = $_[0];
     return BML::ml("/editicons.bml.error.rename.keywords",
                           { 'origkw' => $self->{'origkw'},
                             'newkw' => $self->{'newkw'} });
diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/ljfeed.pl
--- a/cgi-bin/ljfeed.pl Wed Sep 08 15:10:03 2010 +0800
+++ b/cgi-bin/ljfeed.pl Wed Sep 08 15:46:13 2010 +0800
@@ -296,11 +296,10 @@ sub make_feed
     return $viewfunc->{handler}->($journalinfo, $u, $opts, \...@cleanitems, 
\...@entries);
 }
 
-# the creator for the RSS XML syndication view
-sub create_view_rss
-{
-    my ($journalinfo, $u, $opts, $cleanitems) = @_;
-
+# helper method for create_view_rss and create_view_comments
+sub _init_talkview {
+    my ( $journalinfo, $u, $opts, $talkview ) = @_;
+    my $hubbub = $talkview eq 'rss' && LJ::is_enabled( 'hubbub' );
     my $ret;
 
     # header
@@ -310,10 +309,14 @@ sub create_view_rss
             "xmlns:atom10='http://www.w3.org/2005/Atom'>\n";
 
     # channel attributes
+    my $desc = { rss => LJ::exml( "$journalinfo->{title} - $LJ::SITENAME" ),
+                 comments => "Latest comments in "
+                           . LJ::exml( $journalinfo->{title} ) };
+
     $ret .= "<channel>\n";
     $ret .= "  <title>" . LJ::exml($journalinfo->{title}) . "</title>\n";
     $ret .= "  <link>$journalinfo->{link}</link>\n";
-    $ret .= "  <description>" . LJ::exml("$journalinfo->{title} - 
$LJ::SITENAME") . "</description>\n";
+    $ret .= "  <description>" . $desc->{$talkview} . "</description>\n";
     $ret .= "  <managingEditor>" . LJ::exml($journalinfo->{email}) . 
"</managingEditor>\n" if $journalinfo->{email};
     $ret .= "  <lastBuildDate>$journalinfo->{builddate}</lastBuildDate>\n";
     $ret .= "  <generator>LiveJournal / $LJ::SITENAME</generator>\n";
@@ -321,7 +324,7 @@ sub create_view_rss
     $ret .= "  <lj:journaltype>" . $u->journaltype_readable . 
"</lj:journaltype>\n";
     # TODO: add 'language' field when user.lang has more useful information
 
-    if ( LJ::is_enabled( 'hubbub' ) ) {
+    if ( $hubbub ) {
         $ret .= "  <atom10:link rel='self' href='" . $u->journal_base . 
"/data/rss' />\n";
         foreach my $hub (@LJ::HUBBUB_HUBS) {
             $ret .= "  <atom10:link rel='hub' href='" . LJ::exml($hub) . "' 
/>\n";
@@ -329,19 +332,27 @@ sub create_view_rss
     }
 
     ### image block, returns info for their current userpic
-    if ($u->{'defaultpicid'}) {
-        my $pic = {};
-        LJ::load_userpics($pic, [ $u, $u->{'defaultpicid'} ]);
-        $pic = $pic->{$u->{'defaultpicid'}}; # flatten
+    if ( $u->{'defaultpicid'} ) {
+        my $icon = $u->userpic;
+        my $url = $icon->url;
+        my ( $width, $height ) = $icon->dimensions;
 
         $ret .= "  <image>\n";
-        $ret .= "    
<url>$LJ::USERPIC_ROOT/$u->{'defaultpicid'}/$u->{'userid'}</url>\n";
-        $ret .= "    <title>" . LJ::exml($journalinfo->{title}) . "</title>\n";
+        $ret .= "    <url>$url</url>\n";
+        $ret .= "    <title>" . LJ::exml( $journalinfo->{title} ) . 
"</title>\n";
         $ret .= "    <link>$journalinfo->{link}</link>\n";
-        $ret .= "    <width>$pic->{'width'}</width>\n";
-        $ret .= "    <height>$pic->{'height'}</height>\n";
+        $ret .= "    <width>$width</width>\n";
+        $ret .= "    <height>$height</height>\n";
         $ret .= "  </image>\n\n";
     }
+
+    return $ret;
+}
+
+sub create_view_rss {
+    my ( $journalinfo, $u, $opts, $cleanitems ) = @_;
+
+    my $ret = _init_talkview( $journalinfo, $u, $opts, 'rss' );
 
     my %posteru = ();  # map posterids to u objects
     LJ::load_userids_multiple([map { $_->{'posterid'}, 
\$posteru{$_->{'posterid'}} } @$cleanitems], [$u]);
@@ -921,21 +932,21 @@ sub create_view_userpics {
         $descriptions{$pic} = LJ::strip_html($description);
     }
 
-    my @pics;
-    push @pics, map { $info->{pic}->{$_} } sort { $a <=> $b }
-                      grep { $info->{pic}->{$_}->{state} eq 'N' } keys 
%{$info->{pic}};
+    my @pics = map { $info->{pic}->{$_} } sort { $a <=> $b }
+               grep { $info->{pic}->{$_}->{state} eq 'N' }
+               keys %{ $info->{pic} };
 
-    my $entry;
-    my %picdata;
-
-    # this is lame, but we have to do this iteration twice; we load the 
userpic data first, so that
-    # we can figure out what the most recently-uploaded userpic is. we need to 
put that into the feed
-    # before any of the <entry> values.
+    # FIXME: It sucks that there are two different methods for aggregating
+    #        the information for a user's set of icons, one of which doesn't
+    #        include keywords and the other of which doesn't include pictime.
+    #        But hey, at least they both use caching.
+    
+    my %pictimes = map { $_->picid => $_->pictime }
+                       LJ::Userpic->load_user_userpics( $u );
 
     my $latest = 0;
-    foreach my $pic (@pics) {
-        LJ::load_userpics(\%picdata, [$u, $pic->{picid}] );
-        $latest = ($latest < $picdata{$pic->{picid}}->{picdate}) ? 
$picdata{$pic->{picid}}->{picdate} : $latest;
+    foreach my $pictime ( values %pictimes ) {
+        $latest = ($latest < $pictime) ? $pictime : $latest;
     }
 
     $feed->updated( LJ::time_to_w3c($latest, 'Z') );
@@ -949,7 +960,7 @@ sub create_view_userpics {
         my $title = ($pic->{picid} == $u->{defaultpicid}) ? "default userpic" 
: "userpic";
         $entry->title( $title );
 
-        $entry->updated( LJ::time_to_w3c($picdata{$pic->{picid}}->{picdate}, 
'Z') );
+        $entry->updated( LJ::time_to_w3c( $pictimes{ $pic->{picid} }, 'Z') );
 
         my $content;
         $content = $entry_xml->createElement( "content" );
@@ -985,9 +996,8 @@ sub create_view_userpics {
 }
 
 
-sub create_view_comments
-{
-    my ($journalinfo, $u, $opts) = @_;
+sub create_view_comments {
+    my ( $journalinfo, $u, $opts ) = @_;
 
     unless ( LJ::is_enabled('latest_comments_rss', $u) ) {
         $opts->{handler_return} = 404;
@@ -999,37 +1009,7 @@ sub create_view_comments
         return;
     }
 
-    my $ret;
-    $ret .= "<?xml version='1.0' encoding='$opts->{'saycharset'}' ?>\n";
-    $ret .= LJ::Hooks::run_hook("bot_director", "<!-- ", " -->") . "\n";
-    $ret .= "<rss version='2.0' 
xmlns:lj='http://www.livejournal.org/rss/lj/1.0/'>\n";
-
-    # channel attributes
-    $ret .= "<channel>\n";
-    $ret .= "  <title>" . LJ::exml($journalinfo->{title}) . "</title>\n";
-    $ret .= "  <link>$journalinfo->{link}</link>\n";
-    $ret .= "  <description>Latest comments in " . 
LJ::exml($journalinfo->{title}) . "</description>\n";
-    $ret .= "  <managingEditor>" . LJ::exml($journalinfo->{email}) . 
"</managingEditor>\n" if $journalinfo->{email};
-    $ret .= "  <lastBuildDate>$journalinfo->{builddate}</lastBuildDate>\n";
-    $ret .= "  <generator>LiveJournal / $LJ::SITENAME</generator>\n";
-    $ret .= "  <lj:journal>" . $u->user . "</lj:journal>\n";
-    $ret .= "  <lj:journaltype>" . $u->journaltype_readable . 
"</lj:journaltype>\n";
-    # TODO: add 'language' field when user.lang has more useful information
-
-    ### image block, returns info for their current userpic
-    if ($u->{'defaultpicid'}) {
-        my $pic = {};
-        LJ::load_userpics($pic, [ $u, $u->{'defaultpicid'} ]);
-        $pic = $pic->{$u->{'defaultpicid'}}; # flatten
-
-        $ret .= "  <image>\n";
-        $ret .= "    
<url>$LJ::USERPIC_ROOT/$u->{'defaultpicid'}/$u->{'userid'}</url>\n";
-        $ret .= "    <title>" . LJ::exml($journalinfo->{title}) . "</title>\n";
-        $ret .= "    <link>$journalinfo->{link}</link>\n";
-        $ret .= "    <width>$pic->{'width'}</width>\n";
-        $ret .= "    <height>$pic->{'height'}</height>\n";
-        $ret .= "  </image>\n\n";
-    }
+    my $ret = _init_talkview( $journalinfo, $u, $opts, 'comments' );
 
     my @comments = $u->get_recent_talkitems(25);
     foreach my $r (@comments)
diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/ljlib.pl
--- a/cgi-bin/ljlib.pl  Wed Sep 08 15:10:03 2010 +0800
+++ b/cgi-bin/ljlib.pl  Wed Sep 08 15:46:13 2010 +0800
@@ -138,7 +138,6 @@ require "ljcapabilities.pl";
 require "ljcapabilities.pl";
 use DW::Mood;
 require "ljrelation.pl";
-require "ljuserpics.pl";
 
 require "$LJ::HOME/cgi-bin/ljlib-local.pl"
     if -e "$LJ::HOME/cgi-bin/ljlib-local.pl";
diff -r 93050be9e5bf -r b0e5dbe30bbf cgi-bin/ljuserpics.pl
--- a/cgi-bin/ljuserpics.pl     Wed Sep 08 15:10:03 2010 +0800
+++ /dev/null   Thu Jan 01 00:00:00 1970 +0000
@@ -1,112 +0,0 @@
-# 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.
-
-package LJ;
-use strict;
-use Carp qw/ croak /;
-
-# <LJFUNC>
-# name: LJ::load_userpics
-# des: Loads a bunch of userpics at once.
-# args: dbarg?, upics, idlist
-# des-upics: hashref to load pictures into, keys being the picids.
-# des-idlist: [$u, $picid] or [[$u, $picid], [$u, $picid], +] objects
-#             also supports deprecated old method, of an array ref of picids.
-# </LJFUNC>
-sub load_userpics {
-    my ($upics, $idlist) = @_;
-
-    return undef unless ref $idlist eq 'ARRAY' && $idlist->[0];
-
-    # $idlist needs to be an arrayref of arrayrefs,
-    # HOWEVER, there's a special case where it can be
-    # an arrayref of 2 items:  $u (which is really an arrayref)
-    # as well due to 'fields' and picid which is an integer.
-    #
-    # [$u, $picid] needs to map to [[$u, $picid]] while allowing
-    # [[$u1, $picid1], [$u2, $picid2], [etc...]] to work.
-    if (scalar @$idlist == 2 && ! ref $idlist->[1]) {
-        $idlist = [ $idlist ];
-    }
-
-    my @load_list;
-    foreach my $row (@{$idlist})
-    {
-        my ($u, $id) = @$row;
-        next unless ref $u;
-
-        if ($LJ::CACHE_USERPIC{$id}) {
-            $upics->{$id} = $LJ::CACHE_USERPIC{$id};
-        } elsif ($id+0) {
-            push @load_list, [$u, $id+0];
-        }
-    }
-    return unless @load_list;
-
-    if (@LJ::MEMCACHE_SERVERS) {
-        my @mem_keys = map { [$_->[1],"userpic.$_->[1]"] } @load_list;
-        my $mem = LJ::MemCache::get_multi(@mem_keys) || {};
-        while (my ($k, $v) = each %$mem) {
-            next unless $v && $k =~ /(\d+)/;
-            my $id = $1;
-            $upics->{$id} = LJ::MemCache::array_to_hash("userpic", $v);
-        }
-        @load_list = grep { ! $upics->{$_->[1]} } @load_list;
-        return unless @load_list;
-    }
-
-    my %db_load;
-    foreach my $row (@load_list) {
-        # ignore users on clusterid 0
-        next unless $row->[0]->{clusterid};
-
-        push @{$db_load{$row->[0]->{clusterid}}}, $row;
-    }
-
-    foreach my $cid (keys %db_load) {
-        my $dbcr = LJ::get_cluster_def_reader($cid);
-        unless ($dbcr) {
-            print STDERR "Error: LJ::load_userpics unable to get handle; cid = 
$cid\n";
-            next;
-        }
-
-        my (@bindings, @data);
-        foreach my $row (@{$db_load{$cid}}) {
-            push @bindings, "(userid=? AND picid=?)";
-            push @data, ($row->[0]->{userid}, $row->[1]);
-        }
-        next unless @data && @bindings;
-
-        my $sth = $dbcr->prepare("SELECT userid, picid, width, height, fmt, 
state, ".
-                                 "       UNIX_TIMESTAMP(picdate) AS 'picdate', 
location, flags ".
-                                 "FROM userpic2 WHERE " . join(' OR ', 
@bindings));
-        $sth->execute(@data);
-
-        while (my $ur = $sth->fetchrow_hashref) {
-            my $id = delete $ur->{'picid'};
-            $upics->{$id} = $ur;
-
-            # force into numeric context so they'll be smaller in memcache:
-            foreach my $k (qw(userid width height flags picdate)) {
-                $ur->{$k} += 0;
-            }
-            $ur->{location} = uc(substr($ur->{location}, 0, 1));
-
-            $LJ::CACHE_USERPIC{$id} = $ur;
-            LJ::MemCache::set([$id,"userpic.$id"], 
LJ::MemCache::hash_to_array("userpic", $ur));
-        }
-    }
-}
-
-1;
-
diff -r 93050be9e5bf -r b0e5dbe30bbf htdocs/community/moderate.bml
--- a/htdocs/community/moderate.bml     Wed Sep 08 15:10:03 2010 +0800
+++ b/htdocs/community/moderate.bml     Wed Sep 08 15:46:13 2010 +0800
@@ -411,17 +411,15 @@ body<=
         $ret .= "<p>";
         $ret .= "<table><tr valign='middle'>";
 
-        my $picid = $up ? $up->get_picid_from_keyword( 
$props->{picture_keyword} ) : undef;
+        my $kw = $props->{picture_keyword};
+        my $icon = LJ::Userpic->new_from_keyword( $up, $kw );
 
-        my %userpics;
-        if ( $picid ) {
-            LJ::load_userpics(\%userpics, [ $up, $picid ]);
-            my $alt = $up->{name};
-            $alt .= ": $props->{picture_keyword}"
-                if $props->{picture_keyword};
-            $alt = LJ::ehtml( $alt );
-            $ret .= "<td><img src='$LJ::USERPIC_ROOT/$picid/$up->{'userid'}' 
width='$userpics{$picid}->{'width'}' ".
-                "height='$userpics{$picid}->{'height'}' align='absmiddle' ".
+        if ( $up && $icon ) {
+            my $alt = $up->name_html . LJ::ehtml( ": $kw" );
+            my $src = $icon->url;
+            my ( $width, $height ) = $icon->dimensions;
+            $ret .= "<td><img src='$src' width='$width' ".
+                "height='$height' align='absmiddle' ".
                 "hspace='3' title='$alt' alt=''></td>";
         }
 
diff -r 93050be9e5bf -r b0e5dbe30bbf htdocs/manage/profile/index.bml
--- a/htdocs/manage/profile/index.bml   Wed Sep 08 15:10:03 2010 +0800
+++ b/htdocs/manage/profile/index.bml   Wed Sep 08 15:46:13 2010 +0800
@@ -132,15 +132,9 @@ body<=
         ### Picture Settings
         $ret .= "<tr class='field_block'><td 
class='field_name'>$ML{'.fn.userpic2'}</td>\n";
         $ret .= "<td><div style='width: 100px; height: 100px; float: left; 
text-align: center; border: 1px solid #ddd'>";
-        if ($u->{'defaultpicid'}) {
-            my $picid = $u->{'defaultpicid'};
-            my %userpics = ();
-            # FIXME: this repetitive load will be fixed in bug
-            # 513. For now, memcache keeps this from hitting the
-            # db twice.
-            LJ::load_userpics(\%userpics, [ $u, $picid ]);
-            my $userpic_obj = LJ::Userpic->new( $u, $picid );
-            $ret .= $userpic_obj->imgtag;
+        if ( $u->{'defaultpicid'} ) {
+            my $icon = $u->userpic;
+            $ret .= $icon->imgtag;
         } else {
             $ret .= "<br /><i>($ML{'.userpic.none'})</i>";
         }
diff -r 93050be9e5bf -r b0e5dbe30bbf htdocs/support/see_request.bml
--- a/htdocs/support/see_request.bml    Wed Sep 08 15:10:03 2010 +0800
+++ b/htdocs/support/see_request.bml    Wed Sep 08 15:46:13 2010 +0800
@@ -311,14 +311,8 @@ body<=
     $ret .= "<table class='support-requesttable'>\n";
     $ret .= "<tr><td valign='bottom' 
align='right'><b>$ML{'.from'}</b></td><td>";
     
-    if ($u->{'defaultpicid'} && !$u->is_suspended) {
-        my %pic;
-        my $picid = $u->{'defaultpicid'};
-        # FIXME: this repetitive load will be fixed in bug
-        # 513. For now, memcache keeps this from hitting the
-        # db twice.
-        LJ::load_userpics(\%pic, [ $u, $picid ]);
-        my $userpic_obj = LJ::Userpic->new( $u, $picid );
+    if ( $u->{'defaultpicid'} && !$u->is_suspended ) {
+        my $userpic_obj = $u->userpic;
         $ret .= "<a href='" . $u->allpics_base . "'>";
         $ret .= $userpic_obj->imgtag;
         $ret .= "</a>";
@@ -539,8 +533,6 @@ body<=
                 $ML{'.private.request'}."</div>";
     }
 
-    my %userpics;  # id -> {..}
-
     my @screened;
     my $most_recent_tier = 0;
     my $curlang = BML::get_language();
@@ -592,15 +584,16 @@ body<=
         my $header = "";
         if ($up && LJ::Support::can_see_helper($sp, $remote)) {
             my $picid = $up->get_picid_from_keyword( '_support' ) || 
$up->{defaultpicid};
-            $userpics{$picid} or LJ::load_userpics(\%userpics, [[ $up, $picid 
]]);
+            my $icon = $picid ? LJ::Userpic->new( $up, $picid ) : undef;
             $header = "<table style='margin-top: 15px;'><tr valign='bottom'>";
-            if ($picid && !$up->is_suspended) {
-                $header .= "<td><img 
src='$LJ::USERPIC_ROOT/$picid/$up->{'userid'}' 
width='$userpics{$picid}->{'width'}' height='$userpics{$picid}->{'height'}' 
hspace='3' alt='$up->{'user'}'/></td>";
+            if ( $icon && !$up->is_suspended ) {
+                my $alt = $up->display_name;
+                my $src = $icon->url;
+                my ( $width, $height ) = $icon->dimensions;
+                $header .= "<td><img src='$src' width='$width' 
height='$height' hspace='3' alt='$alt'/></td>";
             }
-            $header .= "<td>" . LJ::ljuser($up->{'user'}, { 'full' => 1 });
-            if (!$up->is_suspended) {
-                $header .= " - " . LJ::ehtml($up->{'name'});
-            }
+            $header .= "<td>" . LJ::ljuser( $u, { full => 1 } );
+            $header .= " - " . $up->name_html unless $up->is_suspended;
             $header .= "</td></tr></table>\n"
         }
 
_______________________________________________
dw-changelog mailing list
[email protected]
http://lists.dwscoalition.org/mailman/listinfo/dw-changelog

Reply via email to