345 lines
12 KiB
Perl
345 lines
12 KiB
Perl
#!/usr/bin/perl
|
|
#
|
|
# 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.
|
|
|
|
use strict;
|
|
|
|
package LJ::S2;
|
|
use DW::Logic::AdultContent;
|
|
|
|
sub FriendsPage {
|
|
my ( $u, $remote, $opts ) = @_;
|
|
|
|
my $p = Page( $u, $opts );
|
|
$p->{'_type'} = "FriendsPage";
|
|
$p->{view} = $opts->{view} eq "network" ? "network" : "read";
|
|
$p->{'entries'} = [];
|
|
$p->{'friends'} = {};
|
|
$p->{'friends_title'} = LJ::ehtml( $u->{'friendspagetitle'} );
|
|
$p->{'friends_subtitle'} = LJ::ehtml( $u->{'friendspagesubtitle'} );
|
|
|
|
LJ::need_res( LJ::S2::tracking_popup_js() );
|
|
|
|
# include JS for quick reply, icon browser, and ajax cut tag
|
|
my $handle_with_siteviews = 0; # not an option for FriendsPage?
|
|
LJ::Talk::init_s2journal_js(
|
|
iconbrowser => 1,
|
|
siteskin => $handle_with_siteviews,
|
|
lastn => 1
|
|
);
|
|
|
|
my $collapsed = BML::ml('widget.cuttag.collapsed');
|
|
my $expanded = BML::ml('widget.cuttag.expanded');
|
|
my $collapseAll = BML::ml('widget.cuttag.collapseAll');
|
|
my $expandAll = BML::ml('widget.cuttag.expandAll');
|
|
$p->{'head_content'} .= qq[
|
|
<script type='text/javascript'>
|
|
expanded = '$expanded';
|
|
collapsed = '$collapsed';
|
|
collapseAll = '$collapseAll';
|
|
expandAll = '$expandAll';
|
|
</script>
|
|
];
|
|
|
|
# init shortcut js if selected
|
|
LJ::Talk::init_s2journal_shortcut_js( $remote, $p );
|
|
|
|
my $sth;
|
|
my $user = $u->{'user'};
|
|
|
|
# see how often the remote user can reload this page.
|
|
# "friendsviewupdate" time determines what granularity time
|
|
# increments by for checking for new updates
|
|
my $nowtime = time();
|
|
|
|
# update delay specified by "friendsviewupdate"
|
|
my $newinterval = LJ::Capabilities::get_cap_min( $remote, "friendsviewupdate" ) || 1;
|
|
|
|
# when are we going to say page was last modified? back up to the
|
|
# most recent time in the past where $time % $interval == 0
|
|
my $lastmod = $nowtime;
|
|
$lastmod -= $lastmod % $newinterval;
|
|
|
|
# see if they have a previously cached copy of this page they
|
|
# might be able to still use.
|
|
if ( $opts->{'header'}->{'If-Modified-Since'} ) {
|
|
my $theirtime = LJ::http_to_time( $opts->{'header'}->{'If-Modified-Since'} );
|
|
|
|
# send back a 304 Not Modified if they say they've reloaded this
|
|
# document in the last $newinterval seconds:
|
|
my $uniq = BML::get_request()->notes->{uniq};
|
|
if ( $theirtime > $lastmod && !( $uniq && LJ::MemCache::get("loginout:$uniq") ) ) {
|
|
$opts->{'handler_return'} = 304;
|
|
return 1;
|
|
}
|
|
}
|
|
$opts->{'headers'}->{'Last-Modified'} = LJ::time_to_http($lastmod);
|
|
|
|
my $get = $opts->{'getargs'};
|
|
|
|
my $ret;
|
|
|
|
$remote->preload_props(
|
|
"opt_nctalklinks", "opt_stylemine", "opt_imagelinks", "opt_imageundef",
|
|
"opt_cut_disable_reading"
|
|
) if $remote;
|
|
|
|
# load options for image links
|
|
my ( $maximgwidth, $maximgheight ) = ( undef, undef );
|
|
( $maximgwidth, $maximgheight ) = ( $1, $2 )
|
|
if ( $remote
|
|
&& $remote->equals($u)
|
|
&& $remote->{opt_imagelinks}
|
|
&& $remote->{opt_imagelinks} =~ m/^(\d+)\|(\d+)$/ );
|
|
|
|
## never have spiders index friends pages (change too much, and some
|
|
## people might not want to be indexed)
|
|
$p->{'head_content'} .= LJ::robot_meta_tags();
|
|
|
|
my $itemshow = S2::get_property_value( $opts->{'ctx'}, "num_items_reading" ) + 0;
|
|
if ( $itemshow < 1 ) { $itemshow = 20; }
|
|
elsif ( $itemshow > 50 ) { $itemshow = 50; }
|
|
|
|
my $skip = $get->{skip} ? $get->{skip} + 0 : 0;
|
|
my $maxskip = ( $LJ::MAX_SCROLLBACK_FRIENDS || 1000 ) - $itemshow;
|
|
if ( $skip > $maxskip ) { $skip = $maxskip; }
|
|
if ( $skip < 0 ) { $skip = 0; }
|
|
my $itemload = $itemshow + $skip;
|
|
my $get_date = $get->{date} || '';
|
|
|
|
my $events_date =
|
|
( $get_date =~ m!^(\d{4})-(\d\d)-(\d\d)$! )
|
|
? LJ::mysqldate_to_time("$1-$2-$3")
|
|
: 0;
|
|
|
|
# allow toggling network mode
|
|
$p->{friends_mode} = 'network'
|
|
if $opts->{view} eq 'network';
|
|
|
|
# try to get a group name if they specified one
|
|
my $group_name = '';
|
|
if ( $group_name = $opts->{pathextra} ) {
|
|
$group_name =~ s!^/!!;
|
|
$group_name =~ s!/$!!;
|
|
$group_name = LJ::durl($group_name);
|
|
}
|
|
|
|
# try to get a content filter, try a specified group name first, fall back to Default,
|
|
# and failing that try Default View (for the old school diehards)
|
|
my $cf = $u->content_filters( name => $group_name || "Default" )
|
|
|| $u->content_filters( name => "Default View" );
|
|
|
|
my $filter;
|
|
if ( $opts->{securityfilter} ) {
|
|
my $filter = $u->trust_groups( id => $opts->{securityfilter} );
|
|
$p->{filter_active} = 1;
|
|
if ( defined $filter ) {
|
|
$p->{filter_name} = $filter->{groupname};
|
|
}
|
|
else {
|
|
# something went wrong; just use the group number
|
|
$p->{filter_name} = $opts->{securityfilter};
|
|
}
|
|
}
|
|
else {
|
|
# but we can't just use a filter, we have to make sure the person is allowed to
|
|
if ( ( !defined $get->{filter} || $get->{filter} ne "0" )
|
|
&& $cf
|
|
&& ( $u->equals($remote) || $cf->public ) )
|
|
{
|
|
$filter = $cf;
|
|
|
|
# if we couldn't use the group, then we can throw an error, but ONLY IF they specified
|
|
# a group name manually. if we tried to load the default on our own, don't toss an
|
|
# error as that would let a user disable their friends page.
|
|
}
|
|
elsif ($group_name) {
|
|
$opts->{badfriendgroup} = 1; # nobiscuit
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
if ( $filter && !$filter->is_default ) {
|
|
$p->{filter_active} = 1;
|
|
$p->{filter_name} = $filter->name;
|
|
}
|
|
|
|
## load the itemids
|
|
my ( %friends, %friends_row, %idsbycluster );
|
|
my @items = $u->watch_items(
|
|
itemshow => $itemshow + 1,
|
|
skip => $skip,
|
|
content_filter => $filter,
|
|
friends_u => \%friends,
|
|
friends => \%friends_row,
|
|
idsbycluster => \%idsbycluster,
|
|
showtypes => $get->{show},
|
|
friendsoffriends => $opts->{view} eq 'network',
|
|
security => $opts->{securityfilter},
|
|
dateformat => 'S2',
|
|
events_date => $events_date,
|
|
);
|
|
|
|
my $is_prev_exist = scalar @items - $itemshow > 0 ? 1 : 0;
|
|
pop @items if $is_prev_exist;
|
|
|
|
while ( $_ = each %friends ) {
|
|
|
|
# we expect fgcolor/bgcolor to be in here later
|
|
$friends{$_}->{'fgcolor'} = $friends_row{$_}->{'fgcolor'} || '#ffffff';
|
|
$friends{$_}->{'bgcolor'} = $friends_row{$_}->{'bgcolor'} || '#000000';
|
|
}
|
|
|
|
return $p unless %friends;
|
|
|
|
my %posters;
|
|
{
|
|
my @posterids;
|
|
foreach my $item (@items) {
|
|
next if $friends{ $item->{'posterid'} };
|
|
push @posterids, $item->{'posterid'};
|
|
}
|
|
LJ::load_userids_multiple( [ map { $_ => \$posters{$_} } @posterids ] )
|
|
if @posterids;
|
|
}
|
|
|
|
my $eventnum = 0;
|
|
my $hiddenentries = 0;
|
|
$opts->{cut_disable} = ( $remote && $remote->prop('opt_cut_disable_reading') );
|
|
|
|
ENTRY:
|
|
foreach my $item (@items) {
|
|
my ( $friendid, $posterid, $itemid, $anum ) =
|
|
map { $item->{$_} } qw(ownerid posterid itemid anum);
|
|
|
|
# $fr = journal posted in, can be community
|
|
my $fr = $friends{$friendid};
|
|
$p->{friends}->{ $fr->{user} } ||= Friend($fr);
|
|
|
|
my $ditemid = $itemid * 256 + $anum;
|
|
my $entry_obj = LJ::Entry->new( $fr, ditemid => $ditemid );
|
|
|
|
# get the poster user
|
|
my $po = $posters{$posterid} || $friends{$posterid};
|
|
|
|
# don't allow posts from suspended users or suspended posts
|
|
if ( $po->is_suspended || ( $entry_obj && $entry_obj->is_suspended_for($remote) ) ) {
|
|
$hiddenentries++; # Remember how many we've skipped for later
|
|
next ENTRY;
|
|
}
|
|
|
|
# reading page might need placeholder images
|
|
$opts->{cleanhtml_extra} = {
|
|
maximgheight => $maximgheight,
|
|
maximgwidth => $maximgwidth,
|
|
imageplaceundef => $remote ? $remote->{'opt_imageundef'} : undef
|
|
};
|
|
|
|
# make S2 entry
|
|
my $entry = Entry_from_entryobj( $u, $entry_obj, $opts );
|
|
|
|
$entry->{_ymd} = join( '-', map { $entry->{'time'}->{$_} } qw(year month day) );
|
|
|
|
push @{ $p->{'entries'} }, $entry;
|
|
$eventnum++;
|
|
|
|
LJ::Hooks::run_hook( 'notify_event_displayed', $entry_obj );
|
|
} # end while
|
|
|
|
# set the new_day and end_day members.
|
|
if ($eventnum) {
|
|
for ( my $i = 0 ; $i < $eventnum ; $i++ ) {
|
|
my $entry = $p->{'entries'}->[$i];
|
|
$entry->{'new_day'} = 1;
|
|
my $last = $i;
|
|
for ( my $j = $i + 1 ; $j < $eventnum ; $j++ ) {
|
|
my $ej = $p->{'entries'}->[$j];
|
|
if ( $ej->{'_ymd'} eq $entry->{'_ymd'} ) {
|
|
$last = $j;
|
|
}
|
|
}
|
|
$p->{'entries'}->[$last]->{'end_day'} = 1;
|
|
$i = $last;
|
|
}
|
|
}
|
|
|
|
# make the skip links
|
|
my $nav = {
|
|
'_type' => 'RecentNav',
|
|
'version' => 1,
|
|
'skip' => $skip,
|
|
'count' => $eventnum,
|
|
};
|
|
|
|
my $base = "$u->{_journalbase}/$opts->{view}";
|
|
$base .= "/" . LJ::eurl($group_name)
|
|
if $group_name;
|
|
|
|
# these are the same for both previous and next links
|
|
my %linkvars;
|
|
$linkvars{show} = $get->{show} if defined $get->{show} && $get->{show} =~ /^\w+$/;
|
|
$linkvars{date} = $get->{date} if $get->{date} && $u->can_use_daily_readpage;
|
|
$linkvars{filter} = $get->{filter} + 0 if defined $get->{filter};
|
|
|
|
# if we've skipped down, then we can skip back up
|
|
if ($skip) {
|
|
my $newskip = $skip - $itemshow;
|
|
if ( $newskip > 0 ) { $linkvars{'skip'} = $newskip; }
|
|
else { $newskip = 0; }
|
|
$nav->{'forward_url'} = LJ::S2::make_link( $base, \%linkvars );
|
|
$nav->{'forward_skip'} = $newskip;
|
|
$nav->{'forward_count'} = $itemshow;
|
|
$p->{head_content} .= qq#<link rel="next" href="$nav->{forward_url}" />\n#;
|
|
}
|
|
elsif ( $linkvars{date} ) {
|
|
|
|
# next day when viewing by date
|
|
my %nextvars = %linkvars;
|
|
my $nexttime = LJ::mysqldate_to_time( $linkvars{date} ) + 86400;
|
|
unless ( $nexttime > time ) {
|
|
$nextvars{date} = LJ::mysql_date($nexttime);
|
|
$nav->{'forward_url'} = LJ::S2::make_link( $base, \%nextvars );
|
|
$p->{head_content} .= qq#<link rel="next" href="$nav->{forward_url}" />\n#;
|
|
}
|
|
}
|
|
|
|
## unless we didn't even load as many as we were expecting on this
|
|
## page, then there are more (unless there are exactly the number shown
|
|
## on the page, but who cares about that ... well, we do now...)
|
|
# Must remember to count $hiddenentries or we'll have no skiplinks when > 1
|
|
unless ( ( $eventnum + $hiddenentries ) != $itemshow || $skip == $maxskip || !$is_prev_exist ) {
|
|
my $newskip = $skip + $itemshow;
|
|
$linkvars{'skip'} = $newskip;
|
|
$nav->{'backward_url'} = LJ::S2::make_link( $base, \%linkvars );
|
|
$nav->{'backward_skip'} = $newskip;
|
|
$nav->{'backward_count'} = $itemshow;
|
|
$p->{head_content} .= qq#<link rel="prev" href="$nav->{backward_url}" />\n#;
|
|
}
|
|
elsif ( $linkvars{date} ) {
|
|
|
|
# prev day when viewing by date
|
|
my %prevvars = %linkvars;
|
|
my $prevtime = LJ::mysqldate_to_time( $linkvars{date} ) - 86400;
|
|
$prevvars{date} = LJ::mysql_date($prevtime);
|
|
delete $prevvars{skip}; # from forward case; not used here
|
|
$nav->{'backward_url'} = LJ::S2::make_link( $base, \%prevvars );
|
|
$p->{head_content} .= qq#<link rel="prev" href="$nav->{backward_url}" />\n#;
|
|
}
|
|
|
|
$p->{nav} = $nav;
|
|
|
|
return $p;
|
|
}
|
|
|
|
1;
|