init
This commit is contained in:
124
local/cgi-bin/LJ/Auth.pm
Normal file
124
local/cgi-bin/LJ/Auth.pm
Normal file
@@ -0,0 +1,124 @@
|
||||
# This is the LiveJournal Authentication module.
|
||||
# It contains useful authentication methods.
|
||||
|
||||
package LJ::Auth;
|
||||
use strict;
|
||||
use Digest::HMAC_SHA1 qw(hmac_sha1_hex);
|
||||
use Digest::SHA1 qw(sha1_hex);
|
||||
use Carp qw (croak);
|
||||
|
||||
# Generate an auth token for AJAX requests to use.
|
||||
# Arguments: ($remote, $action, %postvars)
|
||||
# $remote: remote user object
|
||||
# $uri: what uri this is for
|
||||
# %postvars: the expected post variables
|
||||
# Returns: Auth token good for the current hour
|
||||
sub ajax_auth_token {
|
||||
my ($class, $remote, $uri, %postvars) = @_;
|
||||
|
||||
$remote = LJ::want_user($remote) || LJ::get_remote();
|
||||
|
||||
croak "No URI specified" unless $uri;
|
||||
|
||||
my ($stime, $secret) = LJ::get_secret();
|
||||
my $postvars = join('&', map { $postvars{$_} } sort keys %postvars);
|
||||
my $remote_session_id = $remote && $remote->session ? $remote->session->id : LJ::UniqCookie->current_uniq;
|
||||
my $remote_userid = $remote ? $remote->id : 0;
|
||||
|
||||
my $chalbare = qq {ajax:$stime:$remote_userid:$remote_session_id:$uri:$postvars};
|
||||
my $chalsig = sha1_hex($chalbare, $secret);
|
||||
return qq{$chalbare:$chalsig};
|
||||
}
|
||||
|
||||
# Checks an auth token sent by an ajax request
|
||||
# Arguments: $remote, $uri, %POST variables
|
||||
# Returns: bool whether or not key is good
|
||||
sub check_ajax_auth_token {
|
||||
my ($class, $remote, $uri, %postvars) = @_;
|
||||
|
||||
$remote = LJ::want_user($remote) || LJ::get_remote();
|
||||
|
||||
# get auth token out of post vars
|
||||
my $auth_token = delete $postvars{auth_token} or return 0;
|
||||
|
||||
# recompute post vars
|
||||
my $postvars = join('&', map { $postvars{$_} } sort keys %postvars);
|
||||
|
||||
# get vars out of token string
|
||||
my ($c_ver, $stime, $remoteid, $sessid, $chal_uri, $chal_postvars, $chalsig) = split(':', $auth_token);
|
||||
|
||||
# get secret based on $stime
|
||||
my $secret = LJ::get_secret($stime);
|
||||
|
||||
# no time?
|
||||
return 0 unless $stime && $secret;
|
||||
|
||||
# right version?
|
||||
return 0 unless $c_ver eq 'ajax';
|
||||
|
||||
# in logged-out case $remoteid is 0 and $sessid is uniq_cookie
|
||||
my $req_remoteid = $remoteid > 0 ? $remote->id : 0;
|
||||
my $req_sessid = $remoteid > 0 ? $remote->session->id : LJ::UniqCookie->current_uniq;
|
||||
|
||||
|
||||
# do signitures match?
|
||||
my $chalbare = qq {$c_ver:$stime:$remoteid:$sessid:$chal_uri:$chal_postvars};
|
||||
my $realsig = sha1_hex($chalbare, $secret);
|
||||
return 0 unless $realsig eq $chalsig;
|
||||
|
||||
return 0 unless
|
||||
$remoteid == $req_remoteid && # remote id matches or logged-out 0=0
|
||||
$sessid == $req_sessid && # remote sessid or logged-out uniq cookie match
|
||||
$uri eq $chal_uri && # uri matches
|
||||
$postvars eq $chal_postvars; # post vars to uri
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# this is similar to the above methods but doesn't require a session or remote
|
||||
sub sessionless_auth_token {
|
||||
my ($class, $uri, %reqvars) = @_;
|
||||
|
||||
croak "No URI specified" unless $uri;
|
||||
|
||||
my ($stime, $secret) = LJ::get_secret();
|
||||
my $reqvars = join('&', map { $reqvars{$_} } sort keys %reqvars);
|
||||
|
||||
my $chalbare = qq {sessionless:$stime:$uri:$reqvars};
|
||||
my $chalsig = sha1_hex($chalbare, $secret);
|
||||
return qq{$chalbare:$chalsig};
|
||||
}
|
||||
|
||||
sub check_sessionless_auth_token {
|
||||
my ($class, $uri, %reqvars) = @_;
|
||||
|
||||
# get auth token out of post vars
|
||||
my $auth_token = delete $reqvars{auth_token} or return 0;
|
||||
|
||||
# recompute post vars
|
||||
my $reqvars = join('&', map { $reqvars{$_} } sort keys %reqvars);
|
||||
|
||||
# get vars out of token string
|
||||
my ($c_ver, $stime, $chal_uri, $chal_reqvars, $chalsig) = split(':', $auth_token);
|
||||
|
||||
# get secret based on $stime
|
||||
my $secret = LJ::get_secret($stime);
|
||||
|
||||
# no time?
|
||||
return 0 unless $stime && $secret;
|
||||
|
||||
# right version?
|
||||
return 0 unless $c_ver eq 'sessionless';
|
||||
|
||||
# do signitures match?
|
||||
my $chalbare = qq {$c_ver:$stime:$chal_uri:$chal_reqvars};
|
||||
my $realsig = sha1_hex($chalbare, $secret);
|
||||
return 0 unless $realsig eq $chalsig;
|
||||
|
||||
# do other vars match?
|
||||
return 0 unless $uri eq $chal_uri && $reqvars eq $chal_reqvars;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
1;
|
||||
21
local/cgi-bin/LJ/CSS/Cleaner.pm
Normal file
21
local/cgi-bin/LJ/CSS/Cleaner.pm
Normal file
@@ -0,0 +1,21 @@
|
||||
package LJ::CSS::Cleaner;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
no warnings 'redefine';
|
||||
|
||||
use base 'CSS::Cleaner';
|
||||
|
||||
sub new {
|
||||
my $class = shift;
|
||||
return $class->SUPER::new( @_,
|
||||
pre_hook => sub {
|
||||
my $rref = shift;
|
||||
|
||||
$$rref =~ s/comment-bake-cookie/CLEANED/g;
|
||||
return;
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
1;
|
||||
47
local/cgi-bin/LJ/ConvUTF8.pm
Normal file
47
local/cgi-bin/LJ/ConvUTF8.pm
Normal file
@@ -0,0 +1,47 @@
|
||||
# this is a small wrapper around Unicode::MapUTF8, just so we can lazily-load it easier
|
||||
# with Class::Autouse, and so we have a central place to init its charset aliases.
|
||||
# and in the future if we switch transcoding packages, we can just do it here.
|
||||
package LJ::ConvUTF8;
|
||||
|
||||
use strict;
|
||||
use warnings;
|
||||
use Unicode::MapUTF8 ();
|
||||
|
||||
BEGIN {
|
||||
# declare some charset aliases
|
||||
# we need this at least for cases when the only name supported
|
||||
# by MapUTF8.pm isn't recognized by browsers
|
||||
# note: newer versions of MapUTF8 know these
|
||||
{
|
||||
my %alias = ( 'windows-1251' => 'cp1251',
|
||||
'windows-1252' => 'cp1252',
|
||||
'windows-1253' => 'cp1253', );
|
||||
foreach (keys %alias) {
|
||||
next if Unicode::MapUTF8::utf8_supported_charset($_);
|
||||
Unicode::MapUTF8::utf8_charset_alias($_, $alias{$_});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sub load {
|
||||
1;
|
||||
}
|
||||
|
||||
sub supported_charset {
|
||||
my ($class, $charset) = @_;
|
||||
return Unicode::MapUTF8::utf8_supported_charset($charset);
|
||||
}
|
||||
|
||||
sub from_utf8 {
|
||||
my ($class, $from_enc, $str) = @_;
|
||||
return Unicode::MapUTF8::from_utf8({ -string=> $str, -charset => $from_enc });
|
||||
}
|
||||
|
||||
sub to_utf8 {
|
||||
my ($class, $to_enc, $str) = @_;
|
||||
return Unicode::MapUTF8::to_utf8({ -string=> $str, -charset => $to_enc });
|
||||
}
|
||||
|
||||
1;
|
||||
|
||||
|
||||
466
local/cgi-bin/LJ/EmbedModule.pm
Normal file
466
local/cgi-bin/LJ/EmbedModule.pm
Normal file
@@ -0,0 +1,466 @@
|
||||
#!/usr/bin/perl
|
||||
package LJ::EmbedModule;
|
||||
use strict;
|
||||
use Carp qw (croak);
|
||||
use Class::Autouse qw (
|
||||
LJ::Auth
|
||||
HTML::TokeParser
|
||||
);
|
||||
|
||||
# states for a finite-state machine we use in parse()
|
||||
use constant {
|
||||
# reading plain html without <object>, <embed> or <lj-embed>
|
||||
REGULAR => 1,
|
||||
# inside <object> or <embed> tag
|
||||
IMPLICIT => 2,
|
||||
# inside explicit <lj-embed> tag
|
||||
EXPLICIT => 3,
|
||||
# maximum embed width and height
|
||||
MAX_WIDTH => 800,
|
||||
MAX_HEIGHT => 800,
|
||||
};
|
||||
|
||||
# can optionally pass in an id of a module to change its contents
|
||||
# returns module id
|
||||
sub save_module {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
my $contents = $opts{contents} || '';
|
||||
my $id = $opts{id};
|
||||
my $journal = $opts{journal}
|
||||
or croak "No journal passed to LJ::EmbedModule::save_module";
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# are we creating a new entry?
|
||||
unless (defined $id) {
|
||||
$id = LJ::alloc_user_counter($journal, 'D')
|
||||
or die "Could not allocate embed module ID";
|
||||
}
|
||||
|
||||
my $cmptext = 'C-' . LJ::text_compress($contents);
|
||||
|
||||
## embeds for preview are stored in a special table,
|
||||
## where new items overwrites old ones
|
||||
my $table_name = ($preview) ? 'embedcontent_preview' : 'embedcontent';
|
||||
$journal->do("REPLACE INTO $table_name (userid, moduleid, content) VALUES ".
|
||||
"(?, ?, ?)", undef, $journal->{'userid'}, $id, $cmptext);
|
||||
die $journal->errstr if $journal->err;
|
||||
|
||||
# save in memcache
|
||||
my $memkey = $class->memkey($journal->{'userid'}, $id, $preview);
|
||||
LJ::MemCache::set($memkey, $contents);
|
||||
|
||||
return $id;
|
||||
}
|
||||
|
||||
# changes <div class="ljembed"... tags from the RTE into proper lj-embed tags
|
||||
sub transform_rte_post {
|
||||
my ($class, $txt) = @_;
|
||||
return $txt unless $txt && $txt =~ /ljembed/i;
|
||||
# ghetto... shouldn't use regexes to parse this
|
||||
$txt =~ s/<div\s*class="ljembed"\s*(embedid="(\d+)")?\s*>(((?!<\/div>).)*)<\/div>/<lj-embed id="$2">$3<\/lj-embed>/ig;
|
||||
$txt =~ s/<div\s*(embedid="(\d+)")?\s*class="ljembed"\s*>(((?!<\/div>).)*)<\/div>/<lj-embed id="$2">$3<\/lj-embed>/ig;
|
||||
return $txt;
|
||||
}
|
||||
|
||||
# takes a scalarref to entry text and expands lj-embed tags
|
||||
# REPLACE
|
||||
sub expand_entry {
|
||||
my ($class, $journal, $entryref, %opts) = @_;
|
||||
|
||||
$$entryref =~ s/(<lj\-embed[^>]+\/>)/$class->_expand_tag($journal, $1, $opts{edit}, %opts)/ge;
|
||||
}
|
||||
|
||||
sub _expand_tag {
|
||||
my $class = shift;
|
||||
my $journal = shift;
|
||||
my $tag = shift;
|
||||
my $edit = shift;
|
||||
my %opts = @_;
|
||||
|
||||
my %attrs = $tag =~ /(\w+)="?(\-?\d+)"?/g;
|
||||
|
||||
return '[invalid lj-embed, id is missing]' unless $attrs{id};
|
||||
|
||||
if ($edit) {
|
||||
return '<lj-embed ' . join(' ', map {"$_=\"$attrs{$_}\""} keys %attrs) . ">\n" .
|
||||
$class->module_content(moduleid => $attrs{id}, journalid => $journal->id) .
|
||||
"\n<\/lj-embed>";
|
||||
}
|
||||
elsif ($opts{'content_only'}) {
|
||||
return $class->module_content(moduleid => $attrs{id}, journalid => $journal->{'userid'});
|
||||
}
|
||||
else {
|
||||
@opts{qw /width height/} = @attrs{qw/width height/};
|
||||
return $class->module_iframe_tag($journal, $attrs{id}, %opts)
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
# take a scalarref to a post, parses any lj-embed tags, saves the contents
|
||||
# of the tags and replaces them with a module tag with the id.
|
||||
# REPLACE
|
||||
sub parse_module_embed {
|
||||
my ($class, $journal, $postref, %opts) = @_;
|
||||
|
||||
return unless $postref && $$postref;
|
||||
|
||||
return if LJ::conf_test($LJ::DISABLED{embed_module});
|
||||
|
||||
# fast track out if we don't have to expand anything
|
||||
return unless $$postref =~ /lj\-embed|embed|object/i;
|
||||
|
||||
# do we want to replace with the lj-embed tags or iframes?
|
||||
my $expand = $opts{expand};
|
||||
|
||||
# if this is editing mode, then we want to expand embed tags for editing
|
||||
my $edit = $opts{edit};
|
||||
|
||||
# previews are a special case (don't want to permanantly save to db)
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# deal with old-fashion calls
|
||||
if (($edit || $expand) && ! $preview) {
|
||||
return $class->expand_entry($journal, $postref, %opts);
|
||||
}
|
||||
|
||||
# ok, we can safely parse post text
|
||||
# machine state
|
||||
my $state = REGULAR;
|
||||
my $p = HTML::TokeParser->new($postref);
|
||||
my $newtxt = '';
|
||||
my %embed_attrs = (); # ($eid, $ewidth, $eheight);
|
||||
my $embed = '';
|
||||
my @stack = ();
|
||||
my $next_preview_id = 1;
|
||||
|
||||
while (my $token = $p->get_token) {
|
||||
my ($type, $tag, $attr) = @$token;
|
||||
$tag = lc $tag;
|
||||
my $newstate = undef;
|
||||
my $reconstructed = $class->reconstruct($token);
|
||||
|
||||
if ($state == REGULAR) {
|
||||
if ($tag eq 'lj-embed' && $type eq 'S' && ! $attr->{'/'}) {
|
||||
# <lj-embed ...>, not self-closed
|
||||
# switch to EXPLICIT state
|
||||
$newstate = EXPLICIT;
|
||||
# save embed id, width and height if they do exist in attributes
|
||||
$embed_attrs{id} = $attr->{id} if $attr->{id};
|
||||
$embed_attrs{width} = ($attr->{width} > MAX_WIDTH ? MAX_WIDTH : $attr->{width}) if $attr->{width};
|
||||
$embed_attrs{height} = ($attr->{height} > MAX_HEIGHT ? MAX_HEIGHT : $attr->{height}) if $attr->{height};
|
||||
} elsif (($tag eq 'object' || $tag eq 'embed') && $type eq 'S') {
|
||||
# <object> or <embed>
|
||||
# switch to IMPLICIT state unless it is a self-closed tag
|
||||
unless ($attr->{'/'}) {
|
||||
$newstate = IMPLICIT;
|
||||
# tag balance
|
||||
push @stack, $tag;
|
||||
}
|
||||
# append the tag contents to new embed buffer, so we can convert in to lj-embed later
|
||||
$embed .= $reconstructed;
|
||||
} else {
|
||||
# otherwise stay in REGULAR
|
||||
$newtxt .= $reconstructed;
|
||||
}
|
||||
} elsif ($state == IMPLICIT) {
|
||||
if ($tag eq 'object' || $tag eq 'embed') {
|
||||
if ($type eq 'E') {
|
||||
# </object> or </embed>
|
||||
# update tag balance, but only if we have a valid balance up to this moment
|
||||
pop @stack if $stack[-1] eq $tag;
|
||||
# switch to REGULAR if tags are balanced (stack is empty), stay in IMPLICIT otherwise
|
||||
$newstate = REGULAR unless @stack;
|
||||
} elsif ($type eq 'S') {
|
||||
# <object> or <embed>
|
||||
# mind the tag balance, do not update it in case of a self-closed tag
|
||||
push @stack, $tag unless $attr->{'/'};
|
||||
}
|
||||
}
|
||||
# append to embed buffer
|
||||
$embed .= $reconstructed;
|
||||
|
||||
} elsif ($state == EXPLICIT) {
|
||||
|
||||
if ($tag eq 'lj-embed' && $type eq 'E') {
|
||||
# </lj-embed> - that's the end of explicit embed block, switch to REGULAR
|
||||
$newstate = REGULAR;
|
||||
} else {
|
||||
# continue appending contents to embed buffer
|
||||
$embed .= $reconstructed;
|
||||
}
|
||||
} else {
|
||||
# let's be paranoid
|
||||
die "Invalid state: '$state'";
|
||||
}
|
||||
|
||||
# we decided to switch back to REGULAR and have something in embed buffer
|
||||
# so let's save buffer as an embed module and start all over again
|
||||
if (defined($newstate) && $newstate == REGULAR && $embed) {
|
||||
$embed_attrs{id} = $class->save_module(
|
||||
id => ($preview ? $next_preview_id++ : $embed_attrs{id}),
|
||||
contents => $embed,
|
||||
journal => $journal,
|
||||
preview => $preview,
|
||||
);
|
||||
|
||||
$newtxt .= "<lj-embed " . join(' ', map { exists $embed_attrs{$_} ? "$_=\"$embed_attrs{$_}\"" : () } qw / id width height /) . "/>";
|
||||
|
||||
$embed = '';
|
||||
%embed_attrs = ();
|
||||
}
|
||||
|
||||
# switch the state if we have a new one
|
||||
$state = $newstate if defined $newstate;
|
||||
|
||||
}
|
||||
|
||||
# update passed text
|
||||
$$postref = $newtxt;
|
||||
}
|
||||
|
||||
sub module_iframe_tag {
|
||||
my ($class, $u, $moduleid, %opts) = @_;
|
||||
|
||||
return '' if $LJ::DISABLED{embed_module};
|
||||
|
||||
my $journalid = $u->{'userid'};
|
||||
$moduleid += 0;
|
||||
|
||||
# parse the contents of the module and try to come up with a guess at the width and height of the content
|
||||
my $content = $class->module_content(moduleid => $moduleid, journalid => $journalid);
|
||||
my $preview = $opts{preview};
|
||||
my $width = 0;
|
||||
my $height = 0;
|
||||
my $p = HTML::TokeParser->new(\$content);
|
||||
my $embedcodes;
|
||||
|
||||
# if the content only contains a whitelisted embedded video
|
||||
# then we can skip the placeholders (in some cases)
|
||||
my $no_whitelist = 0;
|
||||
my $found_embed = 0;
|
||||
|
||||
# we don't need to estimate the dimensions if they are provided in tag attributes
|
||||
unless ($opts{width} && $opts{height}) {
|
||||
while (my $token = $p->get_token) {
|
||||
my $type = $token->[0];
|
||||
my $tag = $token->[1] ? lc $token->[1] : '';
|
||||
my $attr = $token->[2]; # hashref
|
||||
|
||||
if ($type eq "S") {
|
||||
my ($elewidth, $eleheight);
|
||||
|
||||
if ($attr->{width}) {
|
||||
$elewidth = $attr->{width}+0;
|
||||
$width = $elewidth if $elewidth > $width;
|
||||
}
|
||||
if ($attr->{height}) {
|
||||
$eleheight = $attr->{height}+0;
|
||||
$height = $eleheight if $eleheight > $height;
|
||||
}
|
||||
|
||||
my $flashvars = $attr->{flashvars};
|
||||
|
||||
if ($tag eq 'object' || $tag eq 'embed') {
|
||||
my $src;
|
||||
next unless $src = $attr->{src};
|
||||
|
||||
# we have an object/embed tag with src, make a fake lj-template object
|
||||
my @tags = (
|
||||
['S', 'lj-template', {
|
||||
name => 'video',
|
||||
(defined $elewidth ? ( width => $width ) : ()),
|
||||
(defined $eleheight ? ( height => $height ) : ()),
|
||||
(defined $flashvars ? ( flashvars => $flashvars ) : ()),
|
||||
}],
|
||||
[ 'T', $src, {}],
|
||||
['E', 'lj-template', {}],
|
||||
);
|
||||
|
||||
$embedcodes = LJ::run_hook('expand_template_video', \@tags);
|
||||
|
||||
$found_embed = 1 if $embedcodes;
|
||||
$found_embed &&= $embedcodes !~ /Invalid video/i;
|
||||
|
||||
$no_whitelist = !$found_embed;
|
||||
} elsif ($tag ne 'param') {
|
||||
$no_whitelist = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# add padding
|
||||
$width += 50 if $width;
|
||||
$height += 50 if $height;
|
||||
}
|
||||
|
||||
# use explicit values if we have them
|
||||
$width = $opts{width} if $opts{width};
|
||||
$height = $opts{height} if $opts{height};
|
||||
|
||||
$width ||= 240;
|
||||
$height ||= 200;
|
||||
|
||||
# some dimension min/maxing
|
||||
$width = 50 if $width < 50;
|
||||
$width = MAX_WIDTH if $width > MAX_WIDTH;
|
||||
$height = 50 if $height < 50;
|
||||
$height = MAX_HEIGHT if $height > MAX_HEIGHT;
|
||||
|
||||
# safari caches state of sub-resources aggressively, so give
|
||||
# each iframe a unique 'name' attribute
|
||||
my $id = qq(name="embed_${journalid}_$moduleid");
|
||||
|
||||
my $auth_token = LJ::eurl(LJ::Auth->sessionless_auth_token('embedcontent', moduleid => $moduleid, journalid => $journalid, preview => $preview,));
|
||||
my $iframe_url = qq {http://$LJ::EMBED_MODULE_DOMAIN/tools/embedcontent.bml?journalid=$journalid&moduleid=$moduleid&preview=$preview&auth_token=$auth_token};
|
||||
my $iframe_tag = qq {<iframe src="$iframe_url" } .
|
||||
qq{width="$width" height="$height" allowtransparency="true" frameborder="0" class="lj_embedcontent" $id></iframe>};
|
||||
|
||||
my $remote = LJ::get_remote();
|
||||
my $do_placeholder;
|
||||
|
||||
if ($remote) {
|
||||
return $iframe_tag if $opts{edit};
|
||||
|
||||
# show placeholder instead of iframe?
|
||||
LJ::load_user_props($remote, "opt_embedplaceholders");
|
||||
my $placeholder_prop = $remote->prop('opt_embedplaceholders');
|
||||
$do_placeholder = $placeholder_prop && $placeholder_prop ne 'N';
|
||||
|
||||
# if placeholder_prop is not set, then show placeholder on a friends
|
||||
# page view UNLESS the embedded content is only one embed/object
|
||||
# tag and it's whitelisted video.
|
||||
my $r = eval { Apache->request };
|
||||
my $view = $r ? $r->notes("view") : '';
|
||||
if (! $placeholder_prop && $view eq 'friends') {
|
||||
# show placeholder if this is not whitelisted video
|
||||
$do_placeholder = 1 if $no_whitelist;
|
||||
}
|
||||
}
|
||||
else {
|
||||
$do_placeholder = $BML::COOKIE{'flashpref'};
|
||||
$do_placeholder = 0 unless $do_placeholder eq "0" || $do_placeholder eq "1";
|
||||
}
|
||||
|
||||
return $iframe_tag unless $do_placeholder;
|
||||
|
||||
my $tmpcontent = $class->module_content(
|
||||
journalid => $journalid,
|
||||
moduleid => $moduleid,
|
||||
0
|
||||
);
|
||||
$tmpcontent =~ s/.+param\s+name\s*?=\s*?"?movie"?\s*value\s*?=\s*?"?//sg; #"
|
||||
$tmpcontent =~ s/("|\s).+//sg; #"
|
||||
$tmpcontent = LJ::ehtml($tmpcontent);
|
||||
|
||||
# placeholder
|
||||
return LJ::placeholder_link(
|
||||
placeholder_html => $iframe_tag,
|
||||
placeholder_link => $iframe_url,
|
||||
width => $width,
|
||||
height => $height,
|
||||
img => "$LJ::IMGPREFIX/videoplaceholder.png",
|
||||
img_title => $tmpcontent,
|
||||
);
|
||||
}
|
||||
|
||||
sub module_content {
|
||||
my ($class, %opts) = @_;
|
||||
|
||||
my $moduleid = $opts{moduleid};
|
||||
croak "No moduleid" unless defined $moduleid;
|
||||
$moduleid += 0;
|
||||
|
||||
my $journalid = $opts{journalid}+0 or croak "No journalid";
|
||||
my $journal = LJ::load_userid($journalid) or die "Invalid userid $journalid";
|
||||
my $preview = $opts{preview};
|
||||
|
||||
# try memcache
|
||||
my $memkey = $class->memkey($journalid, $moduleid, $preview);
|
||||
my $content = LJ::MemCache::get($memkey);
|
||||
my ($dbload, $dbid); # module id from the database
|
||||
unless (defined $content) {
|
||||
my $table_name = ($preview) ? 'embedcontent_preview' : 'embedcontent';
|
||||
($content, $dbid) = $journal->selectrow_array("SELECT content, moduleid FROM $table_name WHERE " .
|
||||
"moduleid=? AND userid=?",
|
||||
undef, $moduleid, $journalid);
|
||||
die $journal->errstr if $journal->err;
|
||||
$dbload = 1;
|
||||
}
|
||||
|
||||
$content ||= '';
|
||||
|
||||
LJ::text_uncompress(\$content) if $content =~ s/^C-//;
|
||||
|
||||
# clean js out of content
|
||||
unless ($LJ::DISABLED{'embedmodule-cleancontent'}) {
|
||||
LJ::CleanHTML::clean(\$content, {
|
||||
addbreaks => 0,
|
||||
tablecheck => 0,
|
||||
mode => 'allow',
|
||||
allow => [qw(object embed)],
|
||||
deny => [qw(script iframe)],
|
||||
remove => [qw(script iframe)],
|
||||
ljcut_disable => 1,
|
||||
cleancss => 0,
|
||||
extractlinks => 0,
|
||||
noautolinks => 1,
|
||||
extractimages => 0,
|
||||
noexpandembedded => 1,
|
||||
transform_embed_nocheck => 1,
|
||||
});
|
||||
}
|
||||
|
||||
# if we got stuff out of database
|
||||
if ($dbload) {
|
||||
# save in memcache
|
||||
LJ::MemCache::set($memkey, $content);
|
||||
|
||||
# if we didn't get a moduleid out of the database then this entry is not valid
|
||||
return defined $dbid ? $content : "[Invalid lj-embed id $moduleid]";
|
||||
}
|
||||
|
||||
# get rid of whitespace around the content
|
||||
return LJ::trim($content) || '';
|
||||
}
|
||||
|
||||
sub memkey {
|
||||
my ($class, $journalid, $moduleid, $preview) = @_;
|
||||
my $pfx = $preview ? 'embedcontpreview' : 'embedcont';
|
||||
return [$journalid, "$pfx:$journalid:$moduleid"];
|
||||
}
|
||||
|
||||
# create a tag string from HTML::TokeParser token
|
||||
sub reconstruct {
|
||||
my $class = shift;
|
||||
my $token = shift;
|
||||
my ($type, $tag, $attr, $attord) = @$token;
|
||||
if ($type eq 'S') {
|
||||
my $txt = "<$tag";
|
||||
my $selfclose;
|
||||
|
||||
# preserve order of attributes. the original order is
|
||||
# in element 4 of $token
|
||||
foreach my $name (@$attord) {
|
||||
if ($name eq '/') {
|
||||
$selfclose = 1;
|
||||
next;
|
||||
}
|
||||
|
||||
# FIXME: ultra ghetto.
|
||||
$attr->{$name} = LJ::no_utf8_flag($attr->{$name});
|
||||
|
||||
$txt .= " $name=\"" . LJ::ehtml($attr->{$name}) . "\"";
|
||||
}
|
||||
$txt .= $selfclose ? " />" : ">";
|
||||
|
||||
} elsif ($type eq 'E') {
|
||||
return "</$tag>";
|
||||
} else { # C, T, D or PI
|
||||
return $tag;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
1;
|
||||
|
||||
1138
local/cgi-bin/LJ/Entry.pm
Normal file
1138
local/cgi-bin/LJ/Entry.pm
Normal file
File diff suppressed because it is too large
Load Diff
184
local/cgi-bin/LJ/OpenID.pm
Executable file
184
local/cgi-bin/LJ/OpenID.pm
Executable file
@@ -0,0 +1,184 @@
|
||||
package LJ::OpenID;
|
||||
|
||||
use strict;
|
||||
use Digest::SHA1 qw(sha1 sha1_hex);
|
||||
use LWPx::ParanoidAgent;
|
||||
|
||||
BEGIN {
|
||||
$LJ::OPTMOD_OPENID_CONSUMER = $LJ::OPENID_CONSUMER ? eval "use Net::OpenID::Consumer; 1;" : 0;
|
||||
$LJ::OPTMOD_OPENID_SERVER = $LJ::OPENID_SERVER ? eval "use Net::OpenID::Server; 1;" : 0;
|
||||
}
|
||||
|
||||
# returns boolean whether consumer support is enabled and available
|
||||
sub consumer_enabled {
|
||||
return 0 unless $LJ::OPENID_CONSUMER;
|
||||
return $LJ::OPTMOD_OPENID_CONSUMER || eval "use Net::OpenID::Consumer; 1;";
|
||||
}
|
||||
|
||||
# returns boolean whether consumer support is enabled and available
|
||||
sub server_enabled {
|
||||
return 0 unless $LJ::OPENID_SERVER;
|
||||
return $LJ::OPTMOD_OPENID_CONSUMER || eval "use Net::OpenID::Server; 1;";
|
||||
}
|
||||
|
||||
sub server {
|
||||
my ($get, $post) = @_;
|
||||
|
||||
return Net::OpenID::Server->new(
|
||||
compat => $LJ::OPENID_COMPAT,
|
||||
get_args => $get || {},
|
||||
post_args => $post || {},
|
||||
|
||||
get_user => \&LJ::get_remote,
|
||||
is_identity => sub {
|
||||
my ($u, $ident) = @_;
|
||||
return LJ::OpenID::is_identity($u, $ident, $get);
|
||||
},
|
||||
is_trusted => \&LJ::OpenID::is_trusted,
|
||||
|
||||
setup_url => "$LJ::SITEROOT/openid/approve.bml",
|
||||
|
||||
server_secret => \&LJ::OpenID::server_secret,
|
||||
secret_gen_interval => 3600,
|
||||
secret_expire_age => 86400 * 14,
|
||||
);
|
||||
}
|
||||
|
||||
# Returns a Consumer object
|
||||
# When planning to verify identity, needs GET
|
||||
# arguments passed in
|
||||
sub consumer {
|
||||
my $get_args = shift || {};
|
||||
|
||||
my $ua;
|
||||
unless ($LJ::IS_DEV_SERVER) {
|
||||
$ua = LWPx::ParanoidAgent->new(
|
||||
timeout => 10,
|
||||
max_size => 1024*300,
|
||||
);
|
||||
}
|
||||
|
||||
my $csr = Net::OpenID::Consumer->new(
|
||||
ua => $ua,
|
||||
args => $get_args,
|
||||
cache => eval { LJ::MemCache::get_memcache() },
|
||||
consumer_secret => \&LJ::OpenID::consumer_secret,
|
||||
debug => $LJ::IS_DEV_SERVER || 0,
|
||||
required_root => $LJ::SITEROOT,
|
||||
);
|
||||
|
||||
return $csr;
|
||||
}
|
||||
|
||||
sub consumer_secret {
|
||||
my $time = shift;
|
||||
return server_secret($time - $time % 3600);
|
||||
}
|
||||
|
||||
sub server_secret {
|
||||
my $time = shift;
|
||||
my ($t2, $secret) = LJ::get_secret($time);
|
||||
die "ASSERT: didn't get t2 (t1=$time)" unless $t2;
|
||||
die "ASSERT: didn't get secret (t2=$t2)" unless $secret;
|
||||
die "ASSERT: time($time) != t2($t2)\n" unless $t2 == $time;
|
||||
return $secret;
|
||||
}
|
||||
|
||||
sub is_trusted {
|
||||
my ($u, $trust_root, $is_identity) = @_;
|
||||
return 0 unless $u;
|
||||
# we always look up $is_trusted, even if $is_identity is false, to avoid timing attacks
|
||||
|
||||
my $dbh = LJ::get_db_writer();
|
||||
my ($endpointid, $duration) = $dbh->selectrow_array("SELECT t.endpoint_id, t.duration ".
|
||||
"FROM openid_trust t, openid_endpoint e ".
|
||||
"WHERE t.userid=? AND t.endpoint_id=e.endpoint_id AND e.url=?",
|
||||
undef, $u->{userid}, $trust_root);
|
||||
return 0 unless $endpointid;
|
||||
return 1;
|
||||
}
|
||||
|
||||
sub is_identity {
|
||||
my ($u, $ident, $get) = @_;
|
||||
return 0 unless $u && $u->{journaltype} eq "P";
|
||||
|
||||
my $user = $u->{user};
|
||||
return 1 if
|
||||
$ident eq "$LJ::SITEROOT/users/$user/" ||
|
||||
$ident eq "$LJ::SITEROOT/~$user/" ||
|
||||
$ident eq "http://$user.$LJ::USER_DOMAIN/";
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
sub getmake_endpointid {
|
||||
my $site = shift;
|
||||
|
||||
my $dbh = LJ::get_db_writer()
|
||||
or return undef;
|
||||
|
||||
my $rv = $dbh->do("INSERT IGNORE INTO openid_endpoint (url) VALUES (?)", undef, $site);
|
||||
my $end_id;
|
||||
if ($rv > 0) {
|
||||
$end_id = $dbh->{'mysql_insertid'};
|
||||
} else {
|
||||
$end_id = $dbh->selectrow_array("SELECT endpoint_id FROM openid_endpoint WHERE url=?",
|
||||
undef, $site);
|
||||
}
|
||||
return $end_id;
|
||||
}
|
||||
|
||||
sub add_trust {
|
||||
my ($u, $site) = @_;
|
||||
|
||||
my $end_id = LJ::OpenID::getmake_endpointid($site)
|
||||
or return 0;
|
||||
|
||||
my $dbh = LJ::get_db_writer()
|
||||
or return undef;
|
||||
|
||||
my $rv = $dbh->do("REPLACE INTO openid_trust (userid, endpoint_id, duration, trust_time) ".
|
||||
"VALUES (?,?,?,UNIX_TIMESTAMP())", undef, $u->{userid}, $end_id, "always");
|
||||
return $rv;
|
||||
}
|
||||
|
||||
# From Digest::HMAC
|
||||
sub hmac_sha1_hex {
|
||||
unpack("H*", &hmac_sha1);
|
||||
}
|
||||
sub hmac_sha1 {
|
||||
hmac($_[0], $_[1], \&sha1, 64);
|
||||
}
|
||||
sub hmac {
|
||||
my($data, $key, $hash_func, $block_size) = @_;
|
||||
$block_size ||= 64;
|
||||
$key = &$hash_func($key) if length($key) > $block_size;
|
||||
|
||||
my $k_ipad = $key ^ (chr(0x36) x $block_size);
|
||||
my $k_opad = $key ^ (chr(0x5c) x $block_size);
|
||||
|
||||
&$hash_func($k_opad, &$hash_func($k_ipad, $data));
|
||||
}
|
||||
|
||||
# Returns 1 if destination identity server
|
||||
# is blocked
|
||||
sub blocked_hosts {
|
||||
my $csr = shift;
|
||||
|
||||
return do { my $dummy = 0; \$dummy; } if $LJ::IS_DEV_SERVER;
|
||||
|
||||
my $tried_local_id = 0;
|
||||
$csr->ua->blocked_hosts(
|
||||
sub {
|
||||
my $dest = shift;
|
||||
|
||||
if ($dest =~ /((^|\.)\Q$LJ::DOMAIN\E$|demotivation\.me|anonymity\.com)/i) {
|
||||
$tried_local_id = 1;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
});
|
||||
return \$tried_local_id;
|
||||
}
|
||||
|
||||
1;
|
||||
2739
local/cgi-bin/LJ/S2.pm
Executable file
2739
local/cgi-bin/LJ/S2.pm
Executable file
File diff suppressed because it is too large
Load Diff
232
local/cgi-bin/LJ/S2/DayPage.pm
Executable file
232
local/cgi-bin/LJ/S2/DayPage.pm
Executable file
@@ -0,0 +1,232 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub DayPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "DayPage";
|
||||
$p->{'view'} = "day";
|
||||
$p->{'entries'} = [];
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/calendar" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $month = $get->{'month'};
|
||||
my $day = $get->{'day'};
|
||||
my $year = $get->{'year'};
|
||||
my @errors = ();
|
||||
|
||||
if ($opts->{'pathextra'} =~ m!^/(\d\d\d\d)/(\d\d)/(\d\d)\b!) {
|
||||
($month, $day, $year) = ($2, $3, $1);
|
||||
}
|
||||
|
||||
$opts->{'errors'} = [];
|
||||
if ($year !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant year."; }
|
||||
if ($month !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant month."; }
|
||||
if ($day !~ /^\d+$/) { push @{$opts->{'errors'}}, "Corrupt or non-existant day."; }
|
||||
if ($month < 1 || $month > 12 || int($month) != $month) { push @{$opts->{'errors'}}, "Invalid month."; }
|
||||
if ($year < 1970 || $year > 2038 || int($year) != $year) { push @{$opts->{'errors'}}, "Invalid year: $year"; }
|
||||
if ($day < 1 || $day > 31 || int($day) != $day) { push @{$opts->{'errors'}}, "Invalid day."; }
|
||||
if (scalar(@{$opts->{'errors'}})==0 && $day > LJ::days_in_month($month, $year)) { push @{$opts->{'errors'}}, "That month doesn't have that many days."; }
|
||||
return if @{$opts->{'errors'}};
|
||||
|
||||
$p->{'date'} = Date($year, $month, $day);
|
||||
# mysqldate_to_time(): ^(\d\d\d\d)-(\d\d)-(\d\d)(?: (\d\d):(\d\d)(?::(\d\d))?)?$/ -> unixtime, with check.
|
||||
# why not using get_recent_items() ?
|
||||
|
||||
#use Time::HiRes qw(gettimeofday tv_interval);
|
||||
#my $t0 = [gettimeofday];
|
||||
#my @elapsed;
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
#print STDERR "@elapsed \n";
|
||||
|
||||
my $secwhere = "AND security='public'";
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0; # see public posts from suspended users
|
||||
if ($remote) {
|
||||
|
||||
# do they have the viewall priv?
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "day: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
if ($remote->{'userid'} == $u->{'userid'} || $viewall) {
|
||||
$secwhere = ""; # see everything
|
||||
} elsif ($remote->{'journaltype'} eq 'P' || $remote->{'journaltype'} eq 'I') {
|
||||
my $gmask = LJ::get_groupmask($u, $remote);
|
||||
$secwhere = "AND (security='public' OR (security='usemask' AND allowmask & $gmask))"
|
||||
if $gmask;
|
||||
}
|
||||
}
|
||||
|
||||
my $dbcr = LJ::get_cluster_reader($u);
|
||||
unless ($dbcr) {
|
||||
push @{$opts->{'errors'}}, "Database temporarily unavailable";
|
||||
return;
|
||||
}
|
||||
|
||||
# load the log items
|
||||
my $dateformat = "%Y %m %d %H %i %s %w"; # yyyy mm dd hh mm ss day_of_week
|
||||
my $sth = $dbcr->prepare("SELECT jitemid AS itemid, posterid, security, DATE_FORMAT(eventtime, \"$dateformat\") AS 'alldatepart', anum ".
|
||||
"FROM log2 " .
|
||||
"WHERE journalid=$u->{'userid'} AND year=$year AND month=$month AND day=$day $secwhere " .
|
||||
"ORDER BY eventtime, logtime LIMIT 200");
|
||||
$sth->execute;
|
||||
|
||||
my @items;
|
||||
push @items, $_ while $_ = $sth->fetchrow_hashref;
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
|
||||
LJ::fill_items_with_text_props(\@items, $u);
|
||||
|
||||
# load 'opt_ljcut_disable_lastn' prop for $remote.
|
||||
LJ::load_user_props($remote, "opt_ljcut_disable_lastn");
|
||||
|
||||
my (%apu, %apu_lite); # alt poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
next unless $_->{'posterid'} != $u->{'userid'};
|
||||
$apu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
if (%apu) {
|
||||
LJ::load_userids_multiple([map { $_, \$apu{$_} } keys %apu], [$u]);
|
||||
$apu_lite{$_} = UserLite($apu{$_}) foreach keys %apu;
|
||||
}
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart, $anum) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart anum);
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
# don't show posts from suspended users
|
||||
next ENTRY if $apu{$posterid} && $apu{$posterid}->{'statusvis'} eq 'S' && ! $viewsome;
|
||||
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid*256 + $anum;
|
||||
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($u, $itemid, $anum),
|
||||
'ljcut_disable' => $remote->{'opt_ljcut_disable_lastn'}, });
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$text);
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
($remote->{'user'} eq $u->{'user'} || LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $apu_lite{$posterid} or die "No apu_lite for posterid=$posterid";
|
||||
$pu = $apu{$posterid};
|
||||
}
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
}
|
||||
#push @elapsed, (tv_interval ($t0));
|
||||
#print STDERR "@elapsed \n";
|
||||
|
||||
|
||||
if (@{$p->{'entries'}}) {
|
||||
$p->{'has_entries'} = 1;
|
||||
$p->{'entries'}->[0]->{'new_day'} = 1;
|
||||
$p->{'entries'}->[-1]->{'end_day'} = 1;
|
||||
}
|
||||
|
||||
# calculate previous day
|
||||
my $pdyear = $year;
|
||||
my $pdmonth = $month;
|
||||
my $pdday = $day-1;
|
||||
if ($pdday < 1)
|
||||
{
|
||||
if (--$pdmonth < 1)
|
||||
{
|
||||
$pdmonth = 12;
|
||||
$pdyear--;
|
||||
}
|
||||
$pdday = LJ::days_in_month($pdmonth, $pdyear);
|
||||
}
|
||||
|
||||
# calculate next day
|
||||
my $nxyear = $year;
|
||||
my $nxmonth = $month;
|
||||
my $nxday = $day+1;
|
||||
if ($nxday > LJ::days_in_month($nxmonth, $nxyear))
|
||||
{
|
||||
$nxday = 1;
|
||||
if (++$nxmonth > 12) { ++$nxyear; $nxmonth=1; }
|
||||
}
|
||||
|
||||
$p->{'prev_url'} = "$u->{'_journalbase'}/" . sprintf("%04d/%02d/%02d/", $pdyear, $pdmonth, $pdday);
|
||||
$p->{'prev_date'} = Date($pdyear, $pdmonth, $pdday);
|
||||
$p->{'next_url'} = "$u->{'_journalbase'}/" . sprintf("%04d/%02d/%02d/", $nxyear, $nxmonth, $nxday);
|
||||
$p->{'next_date'} = Date($nxyear, $nxmonth, $nxday);
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
432
local/cgi-bin/LJ/S2/EntryPage.pm
Executable file
432
local/cgi-bin/LJ/S2/EntryPage.pm
Executable file
@@ -0,0 +1,432 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub EntryPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "EntryPage";
|
||||
$p->{'view'} = "entry";
|
||||
$p->{'comments'} = [];
|
||||
$p->{'comment_pages'} = undef;
|
||||
|
||||
# setup viewall options
|
||||
my ($viewall, $viewsome) = (0, 0);
|
||||
if ($get->{viewall} && LJ::check_priv($remote, 'canview')) {
|
||||
# we don't log here, as we don't know what entry we're viewing yet. the logging
|
||||
# is done when we call EntryPage_entry below.
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
my ($entry, $s2entry) = EntryPage_entry($u, $remote, $opts);
|
||||
return if $opts->{'suspendeduser'};
|
||||
return if $opts->{'handler_return'};
|
||||
|
||||
$p->{'multiform_on'} = $remote &&
|
||||
($remote->{'userid'} == $u->{'userid'} ||
|
||||
$remote->{'userid'} == $entry->{'posterid'} ||
|
||||
LJ::can_manage($remote, $u));
|
||||
|
||||
my $itemid = $entry->{'itemid'};
|
||||
my $ditemid = $entry->{'itemid'} * 256 + $entry->{'anum'};
|
||||
my $permalink = LJ::journal_base($u) . "/$ditemid.html";
|
||||
my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/$ditemid.html" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
if ($LJ::UNICODE) {
|
||||
$p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
|
||||
}
|
||||
|
||||
$p->{'entry'} = $s2entry;
|
||||
|
||||
# add the comments
|
||||
my %userpic;
|
||||
my %user;
|
||||
my $copts = {
|
||||
'thread' => ($get->{'thread'} >> 8),
|
||||
'page' => $get->{'page'},
|
||||
'view' => $get->{'view'},
|
||||
'userpicref' => \%userpic,
|
||||
'userref' => \%user,
|
||||
# user object is cached from call just made in EntryPage_entry
|
||||
'up' => LJ::load_user($s2entry->{'poster'}->{'username'}),
|
||||
'viewall' => $viewall,
|
||||
|
||||
# Okuklivanie tredov - daem upravlenie pol'zovatelyu -
|
||||
'page_size' => $get->{'page_size'},
|
||||
'max_subjects' => $get->{'max_subjects'},
|
||||
'threading_point' => $get->{'threading_point'},
|
||||
'uncollapse' => $get->{'uncollapse'},
|
||||
};
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
my @comments = LJ::Talk::load_comments($u, $remote, "L", $itemid, $copts);
|
||||
|
||||
my $pics = LJ::Talk::get_subjecticons()->{'pic'}; # hashref of imgname => { w, h, img }
|
||||
my $convert_comments = sub {
|
||||
my ($self, $destlist, $srclist, $depth) = @_;
|
||||
|
||||
foreach my $com (@$srclist) {
|
||||
my $dtalkid = $com->{'talkid'} * 256 + $entry->{'anum'};
|
||||
my $text = $com->{'body'};
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
LJ::CleanHTML::clean_comment(\$text, { 'preformatted' => $com->{'props'}->{'opt_preformatted'},
|
||||
'anon_comment' => !$com->{posterid}});
|
||||
|
||||
# local time in mysql format to gmtime
|
||||
my $datetime = DateTime_unix(LJ::mysqldate_to_time($com->{'datepost'}));
|
||||
if ($datetime == 0) {
|
||||
$datetime = "Invalid date";
|
||||
}
|
||||
|
||||
my $subject_icon = undef;
|
||||
if (my $si = $com->{'props'}->{'subjecticon'}) {
|
||||
my $pic = $pics->{$si};
|
||||
$subject_icon = Image("$LJ::IMGPREFIX/talk/$pic->{'img'}",
|
||||
$pic->{'w'}, $pic->{'h'}) if $pic;
|
||||
}
|
||||
|
||||
my $comment_userpic;
|
||||
if (my $pic = $userpic{$com->{'picid'}}) {
|
||||
$comment_userpic = Image("$LJ::USERPIC_ROOT/$com->{'picid'}/$pic->{'userid'}",
|
||||
$pic->{'width'}, $pic->{'height'});
|
||||
}
|
||||
|
||||
my $reply_url = LJ::Talk::talkargs($permalink, "replyto=$dtalkid", $stylemine);
|
||||
|
||||
my $par_url;
|
||||
if ($com->{'parenttalkid'}) {
|
||||
my $dparent = ($com->{'parenttalkid'} << 8) + $entry->{'anum'};
|
||||
$par_url = LJ::Talk::talkargs($permalink, "thread=$dparent", $stylemine) . "#t$dparent";
|
||||
}
|
||||
|
||||
my $poster;
|
||||
if ($com->{'posterid'}) {
|
||||
if ($user{$com->{'posterid'}}) {
|
||||
$poster = UserLite($user{$com->{'posterid'}});
|
||||
} else {
|
||||
$poster = {
|
||||
'_type' => 'UserLite',
|
||||
'username' => $com->{'userpost'},
|
||||
'name' => $com->{'userpost'}, # we don't have this, so fake it
|
||||
'journal_type' => 'P', # fake too, but only people can post, so correct
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
my $s2com = {
|
||||
'_type' => 'Comment',
|
||||
'journal' => $userlite_journal,
|
||||
'metadata' => {
|
||||
'picture_keyword' => $com->{'props'}->{'picture_keyword'},
|
||||
},
|
||||
'permalink_url' => "$permalink?thread=$dtalkid#t$dtalkid",
|
||||
'reply_url' => $reply_url,
|
||||
'poster' => $poster,
|
||||
'replies' => [],
|
||||
'subject' => LJ::ehtml($com->{'subject'}),
|
||||
'subject_icon' => $subject_icon,
|
||||
'talkid' => $dtalkid,
|
||||
'text' => $text,
|
||||
'userpic' => $comment_userpic,
|
||||
'time' => $datetime,
|
||||
'tags' => [],
|
||||
'full' => $com->{'_loaded'} ? 1 : 0,
|
||||
'depth' => $depth,
|
||||
'parent_url' => $par_url,
|
||||
'screened' => $com->{'state'} eq "S" ? 1 : 0,
|
||||
'frozen' => $com->{'state'} eq "F" ? 1 : 0,
|
||||
'link_keyseq' => [ 'delete_comment' ],
|
||||
'anchor' => "t$dtalkid",
|
||||
'dom_id' => "ljcmt$dtalkid",
|
||||
};
|
||||
|
||||
# don't show info from suspended users
|
||||
# FIXME: ideally the load_comments should only return these
|
||||
# items if there are children, otherwise they should be hidden entirely
|
||||
my $pu = $com->{'posterid'} ? $user{$com->{'posterid'}} : undef;
|
||||
if ($pu && $pu->{'statusvis'} eq "S" && !$viewsome) {
|
||||
$s2com->{'text'} = "";
|
||||
$s2com->{'subject'} = "";
|
||||
$s2com->{'full'} = 0;
|
||||
$s2com->{'subject_icon'} = undef;
|
||||
$s2com->{'userpic'} = undef;
|
||||
}
|
||||
|
||||
# Conditionally add more links to the keyseq
|
||||
my $link_keyseq = $s2com->{'link_keyseq'};
|
||||
push @$link_keyseq, $s2com->{'screened'} ? 'unscreen_comment' : 'screen_comment';
|
||||
push @$link_keyseq, $s2com->{'frozen'} ? 'unfreeze_thread' : 'freeze_thread';
|
||||
|
||||
if (@{$com->{'children'}}) {
|
||||
$s2com->{'thread_url'} = LJ::Talk::talkargs($permalink, "thread=$dtalkid", $stylemine) . "#t$dtalkid";
|
||||
}
|
||||
|
||||
# add the poster_ip metadata if remote user has
|
||||
# access to see it.
|
||||
$s2com->{'metadata'}->{'poster_ip'} = $com->{'props'}->{'poster_ip'} if
|
||||
($com->{'props'}->{'poster_ip'} && $remote &&
|
||||
($remote->{'userid'} == $entry->{'posterid'} ||
|
||||
LJ::can_manage($remote, $u) || $viewall));
|
||||
|
||||
push @$destlist, $s2com;
|
||||
|
||||
$self->($self, $s2com->{'replies'}, $com->{'children'}, $depth+1);
|
||||
}
|
||||
};
|
||||
$p->{'comments'} = [];
|
||||
$convert_comments->($convert_comments, $p->{'comments'}, \@comments, 1);
|
||||
|
||||
# prepare the javascript data structure to put in the top of the page
|
||||
# if the remote user is a manager of the comments
|
||||
my $do_commentmanage_js = $p->{'multiform_on'};
|
||||
if ($LJ::DISABLED{'commentmanage'}) {
|
||||
if (ref $LJ::DISABLED{'commentmanage'} eq "CODE") {
|
||||
$do_commentmanage_js = $LJ::DISABLED{'commentmanage'}->($remote);
|
||||
} else {
|
||||
$do_commentmanage_js = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ($do_commentmanage_js) {
|
||||
my $js = "<script>\n// don't crawl this. read http://www.livejournal.com/developer/exporting.bml\n";
|
||||
$js .= "var LJ_cmtinfo = {\n";
|
||||
my $canAdmin = LJ::can_manage($remote, $u) ? 1 : 0;
|
||||
$js .= "\tjournal: '$u->{user}',\n";
|
||||
$js .= "\tcanAdmin: $canAdmin,\n";
|
||||
$js .= "\tremote: '$remote->{user}',\n" if $remote;
|
||||
my $recurse = sub {
|
||||
my ($self, $array) = @_;
|
||||
foreach my $i (@$array) {
|
||||
my $has_threads = scalar @{$i->{'replies'}};
|
||||
my $poster = $i->{'poster'} ? $i->{'poster'}{'username'} : "";
|
||||
my $child_ids = join(',', map { $_->{'talkid'} } @{$i->{'replies'}});
|
||||
$js .= "\t$i->{'talkid'}: { rc: [$child_ids], u: '$poster' },\n";
|
||||
$self->($self, $i->{'replies'}) if $has_threads;
|
||||
}
|
||||
};
|
||||
$recurse->($recurse, $p->{'comments'});
|
||||
chop $js; chop $js; # remove final ",\n". stupid javascript.
|
||||
$js .= "\n};\n" .
|
||||
"var LJVAR;\n".
|
||||
"if (!LJVAR) LJVAR = new Object();\n".
|
||||
"LJVAR.imgprefix = \"$LJ::IMGPREFIX\";\n".
|
||||
"</script>\n";
|
||||
$p->{'head_content'} .= $js;
|
||||
$p->{'head_content'} .= "<script src='$LJ::SITEROOT/js/commentmanage.js'></script>\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
$p->{'viewing_thread'} = $get->{'thread'} ? 1 : 0;
|
||||
|
||||
# default values if there were no comments, because
|
||||
# LJ::Talk::load_comments() doesn't provide them.
|
||||
if ($copts->{'out_error'} eq 'noposts') {
|
||||
$copts->{'out_pages'} = $copts->{'out_page'} = 1;
|
||||
$copts->{'out_items'} = 0;
|
||||
$copts->{'out_itemfirst'} = $copts->{'out_itemlast'} = undef;
|
||||
}
|
||||
|
||||
$p->{'comment_pages'} = ItemRange({
|
||||
'all_subitems_displayed' => ($copts->{'out_pages'} == 1),
|
||||
'current' => $copts->{'out_page'},
|
||||
'from_subitem' => $copts->{'out_itemfirst'},
|
||||
'num_subitems_displayed' => scalar @comments,
|
||||
'to_subitem' => $copts->{'out_itemlast'},
|
||||
'total' => $copts->{'out_pages'},
|
||||
'total_subitems' => $copts->{'out_items'},
|
||||
'_url_of' => sub { return "$permalink?page=" . int($_[0]) .
|
||||
($stylemine ? "&$stylemine" : ''); },
|
||||
});
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
sub EntryPage_fast_check
|
||||
{
|
||||
my ($u, $view, $remote, $opts) = @_;
|
||||
|
||||
return unless ($view eq "entry" || $view eq "reply");
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $r = $opts->{'r'};
|
||||
my $uri = $r->uri;
|
||||
|
||||
my ($ditemid, $itemid, $anum);
|
||||
unless ($uri =~ /(\d+)\.html/) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
$ditemid = $1;
|
||||
$anum = $ditemid % 256;
|
||||
$itemid = $ditemid >> 8;
|
||||
|
||||
my $entry = LJ::Talk::get_journal_item($u, $itemid, "props_only");
|
||||
unless ($entry && $entry->{'anum'} == $anum) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
my $props = $entry->{'props'};
|
||||
|
||||
# do they have the viewall priv?
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "entry: $u->{'user'}, itemid: $itemid, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
# check using normal rules
|
||||
unless (LJ::can_view($remote, $entry) || $viewall) {
|
||||
$opts->{'handler_return'} = 403;
|
||||
return;
|
||||
}
|
||||
|
||||
my $pu = $u;
|
||||
if ($entry->{'posterid'} != $entry->{'ownerid'}) {
|
||||
$pu = LJ::load_userid($entry->{'posterid'});
|
||||
}
|
||||
if (($pu && $pu->{'statusvis'} eq 'S') && !$viewsome) {
|
||||
$opts->{'suspendeduser'} = 1;
|
||||
return;
|
||||
}
|
||||
|
||||
# check If-Modified-Since
|
||||
my $lastmod = $props->{'commentalter'};
|
||||
my $revisiontime = $props->{' revtime'};
|
||||
$lastmod = $revisiontime if $revisiontime && $revisiontime > $lastmod;
|
||||
|
||||
my $ims = $r->header_in('If-Modified-Since');
|
||||
if ($ims) {
|
||||
my $theirtime = LJ::http_to_time($ims);
|
||||
if ($theirtime >= $lastmod && !$remote) {
|
||||
# only for anonymous: logged users will be checked by Etag for exact match
|
||||
# reply special: uniq challange string for regular users
|
||||
if ($view eq "entry" || ($view eq "reply" && $r->header_in('User-Agent') =~ /$LJ::ROBOTS_REGEXP/)) {
|
||||
|
||||
$opts->{'notmodified'} = 1;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
$r->header_out("Last-Modified", LJ::time_to_http($lastmod));
|
||||
}
|
||||
|
||||
sub EntryPage_entry
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
### NB! EntryPage_fast_check was previously called, so all checks passed.
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $r = $opts->{'r'};
|
||||
my $uri = $r->uri;
|
||||
|
||||
my ($ditemid, $itemid, $anum);
|
||||
unless ($uri =~ /(\d+)\.html/) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
$ditemid = $1;
|
||||
$anum = $ditemid % 256;
|
||||
$itemid = $ditemid >> 8;
|
||||
|
||||
my $entry = LJ::Talk::get_journal_item($u, $itemid);
|
||||
unless ($entry && $entry->{'anum'} == $anum) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
### more checks skipped ###
|
||||
|
||||
my $props = $entry->{'props'};
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($entry->{'posterid'} != $entry->{'ownerid'}) {
|
||||
$pu = LJ::load_userid($entry->{'posterid'});
|
||||
$userlite_poster = UserLite($pu);
|
||||
}
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $stylemine = $get->{'style'} eq "mine" ? "style=mine" : "";
|
||||
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $permalink = LJ::journal_base($u) . "/$ditemid.html";
|
||||
my $readurl = LJ::Talk::talkargs($permalink, $nc, $stylemine);
|
||||
my $posturl = LJ::Talk::talkargs($permalink, "mode=reply", $stylemine);
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && !
|
||||
$props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
LJ::can_manage($remote, $u)) ? 1 : 0,
|
||||
});
|
||||
|
||||
# format it
|
||||
if ($opts->{'getargs'}->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$entry->{'subject'} =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$entry->{'event'} =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
my $raw_subj = $entry->{'subject'};
|
||||
LJ::CleanHTML::clean_subject(\$entry->{'subject'});
|
||||
LJ::CleanHTML::clean_event(\$entry->{'event'}, $props->{'opt_preformatted'});
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$entry->{'event'});
|
||||
|
||||
my $s2entry = Entry($u, {
|
||||
'_rawsubject' => $raw_subj,
|
||||
'subject' => $entry->{'subject'},
|
||||
'text' => $entry->{'event'},
|
||||
'dateparts' => $entry->{'alldatepart'},
|
||||
'security' => $entry->{'security'},
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'comments' => $comments,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'new_day' => 0,
|
||||
'end_day' => 0,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
return ($entry, $s2entry);
|
||||
}
|
||||
|
||||
1;
|
||||
444
local/cgi-bin/LJ/S2/FriendsPage.pm
Executable file
444
local/cgi-bin/LJ/S2/FriendsPage.pm
Executable file
@@ -0,0 +1,444 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
eval "use LJR::Distributed;";
|
||||
my $ljr = $@ ? 0 : 1;
|
||||
|
||||
if ($ljr) {
|
||||
use LJR::Distributed;
|
||||
}
|
||||
|
||||
sub FriendsPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "FriendsPage";
|
||||
$p->{'view'} = "friends";
|
||||
$p->{'entries'} = [];
|
||||
$p->{'friends'} = {};
|
||||
$p->{'friends_title'} = LJ::ehtml($u->{'friendspagetitle'});
|
||||
$p->{'filter_active'} = 0;
|
||||
$p->{'filter_name'} = "";
|
||||
|
||||
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::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.
|
||||
my $ims = $opts->{'r'}->header_in('If-Modified-Since');
|
||||
if ($ims) {
|
||||
my $theirtime = LJ::http_to_time($ims);
|
||||
|
||||
# send back a 304 Not Modified if they say they've reloaded this
|
||||
# document in the last $newinterval seconds:
|
||||
unless ($theirtime < $lastmod) {
|
||||
$opts->{'handler_return'} = 304;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
$opts->{'r'}->header_out('Last-Modified', LJ::time_to_http($lastmod));
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $ret;
|
||||
|
||||
if ($get->{'mode'} eq "live") {
|
||||
$ret .= "<html><head><title>${user}'s friends: live!</title></head>\n";
|
||||
$ret .= "<frameset rows=\"100%,0%\" border=0>\n";
|
||||
$ret .= " <frame name=livetop src=\"friends?mode=framed\">\n";
|
||||
$ret .= " <frame name=livebottom src=\"friends?mode=livecond&lastitemid=0\">\n";
|
||||
$ret .= "</frameset></html>\n";
|
||||
return $ret;
|
||||
}
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) . "/friends";
|
||||
return 1;
|
||||
}
|
||||
|
||||
LJ::load_user_props($remote, "opt_nctalklinks", "opt_stylemine", "opt_imagelinks", "opt_ljcut_disable_friends");
|
||||
|
||||
# load options for image links
|
||||
my ($maximgwidth, $maximgheight) = (undef, undef);
|
||||
($maximgwidth, $maximgheight) = ($1, $2)
|
||||
if ($remote && $remote->{'userid'} == $u->{'userid'} &&
|
||||
$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'}, "page_friends_items")+0;
|
||||
if ($itemshow < 1) { $itemshow = 20; }
|
||||
elsif ($itemshow > 50) { $itemshow = 50; }
|
||||
|
||||
my $skip = $get->{'skip'}+0;
|
||||
my $maxskip = ($LJ::MAX_SCROLLBACK_FRIENDS || 1000) - $itemshow;
|
||||
if ($skip > $maxskip) { $skip = $maxskip; }
|
||||
if ($skip < 0) { $skip = 0; }
|
||||
my $itemload = $itemshow+$skip;
|
||||
|
||||
my $dayskip = $get->{'dayskip'}+0;
|
||||
|
||||
my $filter;
|
||||
my $group;
|
||||
my $common_filter = 1;
|
||||
|
||||
if (defined $get->{'filter'} && $remote && $remote->{'user'} eq $user) {
|
||||
$filter = $get->{'filter'};
|
||||
$common_filter = 0;
|
||||
$p->{'filter_active'} = 1;
|
||||
$p->{'filter_name'} = "";
|
||||
} else {
|
||||
if ($opts->{'pathextra'}) {
|
||||
$group = $opts->{'pathextra'};
|
||||
$group =~ s!^/!!;
|
||||
$group =~ s!/$!!;
|
||||
if ($group) { $group = LJ::durl($group); $common_filter = 0; }
|
||||
}
|
||||
if ($group) {
|
||||
$p->{'filter_active'} = 1;
|
||||
$p->{'filter_name'} = LJ::ehtml($group);
|
||||
}
|
||||
my $grp = LJ::get_friend_group($u, { 'name' => $group || "Default View" });
|
||||
my $bit = $grp->{'groupnum'};
|
||||
my $public = $grp->{'is_public'};
|
||||
if ($bit && ($public || ($remote && $remote->{'user'} eq $user))) {
|
||||
$filter = (1 << $bit);
|
||||
} elsif ($group) {
|
||||
$opts->{'badfriendgroup'} = 1;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if ($opts->{'view'} eq "friendsfriends") {
|
||||
$p->{'friends_mode'} = "friendsfriends";
|
||||
}
|
||||
|
||||
if ($get->{'mode'} eq "livecond")
|
||||
{
|
||||
## load the itemids
|
||||
my @items = LJ::get_friend_items({
|
||||
'u' => $u,
|
||||
'remote' => $remote,
|
||||
'itemshow' => 1,
|
||||
'skip' => 0,
|
||||
'filter' => $filter,
|
||||
'common_filter' => $common_filter,
|
||||
});
|
||||
my $first = @items ? $items[0]->{'itemid'} : 0;
|
||||
|
||||
$ret .= "time = " . scalar(time()) . "<br />";
|
||||
$opts->{'headers'}->{'Refresh'} = "30;URL=$LJ::SITEROOT/users/$user/friends?mode=livecond&lastitemid=$first";
|
||||
if ($get->{'lastitemid'} == $first) {
|
||||
$ret .= "nothing new!";
|
||||
} else {
|
||||
if ($get->{'lastitemid'}) {
|
||||
$ret .= "<b>New stuff!</b>\n";
|
||||
$ret .= "<script language=\"JavaScript\">\n";
|
||||
$ret .= "window.parent.livetop.location.reload(true);\n";
|
||||
$ret .= "</script>\n";
|
||||
$opts->{'trusted_html'} = 1;
|
||||
} else {
|
||||
$ret .= "Friends Live! started.";
|
||||
}
|
||||
}
|
||||
return $ret;
|
||||
}
|
||||
|
||||
## load the itemids
|
||||
my %friends;
|
||||
my %friends_row;
|
||||
my @items = LJ::get_friend_items({
|
||||
'u' => $u,
|
||||
'remote' => $remote,
|
||||
'itemshow' => $itemshow,
|
||||
'skip' => $skip,
|
||||
'dayskip' => $dayskip,
|
||||
'filter' => $filter,
|
||||
'common_filter' => $common_filter,
|
||||
'friends_u' => \%friends,
|
||||
'friends' => \%friends_row,
|
||||
'showtypes' => $get->{'show'},
|
||||
'friendsoffriends' => $opts->{'view'} eq "friendsfriends",
|
||||
'dateformat' => 'S2',
|
||||
});
|
||||
|
||||
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 %objs_of_picid;
|
||||
my @userpic_load;
|
||||
|
||||
my %lite; # posterid -> s2_UserLite
|
||||
my $get_lite = sub {
|
||||
my $id = shift;
|
||||
return $lite{$id} if $lite{$id};
|
||||
return $lite{$id} = UserLite($posters{$id} || $friends{$id});
|
||||
};
|
||||
|
||||
my $eventnum = 0;
|
||||
my $hiddenentries = 0;
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($friendid, $posterid, $itemid, $security, $alldatepart) =
|
||||
map { $item->{$_} } qw(ownerid posterid itemid security alldatepart);
|
||||
|
||||
my $fru = $friends{$friendid};
|
||||
my ($friend, $poster);
|
||||
$friend = $poster = $fru->{'user'};
|
||||
$p->{'friends'}->{$fru->{'user'}} ||= Friend($fru);
|
||||
|
||||
my $clusterid = $item->{'clusterid'}+0;
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid * 256 + $item->{'anum'};
|
||||
|
||||
my $stylemine = "";
|
||||
$stylemine .= "style=mine" if $remote && $remote->{'opt_stylemine'} &&
|
||||
$remote->{'userid'} != $friendid;
|
||||
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($fru, $itemid, $item->{'anum'}, $stylemine),
|
||||
'maximgwidth' => $maximgwidth,
|
||||
'maximgheight' => $maximgheight,
|
||||
'ljcut_disable' => $remote->{'opt_ljcut_disable_friends'}, });
|
||||
LJ::expand_embedded($fru, $ditemid, $remote, \$text);
|
||||
|
||||
my $userlite_poster = $get_lite->($posterid);
|
||||
my $userlite_journal = $get_lite->($friendid);
|
||||
|
||||
# get the poster user
|
||||
my $po = $posters{$posterid} || $friends{$posterid};
|
||||
|
||||
# don't allow posts from suspended users
|
||||
if ($po->{'statusvis'} eq 'S') {
|
||||
$hiddenentries++; # Remember how many we've skipped for later
|
||||
next ENTRY;
|
||||
}
|
||||
|
||||
# do the picture
|
||||
my $picid = 0;
|
||||
my $picu = undef;
|
||||
if ($friendid != $posterid && S2::get_property_value($opts->{ctx}, 'use_shared_pic')) {
|
||||
# using the community, the user wants to see shared pictures
|
||||
$picu = $fru;
|
||||
|
||||
# use shared pic for community
|
||||
$picid = $fru->{defaultpicid};
|
||||
} else {
|
||||
# we're using the poster for this picture
|
||||
$picu = $po;
|
||||
|
||||
# check if they specified one
|
||||
$picid = LJ::get_picid_from_keyword($po, $props->{picture_keyword})
|
||||
if $props->{picture_keyword};
|
||||
|
||||
# fall back on the poster's default
|
||||
$picid ||= $po->{defaultpicid};
|
||||
}
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $journalbase = LJ::journal_base($fru);
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = LJ::Talk::talkargs($permalink, $nc, $stylemine);
|
||||
my $posturl = LJ::Talk::talkargs($permalink, "mode=reply", $stylemine);
|
||||
my $synurl = "";
|
||||
|
||||
if ($ljr && $props->{'syn_link'}) {
|
||||
my $rs = LJR::Distributed::match_remote_server($props->{'syn_link'});
|
||||
if ($rs->{"servertype"} eq "lj") {
|
||||
$readurl = $props->{'syn_link'};
|
||||
$posturl = $props->{'syn_link'} . "?mode=reply";
|
||||
$replycount = 'Read';
|
||||
}
|
||||
else {
|
||||
$posturl = $props->{'syn_link'};
|
||||
$replycount = undef;
|
||||
}
|
||||
$synurl = $props->{'syn_link'};
|
||||
}
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'syn_url' => $synurl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($fru->{'opt_showtalklinks'} eq "Y" &&
|
||||
! $props->{'opt_nocomments'} ||
|
||||
$props->{'syn_link'}
|
||||
) ? 1 : 0,
|
||||
'screened' => ($remote && LJ::can_manage($remote, $fru) && $props->{'hasscreened'}) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $moodthemeid = $u->{'opt_forcemoodtheme'} eq 'Y' ?
|
||||
$u->{'moodthemeid'} : $fru->{'moodthemeid'};
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'new_day' => 0, # setup below
|
||||
'end_day' => 0, # setup below
|
||||
'userpic' => undef,
|
||||
'permalink_url' => $permalink,
|
||||
'base_url' => $journalbase,
|
||||
'moodthemeid' => $moodthemeid,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
$entry->{'_ymd'} = join('-', map { $entry->{'time'}->{$_} } qw(year month day));
|
||||
|
||||
if ($picid && $picu) {
|
||||
push @userpic_load, [ $picu, $picid ];
|
||||
push @{$objs_of_picid{$picid}}, \$entry->{'userpic'};
|
||||
}
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
$eventnum++;
|
||||
|
||||
} # 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;
|
||||
}
|
||||
}
|
||||
|
||||
# load the pictures that were referenced, then retroactively populate
|
||||
# the userpic fields of the Entries above
|
||||
my %userpics;
|
||||
LJ::load_userpics(\%userpics, \@userpic_load);
|
||||
|
||||
foreach my $picid (keys %userpics) {
|
||||
my $up = Image("$LJ::USERPIC_ROOT/$picid/$userpics{$picid}->{'userid'}",
|
||||
$userpics{$picid}->{'width'},
|
||||
$userpics{$picid}->{'height'});
|
||||
foreach (@{$objs_of_picid{$picid}}) { $$_ = $up; }
|
||||
}
|
||||
|
||||
# make the skip links
|
||||
my $nav = {
|
||||
'_type' => 'RecentNav',
|
||||
'version' => 1,
|
||||
'skip' => $skip,
|
||||
'count' => $eventnum,
|
||||
};
|
||||
|
||||
my $base = "$u->{'_journalbase'}/$opts->{'view'}";
|
||||
if ($group) {
|
||||
$base .= "/" . LJ::eurl($group);
|
||||
}
|
||||
|
||||
# $linkfilter is distinct from $filter: if user has a default view,
|
||||
# $filter is now set according to it but we don't want it to show in the links.
|
||||
# $incfilter may be true even if $filter is 0: user may use filter=0 to turn
|
||||
# off the default group
|
||||
my $linkfilter = $get->{'filter'} + 0;
|
||||
my $incfilter = defined $get->{'filter'};
|
||||
|
||||
# if we've skipped down, then we can skip back up
|
||||
if ($skip) {
|
||||
my %linkvars;
|
||||
$linkvars{'filter'} = $linkfilter if $incfilter;
|
||||
$linkvars{'show'} = $get->{'show'} if $get->{'show'} =~ /^\w+$/;
|
||||
my $newskip = $skip - $itemshow;
|
||||
if ($newskip > 0) { $linkvars{'skip'} = $newskip; }
|
||||
else { $newskip = 0; }
|
||||
$linkvars{'dayskip'} = $dayskip if $dayskip;
|
||||
$nav->{'forward_url'} = LJ::make_link($base, \%linkvars);
|
||||
$nav->{'forward_skip'} = $newskip;
|
||||
$nav->{'forward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
## 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)
|
||||
# Must remember to count $hiddenentries or we'll have no skiplinks when > 1
|
||||
unless (($eventnum + $hiddenentries) != $itemshow || $skip == $maxskip) {
|
||||
my %linkvars;
|
||||
$linkvars{'filter'} = $linkfilter if $incfilter;
|
||||
$linkvars{'show'} = $get->{'show'} if $get->{'show'} =~ /^\w+$/;
|
||||
my $newskip = $skip + $itemshow;
|
||||
$linkvars{'skip'} = $newskip;
|
||||
$linkvars{'dayskip'} = $dayskip if $dayskip;
|
||||
$nav->{'backward_url'} = LJ::make_link($base, \%linkvars);
|
||||
$nav->{'backward_skip'} = $newskip;
|
||||
$nav->{'backward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
$p->{'nav'} = $nav;
|
||||
|
||||
if ($get->{'mode'} eq "framed") {
|
||||
$p->{'head_content'} .= "<base target='_top' />";
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
224
local/cgi-bin/LJ/S2/MonthPage.pm
Executable file
224
local/cgi-bin/LJ/S2/MonthPage.pm
Executable file
@@ -0,0 +1,224 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub MonthPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "MonthPage";
|
||||
$p->{'view'} = "month";
|
||||
$p->{'days'} = [];
|
||||
|
||||
my $ctx = $opts->{'ctx'};
|
||||
|
||||
my $dbcr = LJ::get_cluster_reader($u);
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
my ($year, $month);
|
||||
if ($opts->{'pathextra'} =~ m!^/(\d\d\d\d)/(\d\d)\b!) {
|
||||
($year, $month) = ($1, $2);
|
||||
}
|
||||
|
||||
$opts->{'errors'} = [];
|
||||
if ($month < 1 || $month > 12) { push @{$opts->{'errors'}}, "Invalid month: $month"; }
|
||||
if ($year < 1970 || $year > 2038) { push @{$opts->{'errors'}}, "Invalid year: $year"; }
|
||||
unless ($dbcr) { push @{$opts->{'errors'}}, "Database temporarily unavailable"; }
|
||||
return if @{$opts->{'errors'}};
|
||||
|
||||
$p->{'date'} = Date($year, $month, 0);
|
||||
|
||||
# load the log items
|
||||
my $dateformat = "%Y %m %d %H %i %s %w"; # yyyy mm dd hh mm ss day_of_week
|
||||
my $sth;
|
||||
|
||||
my $secwhere = "AND l.security='public'";
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($remote) {
|
||||
|
||||
# do they have the viewall priv?
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "month: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
if ($remote->{'userid'} == $u->{'userid'} || $viewall) {
|
||||
$secwhere = ""; # see everything
|
||||
} elsif ($remote->{'journaltype'} eq 'P' || $remote->{'journaltype'} eq 'I') {
|
||||
my $gmask = LJ::get_groupmask($u, $remote);
|
||||
$secwhere = "AND (l.security='public' OR (l.security='usemask' AND l.allowmask & $gmask))"
|
||||
if $gmask;
|
||||
}
|
||||
}
|
||||
|
||||
$sth = $dbcr->prepare("SELECT l.jitemid AS 'itemid', l.posterid, l.anum, l.day, ".
|
||||
" DATE_FORMAT(l.eventtime, '$dateformat') AS 'alldatepart', ".
|
||||
" l.replycount, l.security ".
|
||||
"FROM log2 l ".
|
||||
"WHERE l.journalid=? AND l.year=? AND l.month=? ".
|
||||
"$secwhere LIMIT 2000");
|
||||
$sth->execute($u->{'userid'}, $year, $month);
|
||||
|
||||
my @items;
|
||||
push @items, $_ while $_ = $sth->fetchrow_hashref;
|
||||
@items = sort { $a->{'alldatepart'} cmp $b->{'alldatepart'} } @items;
|
||||
|
||||
LJ::fill_items_with_text_props(\@items, $u, {'only_subject' => 1});
|
||||
|
||||
my (%pu, %pu_lite); # poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
$pu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
LJ::load_userids_multiple([map { $_, \$pu{$_} } keys %pu], [$u]);
|
||||
$pu_lite{$_} = UserLite($pu{$_}) foreach keys %pu;
|
||||
|
||||
my %day_entries; # <day> -> [ Entry+ ]
|
||||
|
||||
my $opt_text_subjects = S2::get_property_value($ctx, "page_month_textsubjects");
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart, $replycount, $anum) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart replycount anum);
|
||||
my $day = $item->{'day'};
|
||||
|
||||
# don't show posts from suspended users
|
||||
next unless $pu{$posterid};
|
||||
next ENTRY if $pu{$posterid}->{'statusvis'} eq 'S' && !$viewsome;
|
||||
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $props = $item->{'props'};
|
||||
|
||||
if ($opt_text_subjects) {
|
||||
LJ::CleanHTML::clean_subject_all(\$subject);
|
||||
} else {
|
||||
LJ::CleanHTML::clean_subject(\$subject);
|
||||
}
|
||||
|
||||
my $ditemid = $itemid*256 + $anum;
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && $remote &&
|
||||
($remote->{'user'} eq $u->{'user'} || LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $userpic = $p->{'journal'}->{'default_pic'};
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $pu_lite{$posterid};
|
||||
$userpic = Image_userpic($pu{$posterid}, 0, $props->{'picture_keyword'});
|
||||
}
|
||||
|
||||
my $entry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => "",
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
});
|
||||
|
||||
push @{$day_entries{$day}}, $entry;
|
||||
}
|
||||
|
||||
my $days_month = LJ::days_in_month($month, $year);
|
||||
for my $day (1..$days_month) {
|
||||
my $entries = $day_entries{$day} || [];
|
||||
my $month_day = {
|
||||
'_type' => 'MonthDay',
|
||||
'date' => Date($year, $month, $day),
|
||||
'day' => $day,
|
||||
'has_entries' => scalar @$entries > 0,
|
||||
'num_entries' => scalar @$entries,
|
||||
'url' => $journalbase . sprintf("/%04d/%02d/%02d/", $year, $month, $day),
|
||||
'entries' => $entries,
|
||||
};
|
||||
push @{$p->{'days'}}, $month_day;
|
||||
}
|
||||
|
||||
# populate redirector
|
||||
my $vhost = $opts->{'vhost'};
|
||||
$vhost =~ s/:.*//;
|
||||
$p->{'redir'} = {
|
||||
'_type' => "Redirector",
|
||||
'user' => $u->{'user'},
|
||||
'vhost' => $vhost,
|
||||
'type' => 'monthview',
|
||||
'url' => "$LJ::SITEROOT/go.bml",
|
||||
};
|
||||
|
||||
# figure out what months have been posted into
|
||||
my $nowval = $year*12 + $month;
|
||||
|
||||
$p->{'months'} = [];
|
||||
|
||||
my $days = LJ::get_daycounts($u, $remote) || [];
|
||||
my $lastmo;
|
||||
foreach my $day (@$days) {
|
||||
my ($oy, $om) = ($day->[0], $day->[1]);
|
||||
my $mo = "$oy-$om";
|
||||
next if $mo eq $lastmo;
|
||||
$lastmo = $mo;
|
||||
|
||||
my $date = Date($oy, $om, 0);
|
||||
my $url = $journalbase . sprintf("/%04d/%02d/", $oy, $om);
|
||||
push @{$p->{'months'}}, {
|
||||
'_type' => "MonthEntryInfo",
|
||||
'date' => $date,
|
||||
'url' => $url,
|
||||
'redir_key' => sprintf("%04d%02d", $oy, $om),
|
||||
};
|
||||
|
||||
my $val = $oy*12+$om;
|
||||
if ($val < $nowval) {
|
||||
$p->{'prev_url'} = $url;
|
||||
$p->{'prev_date'} = $date;
|
||||
}
|
||||
if ($val > $nowval && ! $p->{'next_date'}) {
|
||||
$p->{'next_url'} = $url;
|
||||
$p->{'next_date'} = $date;
|
||||
}
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
216
local/cgi-bin/LJ/S2/RecentPage.pm
Executable file
216
local/cgi-bin/LJ/S2/RecentPage.pm
Executable file
@@ -0,0 +1,216 @@
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub RecentPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "RecentPage";
|
||||
$p->{'view'} = "recent";
|
||||
$p->{'entries'} = [];
|
||||
|
||||
my $user = $u->{'user'};
|
||||
my $journalbase = LJ::journal_base($user, $opts->{'vhost'});
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'});
|
||||
return;
|
||||
}
|
||||
|
||||
LJ::load_user_props($remote, "opt_nctalklinks", "opt_ljcut_disable_lastn");
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
if ($opts->{'pathextra'}) {
|
||||
$opts->{'badargs'} = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'} || $get->{'skip'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
$p->{'head_content'} .= qq{<link rel="openid.server" href="$LJ::OPENID_SERVER" />\n}
|
||||
if LJ::OpenID::server_enabled();
|
||||
|
||||
my $itemshow = S2::get_property_value($opts->{'ctx'}, "page_recent_items")+0;
|
||||
if ($itemshow < 1) { $itemshow = 20; }
|
||||
elsif ($itemshow > 50) { $itemshow = 50; }
|
||||
|
||||
my $skip = $get->{'skip'}+0;
|
||||
my $maxskip = $LJ::MAX_HINTS_LASTN-$itemshow;
|
||||
if ($skip < 0) { $skip = 0; }
|
||||
if ($skip > $maxskip) { $skip = $maxskip; }
|
||||
|
||||
my $dayskip = $get->{'dayskip'}+0;
|
||||
|
||||
# do they want to view all entries, regardless of security?
|
||||
my $viewall = 0;
|
||||
my $viewsome = 0;
|
||||
if ($get->{'viewall'} && LJ::check_priv($remote, "canview")) {
|
||||
LJ::statushistory_add($u->{'userid'}, $remote->{'userid'},
|
||||
"viewall", "lastn: $user, statusvis: $u->{'statusvis'}");
|
||||
$viewall = LJ::check_priv($remote, 'canview', '*');
|
||||
$viewsome = $viewall || LJ::check_priv($remote, 'canview', 'suspended');
|
||||
}
|
||||
|
||||
## load the items
|
||||
my $err;
|
||||
my @items = LJ::get_recent_items({
|
||||
'u' => $u,
|
||||
'clustersource' => 'slave',
|
||||
'viewall' => $viewall,
|
||||
'remote' => $remote,
|
||||
'itemshow' => $itemshow,
|
||||
'skip' => $skip,
|
||||
'dayskip' => $dayskip,
|
||||
'tags' => $opts->{tags},
|
||||
'dateformat' => 'S2',
|
||||
'order' => ($u->{'journaltype'} eq "C" || $u->{'journaltype'} eq "Y") # community or syndicated
|
||||
? "logtime" : "",
|
||||
'err' => \$err,
|
||||
});
|
||||
|
||||
die $err if $err;
|
||||
|
||||
my $lastdate = "";
|
||||
my $itemnum = 0;
|
||||
my $lastentry = undef;
|
||||
|
||||
my (%apu, %apu_lite); # alt poster users; UserLite objects
|
||||
foreach (@items) {
|
||||
next unless $_->{'posterid'} != $u->{'userid'};
|
||||
$apu{$_->{'posterid'}} = undef;
|
||||
}
|
||||
if (%apu) {
|
||||
LJ::load_userids_multiple([map { $_, \$apu{$_} } keys %apu], [$u]);
|
||||
$apu_lite{$_} = UserLite($apu{$_}) foreach keys %apu;
|
||||
}
|
||||
|
||||
my $userlite_journal = UserLite($u);
|
||||
|
||||
ENTRY:
|
||||
foreach my $item (@items)
|
||||
{
|
||||
my ($posterid, $itemid, $security, $alldatepart) =
|
||||
map { $item->{$_} } qw(posterid itemid security alldatepart);
|
||||
|
||||
my $props = $item->{'props'};
|
||||
|
||||
my $replycount = $props->{'replycount'};
|
||||
my $subject = $item->{'text'}->[0];
|
||||
my $text = $item->{'text'}->[1];
|
||||
if ($get->{'nohtml'}) {
|
||||
# quote all non-LJ tags
|
||||
$subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
$text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
|
||||
}
|
||||
|
||||
# don't show posts from suspended users unless the user doing the viewing says to (and is allowed)
|
||||
next ENTRY if $apu{$posterid} && $apu{$posterid}->{'statusvis'} eq 'S' && !$viewsome;
|
||||
|
||||
my $date = substr($alldatepart, 0, 10);
|
||||
my $new_day = 0;
|
||||
if ($date ne $lastdate) {
|
||||
$new_day = 1;
|
||||
$lastdate = $date;
|
||||
$lastentry->{'end_day'} = 1 if $lastentry;
|
||||
}
|
||||
|
||||
$itemnum++;
|
||||
LJ::CleanHTML::clean_subject(\$subject) if $subject;
|
||||
|
||||
my $ditemid = $itemid * 256 + $item->{'anum'};
|
||||
LJ::CleanHTML::clean_event(\$text, { 'preformatted' => $props->{'opt_preformatted'},
|
||||
'cuturl' => LJ::item_link($u, $itemid, $item->{'anum'}),
|
||||
'ljcut_disable' => $remote->{"opt_ljcut_disable_lastn"}, });
|
||||
LJ::expand_embedded($u, $ditemid, $remote, \$text);
|
||||
|
||||
my $nc = "";
|
||||
$nc .= "nc=$replycount" if $replycount; # && $remote && $remote->{'opt_nctalklinks'};
|
||||
|
||||
my $permalink = "$journalbase/$ditemid.html";
|
||||
my $readurl = $permalink;
|
||||
$readurl .= "?$nc" if $nc;
|
||||
my $posturl = $permalink . "?mode=reply";
|
||||
|
||||
my $comments = CommentInfo({
|
||||
'read_url' => $readurl,
|
||||
'post_url' => $posturl,
|
||||
'count' => $replycount,
|
||||
'maxcomments' => ($replycount >= LJ::get_cap($u, 'maxcomments')) ? 1 : 0,
|
||||
'enabled' => ($u->{'opt_showtalklinks'} eq "Y" && ! $props->{'opt_nocomments'}) ? 1 : 0,
|
||||
'screened' => ($props->{'hasscreened'} && ($remote->{'user'} eq $u->{'user'}|| LJ::can_manage($remote, $u))) ? 1 : 0,
|
||||
});
|
||||
|
||||
my $userlite_poster = $userlite_journal;
|
||||
my $pu = $u;
|
||||
if ($u->{'userid'} != $posterid) {
|
||||
$userlite_poster = $apu_lite{$posterid} or die "No apu_lite for posterid=$posterid";
|
||||
$pu = $apu{$posterid};
|
||||
}
|
||||
my $userpic = Image_userpic($pu, 0, $props->{'picture_keyword'});
|
||||
|
||||
my $entry = $lastentry = Entry($u, {
|
||||
'subject' => $subject,
|
||||
'text' => $text,
|
||||
'dateparts' => $alldatepart,
|
||||
'security' => $security,
|
||||
'props' => $props,
|
||||
'itemid' => $ditemid,
|
||||
'journal' => $userlite_journal,
|
||||
'poster' => $userlite_poster,
|
||||
'comments' => $comments,
|
||||
'new_day' => $new_day,
|
||||
'end_day' => 0, # if true, set later
|
||||
'userpic' => $userpic,
|
||||
'permalink_url' => $permalink,
|
||||
'enable_tags_compatibility' => [$opts->{enable_tags_compatibility}, $opts->{ctx}],
|
||||
});
|
||||
|
||||
push @{$p->{'entries'}}, $entry;
|
||||
|
||||
} # end huge while loop
|
||||
|
||||
# mark last entry as closing.
|
||||
$p->{'entries'}->[-1]->{'end_day'} = 1 if $itemnum;
|
||||
|
||||
#### make the skip links
|
||||
my $nav = {
|
||||
'_type' => 'RecentNav',
|
||||
'version' => 1,
|
||||
'skip' => $skip,
|
||||
'count' => $itemnum,
|
||||
};
|
||||
|
||||
# if we've skipped down, then we can skip back up
|
||||
if ($skip) {
|
||||
my $newskip = $skip - $itemshow;
|
||||
$newskip = 0 if $newskip <= 0;
|
||||
$nav->{'forward_skip'} = $newskip;
|
||||
$nav->{'forward_url'} = LJ::make_link("$p->{base_url}/", { skip => ($newskip || ""), tag => (LJ::eurl($get->{tag}) || ""), dayskip => ($dayskip || "") });
|
||||
$nav->{'forward_count'} = $itemshow;
|
||||
}
|
||||
|
||||
# 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)
|
||||
unless ($itemnum != $itemshow) {
|
||||
$nav->{'backward_count'} = $itemshow;
|
||||
if ($skip == $maxskip) {
|
||||
my $date_slashes = $lastdate; # "yyyy mm dd";
|
||||
$date_slashes =~ s! !/!g;
|
||||
$nav->{'backward_url'} = "$p->{'base_url'}/day/$date_slashes";
|
||||
} else {
|
||||
my $newskip = $skip + $itemshow;
|
||||
$nav->{'backward_url'} = LJ::make_link("$p->{'base_url'}/", { skip => ($newskip || ""), tag => (LJ::eurl($get->{tag}) || ""), dayskip => ($dayskip || "") });
|
||||
$nav->{'backward_skip'} = $newskip;
|
||||
}
|
||||
}
|
||||
|
||||
$p->{'nav'} = $nav;
|
||||
return $p;
|
||||
}
|
||||
|
||||
1;
|
||||
139
local/cgi-bin/LJ/S2/ReplyPage.pm
Executable file
139
local/cgi-bin/LJ/S2/ReplyPage.pm
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub ReplyPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "ReplyPage";
|
||||
$p->{'view'} = "reply";
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my ($entry, $s2entry) = EntryPage_entry($u, $remote, $opts);
|
||||
return if $opts->{'suspendeduser'};
|
||||
return if $opts->{'handler_return'};
|
||||
my $ditemid = $entry->{'itemid'}*256 + $entry->{'anum'};
|
||||
$p->{'head_content'} .= $LJ::COMMON_CODE{'chalresp_js'};
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
|
||||
$p->{'entry'} = $s2entry;
|
||||
|
||||
# setup the replying item
|
||||
my $replyto = $s2entry;
|
||||
my $parpost;
|
||||
if ($get->{'replyto'}) {
|
||||
my $re_talkid = int($get->{'replyto'} >> 8);
|
||||
my $re_anum = $get->{'replyto'} % 256;
|
||||
unless ($re_anum == $entry->{'anum'}) {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
|
||||
my $sql = "SELECT jtalkid, posterid, state, datepost FROM talk2 ".
|
||||
"WHERE journalid=$u->{'userid'} AND jtalkid=$re_talkid ".
|
||||
"AND nodetype='L' AND nodeid=$entry->{'jitemid'}";
|
||||
foreach my $pass (1, 2) {
|
||||
my $db = $pass == 1 ? LJ::get_cluster_reader($u) : LJ::get_cluster_def_reader($u);
|
||||
$parpost = $db->selectrow_hashref($sql);
|
||||
last if $parpost;
|
||||
}
|
||||
unless ($parpost and $parpost->{'state'} ne 'D') {
|
||||
$opts->{'handler_return'} = 404;
|
||||
return;
|
||||
}
|
||||
if ($parpost->{'state'} eq 'S' && !LJ::Talk::can_unscreen($remote, $u, $s2entry->{'poster'}->{'username'}, undef)) {
|
||||
$opts->{'handler_return'} = 403;
|
||||
return;
|
||||
}
|
||||
if ($parpost->{'state'} eq 'F') {
|
||||
# frozen comment, no replies allowed
|
||||
|
||||
# FIXME: eventually have S2 ErrorPage to handle this and similar
|
||||
# For now, this hack will work; this error is pretty uncommon anyway.
|
||||
$opts->{status} = "403 Forbidden";
|
||||
return "<p>This thread has been frozen; no more replies are allowed.</p>";
|
||||
}
|
||||
|
||||
my $tt = LJ::get_talktext2($u, $re_talkid);
|
||||
$parpost->{'subject'} = $tt->{$re_talkid}->[0];
|
||||
$parpost->{'body'} = $tt->{$re_talkid}->[1];
|
||||
$parpost->{'props'} =
|
||||
LJ::load_talk_props2($u, [ $re_talkid ])->{$re_talkid} || {};
|
||||
|
||||
if($LJ::UNICODE && $parpost->{'props'}->{'unknown8bit'}) {
|
||||
LJ::item_toutf8($u, \$parpost->{'subject'}, \$parpost->{'body'}, {});
|
||||
}
|
||||
|
||||
LJ::CleanHTML::clean_comment(\$parpost->{'body'},
|
||||
{ 'preformatted' => $parpost->{'props'}->{'opt_preformatted'},
|
||||
'anon_comment' => !$parpost->{posterid} });
|
||||
|
||||
my $datetime = DateTime_unix(LJ::mysqldate_to_time($parpost->{'datepost'}));
|
||||
|
||||
my ($s2poster, $pu);
|
||||
my $comment_userpic;
|
||||
if ($parpost->{'posterid'}) {
|
||||
$pu = LJ::load_userid($parpost->{'posterid'});
|
||||
return $opts->{handler_return} = 403 if $pu->{statusvis} eq 'S'; # do not show comments by suspended users
|
||||
$s2poster = UserLite($pu);
|
||||
|
||||
# FIXME: this is a little heavy:
|
||||
$comment_userpic = Image_userpic($pu, 0, $parpost->{'props'}->{'picture_keyword'});
|
||||
}
|
||||
|
||||
my $dtalkid = $re_talkid * 256 + $entry->{'anum'};
|
||||
$replyto = {
|
||||
'_type' => 'EntryLite',
|
||||
'subject' => LJ::ehtml($parpost->{'subject'}),
|
||||
'text' => $parpost->{'body'},
|
||||
'userpic' => $comment_userpic,
|
||||
'poster' => $s2poster,
|
||||
'journal' => $s2entry->{'journal'},
|
||||
'metadata' => {},
|
||||
'permalink_url' => $u->{'_journalbase'} . "/$ditemid.html?view=$dtalkid#t$dtalkid",
|
||||
'depth' => 1,
|
||||
'time' => $datetime,
|
||||
};
|
||||
}
|
||||
|
||||
$p->{'replyto'} = $replyto;
|
||||
|
||||
$p->{'form'} = {
|
||||
'_type' => "ReplyForm",
|
||||
'_remote' => $remote,
|
||||
'_u' => $u,
|
||||
'_ditemid' => $ditemid,
|
||||
'_parpost' => $parpost,
|
||||
};
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
package S2::Builtin::LJ;
|
||||
|
||||
sub ReplyForm__print
|
||||
{
|
||||
my ($ctx, $form) = @_;
|
||||
my $remote = $form->{'_remote'};
|
||||
my $u = $form->{'_u'};
|
||||
my $parpost = $form->{'_parpost'};
|
||||
my $parent = $parpost ? $parpost->{'jtalkid'} : 0;
|
||||
|
||||
$S2::pout->(LJ::Talk::talkform({ 'remote' => $remote,
|
||||
'journalu' => $u,
|
||||
'parpost' => $parpost,
|
||||
'replyto' => $parent,
|
||||
'ditemid' => $form->{'_ditemid'},
|
||||
'form' => $form }));
|
||||
|
||||
}
|
||||
|
||||
1;
|
||||
181
local/cgi-bin/LJ/S2/YearPage.pm
Executable file
181
local/cgi-bin/LJ/S2/YearPage.pm
Executable file
@@ -0,0 +1,181 @@
|
||||
#!/usr/bin/perl
|
||||
#
|
||||
|
||||
use strict;
|
||||
package LJ::S2;
|
||||
|
||||
sub YearPage
|
||||
{
|
||||
my ($u, $remote, $opts) = @_;
|
||||
|
||||
my $p = Page($u, $opts);
|
||||
$p->{'_type'} = "YearPage";
|
||||
$p->{'view'} = "archive";
|
||||
|
||||
my $user = $u->{'user'};
|
||||
|
||||
if ($u->{'journaltype'} eq "R" && $u->{'renamedto'} ne "") {
|
||||
$opts->{'redir'} = LJ::journal_base($u->{'renamedto'}, $opts->{'vhost'}) .
|
||||
"/calendar" . $opts->{'pathextra'};
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($u->{'opt_blockrobots'}) {
|
||||
$p->{'head_content'} .= LJ::robot_meta_tags();
|
||||
}
|
||||
if ($LJ::UNICODE) {
|
||||
$p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
|
||||
}
|
||||
|
||||
my $get = $opts->{'getargs'};
|
||||
|
||||
my $count = LJ::S2::get_journal_day_counts($p);
|
||||
my @years = sort { $a <=> $b } keys %$count;
|
||||
my $maxyear = @years ? $years[-1] : undef;
|
||||
my $year = $get->{'year'}; # old form was /users/<user>/calendar?year=1999
|
||||
|
||||
# but the new form is purtier: */calendar/2001
|
||||
if (! $year && $opts->{'pathextra'} =~ m!^/(\d\d\d\d)/?\b!) {
|
||||
$year = $1;
|
||||
}
|
||||
|
||||
# else... default to the year they last posted.
|
||||
$year ||= $maxyear;
|
||||
|
||||
$p->{'year'} = $year;
|
||||
$p->{'years'} = [];
|
||||
foreach (@years) {
|
||||
push @{$p->{'years'}}, YearYear($_, "$p->{'base_url'}/$_/", $_ == $p->{'year'});
|
||||
}
|
||||
|
||||
$p->{'months'} = [];
|
||||
|
||||
for my $month (1..12) {
|
||||
push @{$p->{'months'}}, YearMonth($p, {
|
||||
'month' => $month,
|
||||
'year' => $year,
|
||||
});
|
||||
}
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
sub YearMonth {
|
||||
my ($p, $calmon) = @_;
|
||||
|
||||
my ($month, $year) = ($calmon->{'month'}, $calmon->{'year'});
|
||||
$calmon->{'_type'} = 'YearMonth';
|
||||
$calmon->{'weeks'} = [];
|
||||
$calmon->{'url'} = sprintf("$p->{'_u'}->{'_journalbase'}/$year/%02d/", $month);
|
||||
|
||||
my $count = LJ::S2::get_journal_day_counts($p);
|
||||
my $has_entries = $count->{$year} && $count->{$year}->{$month} ? 1 : 0;
|
||||
$calmon->{'has_entries'} = $has_entries;
|
||||
|
||||
my $start_monday = 0; # FIXME: check some property to see if weeks start on monday
|
||||
my $week = undef;
|
||||
|
||||
my $flush_week = sub {
|
||||
my $end_month = shift;
|
||||
return unless $week;
|
||||
push @{$calmon->{'weeks'}}, $week;
|
||||
if ($end_month) {
|
||||
$week->{'post_empty'} =
|
||||
7 - $week->{'pre_empty'} - @{$week->{'days'}};
|
||||
}
|
||||
$week = undef;
|
||||
};
|
||||
|
||||
my $push_day = sub {
|
||||
my $d = shift;
|
||||
unless ($week) {
|
||||
my $leading = $d->{'date'}->{'_dayofweek'}-1;
|
||||
if ($start_monday) {
|
||||
$leading = 6 if --$leading < 0;
|
||||
}
|
||||
$week = {
|
||||
'_type' => 'YearWeek',
|
||||
'days' => [],
|
||||
'pre_empty' => $leading,
|
||||
'post_empty' => 0,
|
||||
};
|
||||
}
|
||||
push @{$week->{'days'}}, $d;
|
||||
if ($week->{'pre_empty'} + @{$week->{'days'}} == 7) {
|
||||
$flush_week->();
|
||||
my $size = scalar @{$calmon->{'weeks'}};
|
||||
}
|
||||
};
|
||||
|
||||
my $day_of_week = LJ::day_of_week($year, $month, 1);
|
||||
|
||||
my $daysinmonth = LJ::days_in_month($month, $year);
|
||||
|
||||
for my $day (1..$daysinmonth) {
|
||||
# so we don't auto-vivify years/months
|
||||
my $daycount = $has_entries ? $count->{$year}->{$month}->{$day} : 0;
|
||||
my $d = YearDay($p->{'_u'}, $year, $month, $day,
|
||||
$daycount, $day_of_week+1);
|
||||
$push_day->($d);
|
||||
$day_of_week = ($day_of_week + 1) % 7;
|
||||
}
|
||||
$flush_week->(1); # end of month flag
|
||||
|
||||
my $nowval = $year * 12 + $month;
|
||||
|
||||
# determine the most recent month with posts that is older than
|
||||
# the current time $month/$year. gives calendars the ability to
|
||||
# provide smart next/previous links.
|
||||
my $maxbefore;
|
||||
while (my ($iy, $h) = each %$count) {
|
||||
next if $iy > $year;
|
||||
while (my $im = each %$h) {
|
||||
next if $im >= $month;
|
||||
my $val = $iy * 12 + $im;
|
||||
if ($val < $nowval && $val > $maxbefore) {
|
||||
$maxbefore = $val;
|
||||
$calmon->{'prev_url'} = $p->{'_u'}->{'_journalbase'} . sprintf("/%04d/%02d/", $iy, $im);
|
||||
$calmon->{'prev_date'} = Date($iy, $im, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# same, except inverse: next month after current time with posts
|
||||
my $minafter;
|
||||
while (my ($iy, $h) = each %$count) {
|
||||
next if $iy < $year;
|
||||
while (my $im = each %$h) {
|
||||
next if $im <= $month;
|
||||
my $val = $iy * 12 + $im;
|
||||
if ($val > $nowval && (!$minafter || $val < $minafter)) {
|
||||
$minafter = $val;
|
||||
$calmon->{'next_url'} = $p->{'_u'}->{'_journalbase'} . sprintf("/%04d/%02d/", $iy, $im);
|
||||
$calmon->{'next_date'} = Date($iy, $im, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
return $calmon;
|
||||
}
|
||||
|
||||
sub YearYear {
|
||||
my ($year, $url, $displayed) = @_;
|
||||
return { '_type' => "YearYear",
|
||||
'year' => $year, 'url' => $url, 'displayed' => $displayed };
|
||||
}
|
||||
|
||||
sub YearDay {
|
||||
my ($u, $year, $month, $day, $count, $dow) = @_;
|
||||
my $d = {
|
||||
'_type' => 'YearDay',
|
||||
'day' => $day,
|
||||
'date' => Date($year, $month, $day, $dow),
|
||||
'num_entries' => $count
|
||||
};
|
||||
if ($count) {
|
||||
$d->{'url'} = sprintf("$u->{'_journalbase'}/$year/%02d/%02d/",
|
||||
$month, $day);
|
||||
}
|
||||
return $d;
|
||||
}
|
||||
|
||||
1;
|
||||
2164
local/cgi-bin/LJ/TextMessage.pm
Executable file
2164
local/cgi-bin/LJ/TextMessage.pm
Executable file
File diff suppressed because it is too large
Load Diff
3712
local/cgi-bin/LJ/User.pm
Executable file
3712
local/cgi-bin/LJ/User.pm
Executable file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user