#!/usr/bin/perl # # This code was forked from the LiveJournal project owned and operated # by Live Journal, Inc. The code has been modified and expanded by # Dreamwidth Studios, LLC. These files were originally licensed under # the terms of the license supplied by Live Journal, Inc, which can # currently be found at: # # http://code.livejournal.org/trac/livejournal/browser/trunk/LICENSE-LiveJournal.txt # # In accordance with the original license, this code and all its # modifications are provided under the GNU General Public License. # A copy of that license can be found in the LICENSE file included as # part of this distribution. use strict; package LJ::S2; 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'}; # reply page of suspended entry cannot be accessed by anyone, even entry poster if ( $entry && $entry->is_suspended ) { $opts->{suspendedentry} = 1; return; } # read-only users can't comment anywhere if ( $remote && $remote->is_readonly ) { $opts->{readonlyremote} = 1; return; } # no one can comment in a read-only journal if ( $u->is_readonly ) { $opts->{readonlyjournal} = 1; return; } return if $opts->{'handler_return'}; return if $opts->{'redir'}; return if $opts->{internal_redir}; my $ditemid = $entry->ditemid; my $replytoid = $get->{replyto} ? $get->{replyto} : 0; # canonical link to the entry or comment thread $p->{head_content} .= LJ::canonical_link( $entry->url, $replytoid ); $p->{'head_content'} .= qq{ }; LJ::need_res( LJ::S2::tracking_popup_js() ); # include JS for quick reply, icon browser, and ajax cut tag my $handle_with_siteviews = $opts->{handle_with_siteviews_ref} && ${ $opts->{handle_with_siteviews_ref} }; LJ::Talk::init_s2journal_js( iconbrowser => $remote && $remote->can_use_userpic_select, siteskin => $handle_with_siteviews, noqr => 1 ); if ( $u->should_block_robots || $entry->should_block_robots ) { $p->{'head_content'} .= LJ::robot_meta_tags(); } $p->{'entry'} = $s2entry; LJ::Hooks::run_hook( 'notify_event_displayed', $entry ); # setup the replying item my $replyto = $s2entry; my $editid = $get->{edit} ? $get->{edit} : 0; my $parpost; my $parentcomment; my $comment; my %comment_values; if ($editid) { my $errref; $comment = LJ::Comment->new( $u, dtalkid => $editid ); unless ($remote) { my $redir = LJ::eurl( LJ::create_url( undef, keep_args => 1 ) ); $opts->{'redir'} = "$LJ::SITEROOT/?returnto=$redir&errmsg=notloggedin"; return; } unless ( $comment->remote_can_edit( \$errref ) ) { if ($errref) { $opts->{status} = "403 Forbidden"; return "

$errref

"; } $opts->{'handler_return'} = 403; return; } $parpost = $comment->parent; # for comments where the parent comment is deleted, we pretend the parent comment doesn't exist so the user can edit $parpost = undef if $parpost && $parpost->is_deleted; $replytoid = $parpost ? $comment->parent->dtalkid : 0; $comment_values{editid} = $editid; $comment_values{replyto} = $replytoid; $comment_values{subject} = $comment->subject_orig; $comment_values{body} = $comment->body_orig; $comment_values{subjecticon} = $comment->prop('subjecticon'); $comment_values{prop_opt_preformatted} = $comment->prop('opt_preformatted'); $comment_values{prop_picture_keyword} = $comment->userpic_kw; $comment_values{prop_editor} = $comment->prop('editor'); } if ($replytoid) { my $re_talkid = int( $replytoid >> 8 ); my $re_anum = $replytoid % 256; unless ( $re_anum == $entry->anum ) { $opts->{'handler_return'} = 404; return; } my $dtalkid = $re_talkid * 256 + $entry->anum; # FIXME: Why are we loading the comment manually when we do LJ::Comment->new below # and could do everything through there. 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; } my $parentcomment = LJ::Comment->new( $u, jtalkid => $re_talkid ); unless ( $parpost and $parpost->{'state'} ne 'D' ) { # FIXME: This is a hack. See below... $opts->{status} = "404 Not Found"; return "

This comment has been deleted; you cannot reply to it.

"; } if ( $parpost->{state} eq 'S' && !$parentcomment->visible_to($remote) ) { $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 "

This thread has been frozen; no more replies are allowed.

"; } if ( $entry->is_suspended ) { $opts->{status} = "403 Forbidden"; return "

This entry has been suspended; you cannot reply to it.

"; } if ( $remote && $remote->is_readonly ) { $opts->{status} = "403 Forbidden"; return "

You are read-only. You cannot reply to this entry.

"; } 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 ( $parpost->{'props'}->{'unknown8bit'} ) { LJ::item_toutf8( $u, \$parpost->{'subject'}, \$parpost->{'body'}, {} ); } my $datetime = DateTime_unix( LJ::mysqldate_to_time( $parpost->{'datepost'} ) ); my $comment_userpic; my $s2poster; my $pu = $parentcomment->poster; if ($pu) { return $opts->{handler_return} = 403 if $pu->is_suspended; # do not show comments by suspended users $s2poster = UserLite($pu); my ( $pic, $pickw ) = $parentcomment->userpic; $comment_userpic = Image_userpic( $pu, $pic ? $pic->picid : 0, $pickw ); } my $anon_comment = LJ::Talk::treat_as_anon( $pu, $u ); LJ::CleanHTML::clean_comment( \$parpost->{'body'}, { preformatted => $parentcomment->prop('opt_preformatted'), anon_comment => $anon_comment, nocss => $anon_comment, editor => $parentcomment->prop('editor'), datepost => $parentcomment->{datepost}, # for format guessing is_imported => defined $parentcomment->prop('import_source') ? 1 : 0, } ); my $cmtobj = LJ::Comment->new( $u, dtalkid => $dtalkid ); my $tz_remote; my $datetime_remote; my $datetime_poster; if ($remote) { my $tz = $remote->prop("timezone"); $tz_remote = $tz ? eval { DateTime::TimeZone->new( name => $tz ); } : undef; } $datetime_remote = $tz_remote ? DateTime_tz( $cmtobj->unixtime, $tz_remote ) : undef; $datetime_poster = $parentcomment ? DateTime_tz( $cmtobj->unixtime, $parentcomment->poster ) : undef; my $replyargs = LJ::viewing_style_args(%$get); $replyto = { '_type' => 'Comment', 'subject' => LJ::ehtml( $parpost->{'subject'} ), 'text' => $parpost->{'body'}, 'userpic' => $comment_userpic, 'poster' => $s2poster, 'journal' => $s2entry->{'journal'}, 'metadata' => {}, 'permalink_url' => $cmtobj->url($replyargs), 'depth' => 1, 'parent_url' => $cmtobj->parent_url($replyargs), 'threadroot_url' => $cmtobj->threadroot_url($replyargs), 'time' => $datetime, 'system_time' => $datetime, 'time_remote' => $datetime_remote, 'time_poster' => $datetime_poster, 'tags' => [], 'talkid' => $dtalkid, 'link_keyseq' => ['delete_comment'], 'screened' => $parpost->{'state'} eq "S" ? 1 : 0, 'frozen' => $parpost->{'state'} eq "F" ? 1 : 0, 'deleted' => $parpost->{'state'} eq "D" ? 1 : 0, 'full' => 1, timeformat24 => $remote && $remote->use_24hour_time, admin_post => $cmtobj->admin_post ? 1 : 0, }; # Conditionally add more links to the keyseq my $link_keyseq = $replyto->{'link_keyseq'}; push @$link_keyseq, $replyto->{'screened'} ? 'unscreen_comment' : 'screen_comment'; push @$link_keyseq, $replyto->{'frozen'} ? 'unfreeze_thread' : 'freeze_thread'; push @$link_keyseq, "watch_thread" if LJ::is_enabled('esn'); push @$link_keyseq, "unwatch_thread" if LJ::is_enabled('esn'); push @$link_keyseq, "watching_parent" if LJ::is_enabled('esn'); unshift @$link_keyseq, "edit_comment" if LJ::is_enabled('edit_comments'); } $p->{'replyto'} = $replyto; $p->{'form'} = { '_type' => "ReplyForm", '_remote' => $remote, '_u' => $u, '_ditemid' => $ditemid, '_entry' => $entry, '_parpost' => $parpost, '_values' => \%comment_values, '_styleopts' => $p->{_styleopts}, '_thread' => $get->{thread} || 0, }; $p->{'isedit'} = $editid ? 1 : 0; 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; my $post_vars = DW::Request->get->post_args; $post_vars = $form->{_values} unless keys %$post_vars; # _values only gets populated when editing comment. -NF $S2::pout->( LJ::Talk::talkform( { 'journalu' => $u, 'parpost' => $parpost, 'replyto' => $parent, 'ditemid' => $form->{'_ditemid'}, 'styleopts' => $form->{_styleopts}, 'thread' => $form->{_thread}, 'form' => $post_vars, 'do_captcha' => LJ::Talk::Post::require_captcha_test( $remote, $u, $post_vars->{body}, $form->{'_entry'} ) } ) ); } 1;