Committer: amyshkin
LJSUP-9270: Creare RSS feed for friends pageU trunk/bin/upgrading/en.dat U trunk/cgi-bin/LJ/Entry.pm U trunk/cgi-bin/ljfeed.pl U trunk/cgi-bin/ljlib.pl
Modified: trunk/bin/upgrading/en.dat =================================================================== --- trunk/bin/upgrading/en.dat 2011-07-12 06:24:19 UTC (rev 19464) +++ trunk/bin/upgrading/en.dat 2011-07-12 06:57:34 UTC (rev 19465) @@ -2704,6 +2704,8 @@ feeds.text=Apparently there's good content outside of LJ? We'll let you add [[link]] to your Friends page so you never have to leave. +feeds.title.friends=friends page feed + gender.female|staleness=1 gender.female=Female Modified: trunk/cgi-bin/LJ/Entry.pm =================================================================== --- trunk/cgi-bin/LJ/Entry.pm 2011-07-12 06:24:19 UTC (rev 19464) +++ trunk/cgi-bin/LJ/Entry.pm 2011-07-12 06:57:34 UTC (rev 19465) @@ -78,6 +78,7 @@ $self->{anum} = delete $opts{anum}; $self->{ditemid} = delete $opts{ditemid}; $self->{jitemid} = delete $opts{jitemid}; + $self->{rlogtime}= delete $opts{rlogtime}; # make arguments numeric for my $f (qw(ditemid jitemid anum)) { @@ -90,7 +91,7 @@ croak("Unknown parameters: " . join(", ", keys %opts)) if %opts; - if ($self->{ditemid}) { + if ( $self->{ditemid} ) { $self->{anum} = $self->{ditemid} & 255; $self->{jitemid} = int($self->{ditemid} / 256); } @@ -108,6 +109,8 @@ __PACKAGE__->preload_rows([ $self ]); return undef if $anum and $anum != $self->{anum}; # incorrect anum -> 'no such entry' + $self->{ditemid} = $self->{jitemid} * 256 + $self->{anum}; + # save the singleton if it doesn't exist $singletons{$journalid}->{$jitemid} = $self; @@ -206,12 +209,12 @@ my $self = shift; my %opts = @_; my %args = %opts; # used later - my $u = $self->{u}; - my $view = delete $opts{view}; + my $u = $self->{u}; + my $view = delete $opts{view}; my $anchor = delete $opts{anchor}; - my $mode = delete $opts{mode}; - my $style = delete $opts{style}; - my $nc = delete $opts{nc}; + my $mode = delete $opts{mode}; + my $style = delete $opts{style}; + my $nc = delete $opts{nc}; croak "Unknown args passed to url: " . join(",", keys %opts) if %opts; @@ -430,6 +433,7 @@ sub prop { my ($self, $prop) = @_; $self->_load_props unless $self->{_loaded_props}; + return $self->{props} unless $prop; return $self->{props}{$prop}; } @@ -2174,8 +2178,7 @@ # des-: # returns: # </LJFUNC> -sub load_log_props2 -{ +sub load_log_props2 { my $db = isdb($_[0]) ? shift @_ : undef; my ($uuserid, $listref, $hashref) = @_; @@ -2186,50 +2189,57 @@ my %needrc; my %rc; my @memkeys; - foreach (@$listref) { - my $id = $_+0; + + foreach ( @$listref ) { + my $id = $_ + 0; $needprops{$id} = 1; - $needrc{$id} = 1; + $needrc{$id} = 1; push @memkeys, [$userid, "logprop:$userid:$id"]; push @memkeys, LJ::Entry::reply_count_memkey($userid, $id); } + return unless %needprops || %needrc; my $mem = LJ::MemCache::get_multi(@memkeys) || {}; - while (my ($k, $v) = each %$mem) { + + while ( my ($k, $v) = each %$mem ) { next unless $k =~ /(\w+):(\d+):(\d+)/; - if ($1 eq 'logprop') { + + if ( $1 eq 'logprop' ) { next unless ref $v eq "HASH"; delete $needprops{$3}; $hashref->{$3} = $v; } - if ($1 eq 'rp') { + + if ( $1 eq 'rp' ) { delete $needrc{$3}; $rc{$3} = int($v); # change possible "0 " (true) to "0" (false) } } - foreach (keys %rc) { + foreach ( keys %rc ) { $hashref->{$_}{'replycount'} = $rc{$_}; } return unless %needprops || %needrc; - unless ($db) { + unless ( $db ) { my $u = LJ::load_userid($userid); $db = @LJ::MEMCACHE_SERVERS ? LJ::get_cluster_def_reader($u) : LJ::get_cluster_reader($u); return unless $db; } - if (%needprops) { + if ( %needprops ) { LJ::load_props("log"); my $in = join(",", keys %needprops); my $sth = $db->prepare("SELECT jitemid, propid, value FROM logprop2 ". "WHERE journalid=? AND jitemid IN ($in)"); $sth->execute($userid); + while (my ($jitemid, $propid, $value) = $sth->fetchrow_array) { $hashref->{$jitemid}->{$LJ::CACHE_PROPID{'log'}->{$propid}->{'name'}} = $value; } + foreach my $id (keys %needprops) { LJ::MemCache::set([$userid,"logprop:$userid:$id"], $hashref->{$id} || {}); } @@ -2516,12 +2526,10 @@ # des-opts: Optional hashref of special options. NOW IGNORED (2005-09-14) # des-jitemid: List of jitemids to retrieve the subject & text for. # </LJFUNC> -sub get_logtext2 -{ +sub get_logtext2 { my $u = shift; my $clusterid = $u->{'clusterid'}; - my $journalid = $u->{'userid'}+0; - + my $journalid = $u->{'userid'} + 0; my $opts = ref $_[0] ? shift : {}; # this is now ignored # return structure. @@ -2531,14 +2539,16 @@ # keep track of itemids we still need to load. my %need; my @mem_keys; + foreach (@_) { - my $id = $_+0; + my $id = $_ + 0; $need{$id} = 1; - push @mem_keys, [$journalid,"logtext:$clusterid:$journalid:$id"]; + push @mem_keys, [$journalid, "logtext:$clusterid:$journalid:$id"]; } # pass 1: memcache my $mem = LJ::MemCache::get_multi(@mem_keys) || {}; + while (my ($k, $v) = each %$mem) { next unless $v; $k =~ /:(\d+):(\d+):(\d+)/; @@ -2556,13 +2566,15 @@ my $sth = $db->prepare("SELECT jitemid, subject, event FROM logtext2 ". "WHERE journalid=$journalid AND jitemid IN ($jitemid_in)"); $sth->execute; + while (my ($id, $subject, $event) = $sth->fetchrow_array) { LJ::text_uncompress(\$event); my $val = [ $subject, $event ]; $lt->{$id} = $val; - LJ::MemCache::add([$journalid,"logtext:$clusterid:$journalid:$id"], $val); + LJ::MemCache::add([$journalid, "logtext:$clusterid:$journalid:$id"], $val); delete $need{$id}; } + return $lt; } Modified: trunk/cgi-bin/ljfeed.pl =================================================================== --- trunk/cgi-bin/ljfeed.pl 2011-07-12 06:24:19 UTC (rev 19464) +++ trunk/cgi-bin/ljfeed.pl 2011-07-12 06:57:34 UTC (rev 19465) @@ -17,10 +17,10 @@ yadis => { handler => \&create_view_yadis, }, userpics => { handler => \&create_view_userpics, }, comments => { handler => \&create_view_comments, }, + friends => { handler => \&create_view_rss, need_items => 1 }, ); -sub make_feed -{ +sub make_feed { my ($u, $remote, $opts) = @_; $opts->{pathextra} =~ s!^/(\w+)!!; @@ -36,8 +36,10 @@ my $allowed = 0; my $remote_ip = LJ::get_remote_ip(); + foreach my $block (@LJ::YANDEX_RSS_IP_BLOCKS) { my $net = Net::Netmask->new($block); + next unless $net->match($remote_ip); $allowed = 1; last; @@ -80,17 +82,17 @@ # if we do not want items for this view, just call out $opts->{'contenttype'} = 'text/xml; charset='.$opts->{'saycharset'}; + return $viewfunc->{handler}->($journalinfo, $u, $opts) - unless ($viewfunc->{need_items}); + unless $viewfunc->{need_items}; # for syndicated accounts, redirect to the syndication URL # However, we only want to do this if the data we're returning # is similar. (Not FOAF, for example) if ($u->{'journaltype'} eq 'Y') { my $synurl = $dbr->selectrow_array("SELECT synurl FROM syndicated WHERE userid=$u->{'userid'}"); - unless ($synurl) { - return 'No syndication URL available.'; - } + return 'No syndication URL available.' unless $synurl; + $opts->{'redir'} = $synurl; return undef; } @@ -98,10 +100,10 @@ my %FORM = LJ::Request->args; ## load the itemids - my (@itemids, @items); + my (@itemids, @objs); - # for consistency, we call ditemids "itemid" in user-facing settings - my $ditemid = $FORM{itemid}+0; + # for consistency, we call ditemids "itemid" in user-facing settings + my $ditemid = $FORM{itemid} + 0; if ($ditemid) { my $entry = LJ::Entry->new($u, ditemid => $ditemid); @@ -111,54 +113,57 @@ return undef; } - @itemids = $entry->jitemid; - - push @items, { - itemid => $entry->jitemid, - anum => $entry->anum, - posterid => $entry->poster->id, - security => $entry->security, - alldatepart => LJ::TimeUtil->alldatepart_s2($entry->eventtime_mysql), - }; - } else { - @items = LJ::get_recent_items({ - 'clusterid' => $u->{'clusterid'}, - 'clustersource' => 'slave', - 'remote' => $remote, - 'userid' => $u->{'userid'}, - 'itemshow' => 25, - 'order' => "logtime", - 'tagids' => $opts->{tagids}, - 'tagmode' => $opts->{tagmode}, - 'itemids' => \@itemids, - 'friendsview' => 1, # this returns rlogtimes - 'dateformat' => "S2", # S2 format time format is easier + push @objs, $entry; + } + elsif ( $feedtype eq 'friends' ) { + LJ::get_friend_items({ + 'u' => $u, + 'remote' => $remote, + 'itemshow' => 25, + 'dateformat' => 'S2', + 'itemids' => \@itemids, + 'entry_objects' => \@objs, + 'load_props' => 1, + 'load_text' => 1, }); + $journalinfo->{title} .= ' ' . LJ::Lang::ml('feeds.title.friends'); + $journalinfo->{link} .= 'friends/'; } + else { + LJ::get_recent_items({ + 'remote' => $remote, + 'userid' => $u->{'userid'}, + 'itemshow' => 25, + 'order' => 'logtime', + 'tagids' => $opts->{tagids}, + 'tagmode' => $opts->{tagmode}, + 'itemids' => \@itemids, + 'friendsview' => 1, # this returns rlogtimes + 'dateformat' => 'S2', # S2 format time format is easier + 'entry_objects' => \@objs, + 'load_props' => 1, + 'load_text' => 1, + }); + } - $opts->{'contenttype'} = 'text/xml; charset='.$opts->{'saycharset'}; + $opts->{'contenttype'} = 'text/xml; charset=' . $opts->{'saycharset'}; - ### load the log properties - my %logprops = (); - my $logtext; - my $logdb = LJ::get_cluster_reader($u); - LJ::load_log_props2($logdb, $u->{'userid'}, \@itemids, \%logprops); - $logtext = LJ::get_logtext2($u, @itemids); - # set last-modified header, then let apache figure out # whether we actually need to send the feed. my $lastmod = 0; - foreach my $item (@items) { + + for my $obj ( @objs ) { # revtime of the item. - my $revtime = $logprops{$item->{itemid}}->{revtime}; + my $revtime = $obj->prop('revtime'); $lastmod = $revtime if $revtime > $lastmod; - # if we don't have a revtime, use the logtime of the item. unless ($revtime) { - my $itime = $LJ::EndOfTime - $item->{rlogtime}; + # use the logtime of the item. + my $itime = $LJ::EndOfTime - $obj->{rlogtime}; $lastmod = $itime if $itime > $lastmod; } } + LJ::Request->set_last_modified($lastmod) if $lastmod; # use this $lastmod as the feed's last-modified time @@ -184,31 +189,27 @@ # load tags now that we have no chance of jumping out early my $logtags = LJ::Tags::get_logtags($u, \@itemids); - my %posteru = (); # map posterids to u objects - LJ::load_userids_multiple([map { $_->{'posterid'}, \$posteru{$_->{'posterid'}} } @items], [$u]); - my @cleanitems; - my @entries; # LJ::Entry objects ENTRY: - foreach my $it (@items) - { - # load required data - my $itemid = $it->{'itemid'}; - my $ditemid = $itemid*256 + $it->{'anum'}; - my $entry_obj = LJ::Entry->new($u, ditemid => $ditemid); - $entry_obj->handle_prefetched_props($logprops{$itemid}); + foreach my $entry_obj (@objs) { + my $ditemid = $entry_obj->{ditemid}; - next ENTRY if $posteru{$it->{'posterid'}} && $posteru{$it->{'posterid'}}->{'statusvis'} eq 'S'; + next ENTRY if $entry_obj->poster->{'statusvis'} eq 'S'; next ENTRY if $entry_obj && $entry_obj->is_suspended_for($remote); - if ($LJ::UNICODE && $logprops{$itemid}->{'unknown8bit'}) { - LJ::item_toutf8($u, \$logtext->{$itemid}->[0], - \$logtext->{$itemid}->[1], $logprops{$itemid}); + if ( $LJ::UNICODE && $entry_obj->prop('unknown8bit') ) { + LJ::item_toutf8( + $u, + \$entry_obj->{'subject'}, + \$entry_obj->{'event'}, + $entry_obj->prop, + ); } # see if we have a subject and clean it - my $subject = $logtext->{$itemid}->[0]; + my $subject = $entry_obj->{'subject'}; + if ($subject) { $subject =~ s/[\r\n]/ /g; LJ::CleanHTML::clean_subject_all(\$subject); @@ -218,12 +219,12 @@ my $readmore = "<b>(<a href=\"$journalinfo->{link}$ditemid.html\">Read more ...</a>)</b>"; # empty string so we don't waste time cleaning an entry that won't be used - my $event = $u->{'opt_synlevel'} eq 'title' ? '' : $logtext->{$itemid}->[1]; + my $event = $u->{'opt_synlevel'} eq 'title' ? '' : $entry_obj->event_raw; # clean the event, if non-empty my $ppid = 0; + if ($event) { - # users without 'full_rss' get their logtext bodies truncated # do this now so that the html cleaner will hopefully fix html we break unless (LJ::get_cap($u, 'full_rss')) { @@ -232,11 +233,12 @@ } LJ::CleanHTML::clean_event(\$event, - { 'wordlength' => 0, - 'preformatted' => $logprops{$itemid}->{'opt_preformatted'}, - 'journalid' => $u->userid, - 'posterid' => $it->{'posterid'}, - 'entry_url' => $entry_obj->url, + { + 'wordlength' => 0, + 'preformatted' => $entry_obj->prop('opt_preformatted'), + 'journalid' => $u->userid, + 'posterid' => $entry_obj->{'posterid'}, + 'entry_url' => $entry_obj->url, } ); @@ -245,12 +247,12 @@ if ($u->{'opt_synlevel'} eq 'summary') { # assume the first paragraph is terminated by two <br> or a </p> # valid XML tags should be handled, even though it makes an uglier regex - if ($event =~ m! + if ($event =~ m! (.*?) ## any text (?=<) ## followed by "<" (zero-width positive look-ahead assertion) - ## and then either </p> or 2 BRs, + ## and then either </p> or 2 BRs, ## where BR is one of: <br></br>, <br> or <br/> - ( (?:<br\s*/?\>(?:</br\s*>)?\s*){2} | (?:</p\s*>) ) !six) + ( (?:<br\s*/?\>(?:</br\s*>)?\s*){2} | (?:</p\s*>) ) !six) { # everything before the matched tag + the tag itself # + a link to read more @@ -264,13 +266,14 @@ my $name = LJ::Poll->new($pollid)->name; if ($name) { LJ::Poll->clean_poll(\$name); - } else { + } + else { $name = "#$pollid"; } $event =~ s!<lj-poll-$pollid>!<div><a href="$LJ::SITEROOT/poll/?id=$pollid">View Poll: $name</a></div>!g; } - + my %args = LJ::Request->args; LJ::EmbedModule->expand_entry($u, \$event, expand_full => 1) if %args && $args{'unfold_embed'}; @@ -280,45 +283,47 @@ } my $mood; - if ($logprops{$itemid}->{'current_mood'}) { - $mood = $logprops{$itemid}->{'current_mood'}; - } elsif ($logprops{$itemid}->{'current_moodid'}) { - $mood = LJ::mood_name($logprops{$itemid}->{'current_moodid'}+0); + + if ( $entry_obj->prop('current_mood') ) { + $mood = $entry_obj->prop('current_mood'); } + elsif ( $entry_obj->prop('current_moodid') ) { + $mood = LJ::mood_name($entry_obj->prop('current_moodid') + 0); + } - my $createtime = $LJ::EndOfTime - $it->{rlogtime}; - my $cleanitem = { - itemid => $itemid, + my $alldateparts = $entry_obj->{'eventtime'}; + $alldateparts =~ s/[-:]/ /g; + + my $createtime = $LJ::EndOfTime - $entry_obj->{rlogtime}; + push @cleanitems, { + itemid => $entry_obj->jitemid, ditemid => $ditemid, subject => $subject, event => $event, createtime => $createtime, - eventtime => $it->{alldatepart}, # ugly: this is of a different format than the other two times. - modtime => $logprops{$itemid}->{revtime} || $createtime, + eventtime => $alldateparts, + modtime => $entry_obj->prop('revtime') || $createtime, comments => $entry_obj->comments_shown, - music => $logprops{$itemid}->{'current_music'}, + music => $entry_obj->prop('current_music'), mood => $mood, ppid => $ppid, - tags => [ values %{$logtags->{$itemid} || {}} ], - security => $it->{security}, - posterid => $it->{posterid}, - replycount => $logprops{$itemid}->{'replycount'}, + tags => [ values %{$logtags->{$entry_obj->jitemid} || {}} ], + security => $entry_obj->security, + posterid => $entry_obj->poster->id, + replycount => $entry_obj->prop('replycount'), + posteruser => $entry_obj->poster->user, }; - push @cleanitems, $cleanitem; - push @entries, $entry_obj; } # fix up the build date to use entry-time - $journalinfo->{'builddate'} = LJ::TimeUtil->time_to_http($LJ::EndOfTime - $items[0]->{'rlogtime'}), + $journalinfo->{'builddate'} = LJ::TimeUtil->time_to_http($LJ::EndOfTime - $objs[0]->{'rlogtime'}), - return $viewfunc->{handler}->($journalinfo, $u, $opts, \@cleanitems, \@entries); + return $viewfunc->{handler}->($journalinfo, $u, $opts, \@cleanitems, \@objs); } # the creator for the RSS XML syndication view -sub create_view_rss -{ - my ($journalinfo, $u, $opts, $cleanitems) = @_; - +sub create_view_rss { + my ($journalinfo, $u, $opts, $cleanitems, $objs) = @_; my $ret; # For Yandex ( http://blogs.yandex.ru/faq.xml?id=542563 ) @@ -367,30 +372,25 @@ $ret .= " </image>\n\n"; } - my %posteru = (); # map posterids to u objects - LJ::load_userids_multiple([map { $_->{'posterid'}, \$posteru{$_->{'posterid'}} } @$cleanitems], [$u]); - # output individual item blocks - - foreach my $it (@$cleanitems) - { + foreach my $it (@$cleanitems) { + my $entry = shift @$objs; my $itemid = $it->{itemid}; my $ditemid = $it->{ditemid}; - my $poster = $posteru{$it->{posterid}}; $ret .= "<item>\n"; $ret .= " <guid isPermaLink='true'>$journalinfo->{link}$ditemid.html</guid>\n"; $ret .= " <pubDate>" . LJ::TimeUtil->time_to_http($it->{createtime}) . "</pubDate>\n"; $ret .= " <title>" . LJ::exml($it->{subject}) . "</title>\n" if $it->{subject}; $ret .= " <author>" . LJ::exml($journalinfo->{email}) . "</author>" if $journalinfo->{email}; - $ret .= " <link>$journalinfo->{link}$ditemid.html</link>\n"; + $ret .= " <link>" . $entry->url . "</link>\n"; # omit the description tag if we're only syndicating titles # note: the $event was also emptied earlier, in make_feed unless ($u->{'opt_synlevel'} eq 'title') { $ret .= " <description>" . LJ::exml($it->{event}) . "</description>\n"; } if ($it->{comments}) { - $ret .= " <comments>$journalinfo->{link}$ditemid.html</comments>\n"; + $ret .= " <comments>" . $entry->url . "</comments>\n"; } $ret .= " <category>$_</category>\n" foreach map { LJ::exml($_) } @{$it->{tags} || []}; # support 'podcasting' enclosures @@ -401,9 +401,9 @@ $ret .= " <media:title type=\"plain\">" . LJ::exml($it->{music}) . "</media:title>\n" if $it->{music}; $ret .= " <lj:mood>" . LJ::exml($it->{mood}) . "</lj:mood>\n" if $it->{mood}; $ret .= " <lj:security>" . LJ::exml($it->{security}) . "</lj:security>\n" if $it->{security}; - unless (LJ::u_equals($u, $poster)) { - $ret .= " <lj:poster>" . LJ::exml($poster->user) . "</lj:poster>\n"; - $ret .= " <lj:posterid>" . $poster->userid . "</lj:posterid>\n"; + unless ($u->{'userid'} == $it->{'posterid'}) { + $ret .= " <lj:poster>" . LJ::exml($it->{'posteruser'}) . "</lj:poster>\n"; + $ret .= " <lj:posterid>" . $it->{'posterid'} . "</lj:posterid>\n"; } $ret .= " <lj:reply-count>$it->{replycount}</lj:reply-count>\n"; @@ -444,7 +444,7 @@ for (my $i = 0; $i <= $now->hour; $i++) { $sum += $today_hits[$i]; } - + if ($now->hour < 23) { my @yesterday_hits; foreach my $el (@$data_y) { @@ -533,6 +533,7 @@ unless ($opts->{'single_entry'}) { $feed = XML::Atom::Feed->new( Version => 1 ); $xml = $feed->{doc}; + unless ($xml){ die "Error: XML-LibXML is required"; ## sudo yum install perl-XML-LibXML } @@ -596,9 +597,9 @@ } my $posteru = LJ::load_userids( map { $_->{posterid} } @$cleanitems); + # output individual item blocks - foreach my $it (@$cleanitems) - { + foreach my $it ( @$cleanitems ) { my $itemid = $it->{itemid}; my $ditemid = $it->{ditemid}; my $poster = $posteru->{$it->{posterid}}; @@ -945,15 +946,15 @@ my $view; if ($viewchunk eq '') { - $view = "recent"; + $view = "recent"; } elsif ($viewchunk eq '/friends') { - $view = "friends"; + $view = "friends"; } else { $view = undef; } - + if ($view eq 'recent') { # Only people (not communities, etc) can be OpenID authenticated if ($person && LJ::OpenID->server_enabled) { @@ -1109,12 +1110,12 @@ $opts->{handler_return} = 404; return 404; } - + unless ($u->get_cap('latest_comments_rss')) { $opts->{handler_return} = 403; return; } - + my $ret; $ret .= "<?xml version='1.0' encoding='$opts->{'saycharset'}' ?>\n"; $ret .= LJ::run_hook("bot_director", "<!-- ", " -->") . "\n"; @@ -1154,7 +1155,7 @@ my $thread_url = $c->thread_url; my $subject = $c->subject_raw; LJ::CleanHTML::clean_subject_all(\$subject); - + $ret .= "<item>\n"; $ret .= " <guid isPermaLink='true'>$thread_url</guid>\n"; $ret .= " <pubDate>" . LJ::TimeUtil->time_to_http($r->{datepostunix}) . "</pubDate>\n"; Modified: trunk/cgi-bin/ljlib.pl =================================================================== --- trunk/cgi-bin/ljlib.pl 2011-07-12 06:24:19 UTC (rev 19464) +++ trunk/cgi-bin/ljlib.pl 2011-07-12 06:57:34 UTC (rev 19465) @@ -612,20 +612,21 @@ # - showtypes: /[PICNY]/ # returns: Array of item hashrefs containing the same elements # </LJFUNC> -sub get_friend_items -{ +sub get_friend_items { &nodb; my $opts = shift; my $dbr = LJ::get_db_reader(); my $sth; - my $userid = $opts->{'userid'}+0; + my $userid = $opts->{'userid'} + 0; + $userid = $opts->{'u'}->{'userid'} unless $userid; return () if $LJ::FORCE_EMPTY_FRIENDS{$userid}; # 'remote' opt takes precendence, then 'remoteid' my $remote = $opts->{'remote'}; my $remoteid = $remote ? $remote->{'userid'} : 0; + if ($remoteid == 0 && $opts->{'remoteid'}) { $remoteid = $opts->{'remoteid'} + 0; $remote = LJ::load_userid($remoteid); @@ -642,13 +643,13 @@ } my @items = (); - my $itemshow = $opts->{'itemshow'}+0; - my $skip = $opts->{'skip'}+0; + my $itemshow = $opts->{'itemshow'} + 0; + my $skip = $opts->{'skip'} + 0; my $getitems = $itemshow + $skip; # friendspage per day is allowed only for journals with # special cap 'friendspage_per_day' - my $events_date = $opts->{u}->get_cap('friendspage_per_day') + my $events_date = $opts->{'u'}->get_cap('friendspage_per_day') ? $opts->{events_date} : ''; @@ -708,7 +709,7 @@ if ($LJ::SLOPPY_FRIENDS_THRESHOLD && $fcount > $LJ::SLOPPY_FRIENDS_THRESHOLD) { $tu_opts->{memcache_only} = 1; } - + my $times = $events_date ? LJ::get_times_multi($tu_opts, keys %$friends) : {updated => LJ::get_timeupdate_multi($tu_opts, keys %$friends)}; @@ -722,11 +723,11 @@ push @friends_buffer, [ $fid, $rupdate, $clusterid, $friends->{$fid}, $fu ]; } - @friends_buffer = - sort { $a->[1] <=> $b->[1] } - grep { + @friends_buffer = + sort { $a->[1] <=> $b->[1] } + grep { $timeupdate->{$_->[0]} >= $lastmax and # reverse index - ($events_date + ($events_date ? $times->{created}->{$_->[0]} < $events_date : 1 ) @@ -978,11 +979,51 @@ # remove skipped ones splice(@items, 0, $skip) if $skip; + my ( @itemids, %owner_itemsids ); + # get items foreach (@items) { $opts->{'owners'}->{$_->{'ownerid'}} = 1; + + # construct an LJ::Entry singleton + my $entry = LJ::Entry->new( + $_->{'journalid'}, + 'jitemid' => $_->{'itemid'}, + 'anum' => $_->{'anum'}, + 'rlogtime' => $_->{'rlogtime'}, + ); + $entry->absorb_row($_); + push @{$opts->{'entry_objects'}}, $entry; + push @{$opts->{'itemids'}}, $_->{'itemid'}; + push @{$owner_itemsids{ $_->{'journalid'} }->{id}}, $_->{'itemid'}; + push @{$owner_itemsids{ $_->{'journalid'} }->{entry}}, \$opts->{'entry_objects'}->[-1]; } + if ( exists $opts->{load_props} && $opts->{load_props} ) { + my %logprops = (); + + for my $journal ( keys %owner_itemsids ) { + LJ::load_log_props2($journal, $owner_itemsids{ $journal }->{id}, \%logprops); + } + + for my $entry ( @{$opts->{'entry_objects'}} ) { + $entry->handle_prefetched_props($logprops{$entry->{jitemid}}); + } + } + + if ( exists $opts->{load_text} && $opts->{load_text} ) { + my $texts; + + for my $journal ( keys %owner_itemsids ) { + $texts = LJ::get_logtext2(LJ::load_userid($journal), @{$owner_itemsids{ $journal }->{id}} ); + + for my $rentry ( @{$owner_itemsids{ $journal }->{entry}} ) { + $$rentry->handle_prefetched_text( $texts->{ $$rentry->{jitemid} }->[0], $texts->{ $$rentry->{jitemid} }->[1] ); + } + } + } + + # return the itemids grouped by clusters, if callers wants it. if (ref $opts->{'idsbycluster'} eq "HASH") { foreach (@items) { @@ -1044,7 +1085,7 @@ my $err = $opts->{'err'}; my $userid = $opts->{'userid'}+0; - my $u = LJ::load_userid($userid) + my $u = LJ::load_userid($userid) or die "No such userid: $userid"; # 'remote' opt takes precendence, then 'remoteid' @@ -1058,13 +1099,16 @@ my $max_hints = $LJ::MAX_SCROLLBACK_LASTN; # temporary my $sort_key = "revttime"; - my $clusterid = $u->{'clusterid'}+0; + my $clusterid = $u->{'clusterid'} + 0; my @sources = ("cluster$clusterid"); + if (my $ab = $LJ::CLUSTER_PAIR_ACTIVE{$clusterid}) { @sources = ("cluster${clusterid}${ab}"); } + unshift @sources, ("cluster${clusterid}lite", "cluster${clusterid}slave") if $opts->{'clustersource'} eq "slave"; + my $logdb = LJ::get_dbh(@sources); # community/friend views need to post by log time, not event time @@ -1161,7 +1205,7 @@ # set $jitemidwhere iff we have jitemids if (@$jitemids) { $jitemidwhere = " AND jitemid IN (" . - join(',', map { $_+0 } @$jitemids) . + join(',', map { $_ + 0 } @$jitemids) . ")"; } else { # no items, so show no entries @@ -1260,6 +1304,7 @@ # keep track of the last alldatepart, and a per-minute buffer my $last_time; my @buf; + my $flush = sub { return unless @buf; push @items, sort { $b->{itemid} <=> $a->{itemid} } @buf; @@ -1274,7 +1319,7 @@ $last_time = $li->{alldatepart}; # construct an LJ::Entry singleton - my $entry = LJ::Entry->new($userid, jitemid => $li->{itemid}); + my $entry = LJ::Entry->new($userid, jitemid => $li->{itemid}, rlogtime => $li->{rlogtime}); $entry->absorb_row($li); push @{$opts->{'entry_objects'}}, $entry; }