12 my ($u, $remote, $opts) = @_;
13 my $get = $opts->{'getargs'};
15 my $p = Page
($u, $opts);
16 $p->{'_type'} = "EntryPage";
17 $p->{'view'} = "entry";
18 $p->{'comment_pages'} = undef;
19 $p->{'comments'} = [];
20 $p->{'comment_pages'} = undef;
22 $p->{'view_my_games'} = $remote && $remote->equals($u) && !LJ
::SUP
->is_remote_sup() && LJ
::UserApps
->user_games_count($remote);
24 # setup viewall options
25 my ($viewall, $viewsome) = (0, 0);
26 if ($get->{viewall
} && LJ
::check_priv
($remote, 'canview', 'suspended')) {
27 # we don't log here, as we don't know what entry we're viewing yet. the logging
28 # is done when we call EntryPage_entry below.
29 $viewall = LJ
::check_priv
($remote, 'canview', '*');
30 $viewsome = $viewall || LJ
::check_priv
($remote, 'canview', 'suspended');
33 my ($entry, $s2entry) = EntryPage_entry
($u, $remote, $opts);
34 return if $opts->{'suspendeduser'};
35 return if $opts->{'suspendedentry'};
36 return if $opts->{'readonlyremote'};
37 return if $opts->{'readonlyjournal'};
38 return if $opts->{'handler_return'};
39 return if $opts->{'redir'};
41 $p->{'multiform_on'} = $entry->comments_manageable_by($remote);
43 my $itemid = $entry->jitemid;
44 my $permalink = $entry->url;
45 my $stylemine = $get->{'style'} eq "mine" ?
"style=mine" : "";
46 my $style_set = defined $get->{'s2id'} ?
"s2id=" . int( $get->{'s2id'} ) : "";
47 my $style_arg = ($stylemine ne '' and $style_set ne '') ?
($stylemine . '&' . $style_set) : ($stylemine . $style_set);
49 if ($u->should_block_robots || $entry->should_block_robots) {
50 $p->{'head_content'} .= LJ
::robot_meta_tags
();
53 $p->{'head_content'} .= '<meta http-equiv="Content-Type" content="text/html; charset='.$opts->{'saycharset'}."\" />\n";
69 js/selectable_table.js
70 )) if ! $LJ::DISABLED
{userpicselect
} && $remote && $remote->get_cap('userpicselect');
84 comment
.delete.all
.sub
85 comment
.delete.no.options
88 comment
.mark
.spam
.title
89 comment
.mark
.spam
.subject
90 comment
.mark
.spam
.button
94 $p->{'entry'} = $s2entry;
95 LJ
::run_hook
('notify_event_displayed', $entry);
98 my $view_arg = $get->{'view'} || "";
99 my $flat_mode = ($view_arg =~ /\bflat\b/);
100 my $view_num = ($view_arg =~ /(\d+)/) ?
$1 : undef;
105 'flat' => $flat_mode,
106 'thread' => int($get->{'thread'} / 256),
107 'page' => $get->{'page'},
109 'userpicref' => \
%userpic,
111 # user object is cached from call just made in EntryPage_entry
112 'up' => LJ
::load_user
($s2entry->{'poster'}->{'username'}),
113 'viewall' => $viewall,
114 'expand_all' => $opts->{expand_all
},
116 'showspam' => $p->{'showspam'} && !$get->{from_rpc
},
119 ## Expand all comments on page
120 unless ($LJ::DISABLED
{allow_expand_all_comments
}){
121 $copts->{expand_all
} = 1 if $get->{expand
} eq 'all';
124 my $userlite_journal = UserLite
($u);
127 if ($entry->comments_shown) {
128 ## allow to modify strategies to load/expand comments tree.
129 LJ
::run_hooks
('load_comments_opts', $u, $itemid, $copts);
130 @comments = LJ
::Talk
::load_comments
($u, $remote, "L", $itemid, $copts);
135 my $tz = $remote->prop("timezone");
136 $tz_remote = $tz ?
eval { DateTime
::TimeZone
->new( name
=> $tz); } : undef;
139 my $pics = LJ
::Talk
::get_subjecticons
()->{'pic'}; # hashref of imgname => { w, h, img }
140 my $convert_comments = sub {
141 my ($self, $destlist, $srclist, $depth) = @_;
143 foreach my $com (@
$srclist) {
144 my $pu = $com->{'posterid'} ?
$user{$com->{'posterid'}} : undef;
146 my $dtalkid = $com->{'talkid'} * 256 + $entry->anum;
147 my $text = $com->{'body'};
148 if ($get->{'nohtml'}) {
149 # quote all non-LJ tags
150 $text =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
152 LJ
::CleanHTML
::clean_comment
(\
$text, { 'preformatted' => $com->{'props'}->{'opt_preformatted'},
153 'anon_comment' => (!$pu || $pu->{'journaltype'} eq 'I'),
157 # local time in mysql format to gmtime
158 my $datetime = DateTime_unix
($com->{'datepost_unix'});
159 my $datetime_remote = $tz_remote ? DateTime_tz
($com->{'datepost_unix'}, $tz_remote) : undef;
160 my $seconds_since_entry = $com->{'datepost_unix'} - $entry->logtime_unix;
161 my $datetime_poster = DateTime_tz
($com->{'datepost_unix'}, $pu);
163 my ($edited, $edit_url, $edittime, $edittime_remote, $edittime_poster);
164 if ($com->{_loaded
}) {
165 my $comment = LJ
::Comment
->new($u, jtalkid
=> $com->{talkid
});
167 $edited = $comment->is_edited;
168 $edit_url = LJ
::Talk
::talkargs
($comment->edit_url, $style_arg);
170 $edittime = DateTime_unix
($comment->edit_time);
171 $edittime_remote = $tz_remote ? DateTime_tz
($comment->edit_time, $tz_remote) : undef;
172 $edittime_poster = DateTime_tz
($comment->edit_time, $pu);
176 my $subject_icon = undef;
177 if (my $si = $com->{'props'}->{'subjecticon'}) {
178 my $pic = $pics->{$si};
179 $subject_icon = Image
("$LJ::IMGPREFIX/talk/$pic->{'img'}",
180 $pic->{'w'}, $pic->{'h'}) if $pic;
184 if (my $pic = $userpic{$com->{'picid'}}) {
185 $comment_userpic = Image
("$LJ::USERPIC_ROOT/$com->{'picid'}/$pic->{'userid'}",
186 $pic->{'width'}, $pic->{'height'});
189 my $reply_url = LJ
::Talk
::talkargs
($permalink, "replyto=$dtalkid", $style_arg);
193 # in flat mode, promote the parenttalkid_actual
195 $com->{'parenttalkid'} ||= $com->{'parenttalkid_actual'};
198 if ($com->{'parenttalkid'}) {
199 my $dparent = ($com->{'parenttalkid'} * 256) + $entry->anum;
200 $par_url = LJ
::Talk
::talkargs
($permalink, "thread=$dparent", $style_arg) . "#t$dparent";
204 if ($com->{'posterid'} && $pu) {
205 $poster = UserLite
($pu);
206 $poster->{'_opt_side_alias'} = 1;
209 # Comment Posted Notice
210 my ($last_talkid, $last_jid) = LJ
::get_lastcomment
();
211 my $commentposted = "";
213 if ($last_talkid == $dtalkid && $last_jid == $remote->{'userid'});
216 '_type' => 'Comment',
217 'journal' => $userlite_journal,
219 'picture_keyword' => $com->{'props'}->{'picture_keyword'},
221 'permalink_url' => "$permalink?thread=$dtalkid#t$dtalkid",
222 'reply_url' => $reply_url,
225 'subject' => LJ
::ehtml
($com->{'subject'}),
226 'subject_icon' => $subject_icon,
227 'talkid' => $dtalkid,
229 'userpic' => $comment_userpic,
231 'system_time' => $datetime, # same as regular time for comments
232 'edittime' => $edittime,
234 'full' => $com->{'_loaded'} ?
1 : 0,
235 'show' => $com->{'_show'} ?
1 : 0,
237 'parent_url' => $par_url,
238 'spam' => $com->{'state'} eq "B" ?
1 : 0,
239 'screened' => $com->{'state'} eq "S" ?
1 : 0,
240 'frozen' => $com->{'state'} eq "F" || !$entry->posting_comments_allowed ?
1 : 0,
241 'deleted' => $com->{'state'} eq "D" ?
1 : 0,
242 'link_keyseq' => [ 'delete_comment' ],
243 'anchor' => "t$dtalkid",
244 'dom_id' => "ljcmt$dtalkid",
245 'comment_posted' => $commentposted,
246 'edited' => $edited ?
1 : 0,
247 'time_remote' => $datetime_remote,
248 'time_poster' => $datetime_poster,
249 'seconds_since_entry' => $seconds_since_entry,
250 'edittime_remote' => $edittime_remote,
251 'edittime_poster' => $edittime_poster,
252 'edit_url' => $edit_url,
255 # don't show info from suspended users, and from users who deleted their journals
256 # and choosed to delete their comments in other journals
257 if (!$viewsome && $pu) {
259 if ($pu->is_suspended) {
261 } elsif ($pu->is_deleted) {
262 my ($purge_comments, $purge_community_entries) = split /:/, $pu->prop("purge_external_content");
263 if ($purge_comments && !$LJ::JOURNALS_WITH_PROTECTED_CONTENT
{ $u->{user
} }) {
269 $s2com->{'text'} = "";
270 $s2com->{'subject'} = "";
271 $s2com->{'full'} = 0;
272 $s2com->{'subject_icon'} = undef;
273 $s2com->{'userpic'} = undef;
277 # Conditionally add more links to the keyseq
278 my $link_keyseq = $s2com->{'link_keyseq'};
279 push @
$link_keyseq, $s2com->{'spam'} ?
'unspam_comment' : 'spam_comment';
280 push @
$link_keyseq, $s2com->{'screened'} ?
'unscreen_comment' : 'screen_comment';
281 if ($entry->posting_comments_allowed) {
282 push @
$link_keyseq, $s2com->{'frozen'} ?
'unfreeze_thread' : 'freeze_thread';
284 push @
$link_keyseq, "watch_thread" unless $LJ::DISABLED
{'esn'};
285 push @
$link_keyseq, "unwatch_thread" unless $LJ::DISABLED
{'esn'};
286 push @
$link_keyseq, "watching_parent" unless $LJ::DISABLED
{'esn'};
287 unshift @
$link_keyseq, "edit_comment" if LJ
::is_enabled
("edit_comments");
289 $s2com->{'thread_url'} = LJ
::Talk
::talkargs
($permalink, "thread=$dtalkid", $style_arg) . "#t$dtalkid";
291 # add the poster_ip metadata if remote user has
293 $s2com->{'metadata'}->{'poster_ip'} = $com->{'props'}->{'poster_ip'} if
294 ($com->{'props'}->{'poster_ip'} && $remote &&
295 ($remote->{'userid'} == $entry->posterid ||
296 ($remote && $remote->can_manage($u)) || $viewall));
298 push @
$destlist, $s2com;
300 $self->($self, $s2com->{'replies'}, $com->{'children'}, $depth+1);
303 $p->{'comments'} = [];
304 $convert_comments->($convert_comments, $p->{'comments'}, \
@comments, ($get->{'depth'} || 0) + 1);
306 # prepare the javascript data structure to put in the top of the page
307 # if the remote user is a manager of the comments
308 my $do_commentmanage_js = $p->{'multiform_on'};
309 if ($LJ::DISABLED
{'commentmanage'}) {
310 if (ref $LJ::DISABLED
{'commentmanage'} eq "CODE") {
311 $do_commentmanage_js = $LJ::DISABLED
{'commentmanage'}->($remote);
313 $do_commentmanage_js = 0;
319 my $canAdmin = ($remote && ($remote->can_manage($u) || $remote->can_sweep($u))) ?
1 : 0;
320 my $formauth = LJ
::ejs
(LJ
::eurl
(LJ
::form_auth
(1)));
323 form_auth
=> $formauth,
325 canAdmin
=> $canAdmin,
326 remote
=> $remote ?
$remote->user : undef,
330 my ($self, $array, $depth) = @_;
332 foreach my $i (@
$array) {
333 my $cmt = LJ
::Comment
->new($u, dtalkid
=> $i->{talkid
});
335 my $has_threads = scalar @
{$i->{'replies'}};
336 my $poster = $i->{'poster'} ?
$i->{'poster'}{'username'} : "";
337 my @child_ids = map { $_->{'talkid'} } @
{$i->{'replies'}};
338 my $parent = $cmt->parent;
339 $cmtinfo->{$i->{talkid
}} = {
342 username
=> $i->{'poster'} ?
$i->{'poster'}->{'_u'}->{'user'} : '',
343 parent
=> $parent && $parent->valid ?
$parent->dtalkid : undef,
344 full
=> ($i->{full
}),
347 $self->($self, $i->{'replies'}, $depth + 1) if $has_threads;
351 $recurse->($recurse, $p->{'comments'}, 0);
353 my $js = "<script>\n// don't crawl this. read http://www.livejournal.com/developer/exporting.bml\n";
354 $js .= "var LJ_cmtinfo = " . LJ
::js_dumper
($cmtinfo) . "\n";
356 $p->{'LJ_cmtinfo'} = $js if $opts->{'need_cmtinfo'};
357 $p->{'head_content'} .= $js;
361 'title' => LJ
::Text
->drop_html($entry->subject_raw),
362 'description' => LJ
::Text
->drop_html($entry->event_raw),
365 $p->{'head_content'} .= qq[
366 <meta name
="title" value
="$meta{'title'}"/>
367 <meta name
="description" value
="$meta{'description'}"/>
374 $p->{'_stylemine'} = $get->{'style'} eq 'mine' ?
1 : 0;
375 $p->{'_picture_keyword'} = $get->{'prop_picture_keyword'};
377 $p->{'viewing_thread'} = $get->{'thread'} ?
1 : 0;
379 # default values if there were no comments, because
380 # LJ::Talk::load_comments() doesn't provide them.
381 if ($copts->{'out_error'} eq 'noposts' || scalar @comments < 1) {
382 $copts->{'out_pages'} = $copts->{'out_page'} = 1;
383 $copts->{'out_items'} = 0;
384 $copts->{'out_itemfirst'} = $copts->{'out_itemlast'} = undef;
387 $p->{'comment_pages'} = ItemRange
({
388 'all_subitems_displayed' => ($copts->{'out_pages'} == 1),
389 'current' => $copts->{'out_page'},
390 'from_subitem' => $copts->{'out_itemfirst'},
391 'num_subitems_displayed' => scalar @comments,
392 'to_subitem' => $copts->{'out_itemlast'},
393 'total' => $copts->{'out_pages'},
394 'total_subitems' => $copts->{'out_items'},
396 my $sty = $flat_mode ?
"view=flat&" : "";
397 return "$permalink?${sty}page=" . int($_[0]) .
398 ($style_arg ?
"&$style_arg" : '');
407 my ($u, $remote, $opts) = @_;
409 my $get = $opts->{'getargs'};
411 my $uri = LJ
::Request
->uri;
413 my ($ditemid, $itemid);
414 my $entry = $opts->{ljentry
}; # only defined in named-URI case. otherwise undef.
416 unless ($entry || $uri =~ /(\d+)\.html/) {
417 $opts->{'handler_return'} = 404;
418 LJ
::Request
->pnotes ('error' => 'e404');
419 LJ
::Request
->pnotes ('remote' => LJ
::get_remote
());
423 $entry ||= LJ
::Entry
->new($u, ditemid
=> $1);
425 unless ($entry and $entry->correct_anum) {
426 $opts->{'handler_return'} = 404;
427 LJ
::Request
->pnotes ('error' => 'e404');
428 LJ
::Request
->pnotes ('remote' => LJ
::get_remote
());
432 $ditemid = $entry->ditemid;
433 $itemid = $entry->jitemid;
435 my $pu = $entry->poster;
437 my $userlite_journal = UserLite
($u);
438 my $userlite_poster = UserLite
($pu);
440 # do they have the viewall priv?
441 my $canview = $get->{'viewall'} && LJ
::check_priv
($remote, "canview");
442 my ($viewall, $viewsome) = (0, 0);
444 LJ
::statushistory_add
($u->{'userid'}, $remote->{'userid'},
445 "viewall", "entry: $u->{'user'}, itemid: $itemid, statusvis: $u->{'statusvis'}");
446 $viewall = LJ
::check_priv
($remote, 'canview', '*');
447 $viewsome = $viewall || LJ
::check_priv
($remote, 'canview', 'suspended');
450 # check using normal rules
451 unless ($entry->visible_to($remote, { viewall
=> $canview })) {
453 $opts->{'handler_return'} = 403;
454 LJ
::Request
->pnotes ('error' => 'private');
455 LJ
::Request
->pnotes ('remote' => LJ
::get_remote
());
458 my $host = LJ
::Request
->header_in("Host");
459 my $args = scalar LJ
::Request
->args;
460 my $querysep = $args ?
"?" : "";
461 my $redir = LJ
::eurl
("http://$host$uri$querysep$args");
462 $opts->{'redir'} = "$LJ::SITEROOT/?returnto=$redir&errmsg=notloggedin";
467 if (($pu && $pu->{'statusvis'} eq 'S') && !$viewsome) {
468 $opts->{'suspendeduser'} = 1;
469 LJ
::Request
->pnotes ('error' => 'suspended');
470 LJ
::Request
->pnotes ('remote' => LJ
::get_remote
());
474 if ($entry && $entry->is_suspended_for($remote)) {
475 $opts->{'suspendedentry'} = 1;
476 LJ
::Request
->pnotes ('error' => 'suspended_post');
477 LJ
::Request
->pnotes ('remote' => LJ
::get_remote
());
481 my $replycount = $entry->prop("replycount");
483 $nc .= "nc=$replycount" if $replycount && $remote && $remote->{'opt_nctalklinks'};
485 my $stylemine = $get->{'style'} eq "mine" ?
"style=mine" : "";
486 my $style_set = defined $get->{'s2id'} ?
"s2id=" . int( $get->{'s2id'} ) : "";
487 my $style_arg = ($stylemine ne '' and $style_set ne '') ?
($stylemine . '&' . $style_set) : ($stylemine . $style_set);
488 my $show_spam_arg = ($get->{'mode'} ne "showspam" and LJ
::is_enabled
('spam_button')) ?
"mode=showspam" : "";
490 my $userpic = Image_userpic
($pu, $entry->userpic ?
$entry->userpic->picid : 0);
492 my $permalink = $entry->url;
493 my $readurl = LJ
::Talk
::talkargs
($permalink, $nc, $style_arg);
494 my $readspamurl = LJ
::Talk
::talkargs
($permalink, $nc, $style_arg, $show_spam_arg);
495 my $posturl = LJ
::Talk
::talkargs
($permalink, "mode=reply", $style_arg);
497 my $comments = CommentInfo
({
498 'read_url' => $readurl,
499 'read_spam_url' => LJ
::Talk
::can_unmark_spam
($remote, $u, $pu) ?
$readspamurl : '',
500 'spam_counter' => $entry->prop('spam_counter') || 0,
501 'post_url' => $posturl,
502 'count' => $replycount,
503 'maxcomments' => ($replycount >= LJ
::get_cap
($u, 'maxcomments')) ?
1 : 0,
504 'enabled' => $entry->comments_shown,
505 'locked' => !$entry->posting_comments_allowed,
506 'screened' => ($entry->prop("hasscreened") and $remote && LJ
::Talk
::can_view_screened
($remote, $u)),
509 $comments->{show_postlink
} = $entry->posting_comments_allowed;
510 $comments->{show_readlink
} = $entry->comments_shown && ($replycount || $comments->{'screened'});
515 my $tag_map = $entry->tag_map;
516 while (my ($kwid, $kw) = each %$tag_map) {
517 push @taglist, Tag
($u, $kwid => $kw);
519 LJ
::run_hooks
('augment_s2_tag_list', u
=> $u, jitemid
=> $itemid, tag_list
=> \
@taglist);
520 @taglist = sort { $a->{name
} cmp $b->{name
} } @taglist;
523 my $subject = $entry->subject_html;
525 my $no_cut_expand = !$get->{cut_expand
} && $get->{page
} && $get->{page
} > 1 ?
1 : 0;
527 my $event = $entry->event_html({
528 no_cut_expand
=> $no_cut_expand,
529 page
=> $get->{page
},
532 if ($get->{'nohtml'}) {
533 # quote all non-LJ tags
534 $subject =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
535 $event =~ s{<(?!/?lj)(.*?)>} {<$1>}gi;
538 if ($opts->{enable_tags_compatibility
} && @taglist) {
539 $event .= LJ
::S2
::get_tags_text
($opts->{ctx
}, \
@taglist);
542 if ($entry->security eq "public") {
543 $LJ::REQ_GLOBAL
{'text_of_first_public_post'} = $event;
546 $LJ::REQ_GLOBAL
{'tags_of_first_public_post'} = [map { $_->{name
} } @taglist];
549 my @verticals = $entry->verticals_list_for_ad;
551 $LJ::REQ_GLOBAL
{'verticals_of_first_public_post'} = join(",", @verticals);
555 my $s2entry = Entry
($u, {
556 'subject' => $subject,
558 'dateparts' => LJ
::TimeUtil
->alldatepart_s2($entry->eventtime_mysql),
559 'system_dateparts' => LJ
::TimeUtil
->alldatepart_s2($entry->logtime_mysql),
560 'security' => $entry->security,
561 'allowmask' => $entry->allowmask,
562 'props' => $entry->props,
563 'itemid' => $ditemid,
564 'comments' => $comments,
565 'journal' => $userlite_journal,
566 'poster' => $userlite_poster,
570 'userpic' => $userpic,
571 'permalink_url' => $permalink,
574 return ($entry, $s2entry);