423 lines
15 KiB
Perl
423 lines
15 KiB
Perl
|
|
#!/usr/bin/perl
|
||
|
|
#
|
||
|
|
# DW::Controller::Recent_comments
|
||
|
|
#
|
||
|
|
# This controller is for the Recent Comments pages.
|
||
|
|
#
|
||
|
|
# Authors:
|
||
|
|
# hotlevel4 <hotlevel4@hotmail.com>
|
||
|
|
#
|
||
|
|
# Copyright (c) 2013 by Dreamwidth Studios, LLC.
|
||
|
|
#
|
||
|
|
# This is based on code originally implemented on LiveJournal.
|
||
|
|
#
|
||
|
|
# This program is free software; you may redistribute it and/or modify it under
|
||
|
|
# the same terms as Perl itself. For a copy of the license, please reference
|
||
|
|
# 'perldoc perlartistic' or 'perldoc perlgpl'.
|
||
|
|
#
|
||
|
|
|
||
|
|
package DW::Controller::Comments;
|
||
|
|
|
||
|
|
use strict;
|
||
|
|
use warnings;
|
||
|
|
|
||
|
|
use LJ::JSON;
|
||
|
|
|
||
|
|
use DW::Controller;
|
||
|
|
use DW::Routing;
|
||
|
|
use DW::Template;
|
||
|
|
|
||
|
|
DW::Routing->register_string( '/comments/recent', \&received_handler, app => 1 );
|
||
|
|
DW::Routing->register_string( '/comments/posted', \&posted_handler, app => 1 );
|
||
|
|
|
||
|
|
# redirect /tools/recent_comments, /tools/recent_comments.bml
|
||
|
|
DW::Routing->register_redirect(
|
||
|
|
'/tools/recent_comments', '/comments/recent',
|
||
|
|
app => 1,
|
||
|
|
formats => [ 'html', 'bml' ]
|
||
|
|
);
|
||
|
|
|
||
|
|
sub received_handler {
|
||
|
|
my ( $ok, $rv ) = controller( authas => 1 );
|
||
|
|
return $rv unless $ok;
|
||
|
|
|
||
|
|
my $r = $rv->{r};
|
||
|
|
my $u = $rv->{u};
|
||
|
|
my $remote = $rv->{remote};
|
||
|
|
|
||
|
|
my $dbcr = LJ::get_cluster_reader($u);
|
||
|
|
die "Error: can't get DB for user" unless $dbcr;
|
||
|
|
|
||
|
|
my $vars;
|
||
|
|
$vars->{u} = $u;
|
||
|
|
$vars->{authas_html} = $rv->{authas_html};
|
||
|
|
$vars->{getextra} = ( $u ne $remote ) ? { authas => $u->user } : {};
|
||
|
|
|
||
|
|
my %LJ_cmtinfo = %{ LJ::Comment->info($u) };
|
||
|
|
$LJ_cmtinfo{form_auth} = LJ::form_auth(1);
|
||
|
|
|
||
|
|
$vars = initialize_count( $u, $r, $vars );
|
||
|
|
|
||
|
|
my ( @recv, %talkids );
|
||
|
|
my %need_userid;
|
||
|
|
$need_userid{ $u->{userid} } = 1 if $u->is_community; # Need to load the community for logtext
|
||
|
|
my %logrow; # "jid nodeid" -> $logrow
|
||
|
|
my %need_logids; # hash of "journalid jitemid" => [journalid, jitemid]
|
||
|
|
|
||
|
|
my $now = time();
|
||
|
|
|
||
|
|
# Retrieve received
|
||
|
|
if ( $u->is_person || $u->is_community ) {
|
||
|
|
@recv = $u->get_recent_talkitems( $vars->{count} );
|
||
|
|
foreach my $post (@recv) {
|
||
|
|
$need_userid{ $post->{posterid} } = 1 if $post->{posterid};
|
||
|
|
$talkids{ $post->{jtalkid} } = 1;
|
||
|
|
$need_logids{"$u->{userid} $post->{nodeid}"} = [ $u->{userid}, $post->{nodeid} ]
|
||
|
|
if $post->{nodetype} eq "L";
|
||
|
|
}
|
||
|
|
@recv = sort { $b->{datepostunix} <=> $a->{datepostunix} } @recv;
|
||
|
|
my @recv_talkids = map { $_->{'jtalkid'} } @recv;
|
||
|
|
|
||
|
|
my %props;
|
||
|
|
LJ::load_talk_props2( $u->{'userid'}, \@recv_talkids, \%props );
|
||
|
|
|
||
|
|
my $us = LJ::load_userids( keys %need_userid );
|
||
|
|
|
||
|
|
# setup the parameter to get_posts_raw
|
||
|
|
my @need_logtext;
|
||
|
|
foreach my $need ( values %need_logids ) {
|
||
|
|
my ( $ownerid, $itemid ) = @$need;
|
||
|
|
my $ju = $us->{$ownerid} or next;
|
||
|
|
push @need_logtext, [ $ju->{clusterid}, $ownerid, $itemid ];
|
||
|
|
}
|
||
|
|
|
||
|
|
my $comment_text = LJ::get_talktext2( $u, keys %talkids );
|
||
|
|
my $log_data = LJ::get_posts_raw( { text_only => 1 }, @need_logtext );
|
||
|
|
my $log_text = $log_data->{text};
|
||
|
|
my $root = $u->journal_base;
|
||
|
|
|
||
|
|
# Cycle through comments and skip deleted ones
|
||
|
|
foreach my $r (@recv) {
|
||
|
|
next unless $r->{nodetype} eq "L";
|
||
|
|
next if $r->{state} eq "D";
|
||
|
|
|
||
|
|
my $pu = $us->{ $r->{posterid} };
|
||
|
|
next if $pu && ( $pu->is_expunged || $pu->is_suspended );
|
||
|
|
|
||
|
|
$r->{'props'} = $props{ $r->{'jtalkid'} };
|
||
|
|
|
||
|
|
my $lrow = $logrow{"$u->{userid} $r->{nodeid}"} ||=
|
||
|
|
LJ::get_log2_row( $u, $r->{'nodeid'} );
|
||
|
|
my $talkid = ( $r->{'jtalkid'} << 8 ) + $lrow->{'anum'};
|
||
|
|
|
||
|
|
my $ditemid = "$root/$lrow->{ditemid}.html";
|
||
|
|
my $commentanchor = LJ::Talk::comment_anchor($talkid);
|
||
|
|
my $talkurl = "$root/$lrow->{ditemid}.html?thread=$talkid$commentanchor";
|
||
|
|
|
||
|
|
my $state = "";
|
||
|
|
my $tdclass = "";
|
||
|
|
if ( $r->{state} eq "S" ) {
|
||
|
|
$state = "Screened";
|
||
|
|
$tdclass = "screened";
|
||
|
|
}
|
||
|
|
elsif ( $r->{state} eq "D" ) {
|
||
|
|
$state = "Deleted";
|
||
|
|
}
|
||
|
|
elsif ( $r->{state} eq "F" ) {
|
||
|
|
$state = "Frozen";
|
||
|
|
}
|
||
|
|
|
||
|
|
my $ljcmt = $LJ_cmtinfo{$talkid} = {};
|
||
|
|
$ljcmt->{u} = $pu ? $pu->{user} : "";
|
||
|
|
|
||
|
|
my $isanonymous = LJ::isu($pu) ? 0 : 1;
|
||
|
|
|
||
|
|
my $hr_ago = LJ::diff_ago_text( $r->{datepostunix}, $now );
|
||
|
|
|
||
|
|
my $del_link = LJ::create_url(
|
||
|
|
"/delcomment",
|
||
|
|
args => {
|
||
|
|
journal => $u->{'user'},
|
||
|
|
id => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
my $del_img = LJ::img( "btn_del", "", { align => 'absmiddle', hspace => 2 } );
|
||
|
|
|
||
|
|
my $freeze_link;
|
||
|
|
my $freeze_img;
|
||
|
|
|
||
|
|
if ( $r->{'state'} ne 'F' ) {
|
||
|
|
$freeze_link = LJ::create_url(
|
||
|
|
"/talkscreen",
|
||
|
|
args => {
|
||
|
|
mode => "freeze",
|
||
|
|
journal => $u->{'user'},
|
||
|
|
talkid => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
$freeze_img = LJ::img( "btn_freeze", "", { align => 'absmiddle', hspace => 2 } );
|
||
|
|
}
|
||
|
|
elsif ( $r->{'state'} eq 'F' ) {
|
||
|
|
$freeze_link = LJ::create_url(
|
||
|
|
"/talkscreen",
|
||
|
|
args => {
|
||
|
|
mode => "unfreeze",
|
||
|
|
journal => $u->{'user'},
|
||
|
|
talkid => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
$freeze_img = LJ::img( "btn_unfreeze", "", { align => 'absmiddle', hspace => 2 } );
|
||
|
|
}
|
||
|
|
|
||
|
|
my $screen_link;
|
||
|
|
my $screen_img;
|
||
|
|
|
||
|
|
if ( $r->{'state'} ne 'S' ) {
|
||
|
|
$screen_link = LJ::create_url(
|
||
|
|
"/talkscreen",
|
||
|
|
args => {
|
||
|
|
mode => "screen",
|
||
|
|
journal => $u->{'user'},
|
||
|
|
talkid => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
$screen_img = LJ::img( "btn_scr", "", { align => 'absmiddle', hspace => 2 } );
|
||
|
|
}
|
||
|
|
elsif ( $r->{'state'} eq 'S' ) {
|
||
|
|
$screen_link = LJ::create_url(
|
||
|
|
"/talkscreen",
|
||
|
|
args => {
|
||
|
|
mode => "unscreen",
|
||
|
|
journal => $u->{'user'},
|
||
|
|
talkid => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
$screen_img = LJ::img( "btn_unscr", "", { align => 'absmiddle', hspace => 2 } );
|
||
|
|
}
|
||
|
|
|
||
|
|
# FIXME: (David?) We'll have to make talk_multi.bml understand jtalkids in multiple posts
|
||
|
|
#$ret .= " <nobr><input type='checkbox' name='selected_$r->{jtalkid}' id='s$r->{jtalkid}' />";
|
||
|
|
#$ret .= " <label for='s$r->{jtalkid}'>$ML{'label.select'}</label></nobr>";
|
||
|
|
|
||
|
|
my $comment_htmlid = LJ::Talk::comment_htmlid($talkid);
|
||
|
|
|
||
|
|
my $esubject = $log_text->{"$u->{userid}:$r->{nodeid}"}[0] // "";
|
||
|
|
LJ::CleanHTML::clean_subject( \$esubject ) if $esubject ne "";
|
||
|
|
|
||
|
|
my $ditemid_undef = defined $lrow->{ditemid} ? 0 : 1;
|
||
|
|
my $csubject = LJ::ehtml( $comment_text->{ $r->{jtalkid} }[0] );
|
||
|
|
|
||
|
|
if ( !$csubject || $csubject =~ /^Re:\s*$/ ) {
|
||
|
|
$csubject = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
my $comment = $comment_text->{ $r->{jtalkid} }[1];
|
||
|
|
LJ::CleanHTML::clean_comment(
|
||
|
|
\$comment,
|
||
|
|
{
|
||
|
|
preformatted => $r->{props}->{opt_preformatted},
|
||
|
|
editor => $r->{props}->{editor},
|
||
|
|
anon_comment => LJ::Talk::treat_as_anon( $pu, $u ),
|
||
|
|
nocss => 1,
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
my $stylemine = 0;
|
||
|
|
my $replyurl = LJ::Talk::talkargs( $ditemid, "replyto=$talkid", $stylemine );
|
||
|
|
|
||
|
|
push @{ $vars->{comments} }, {
|
||
|
|
isanonymous => $isanonymous, # 1 if posted by anonymous user
|
||
|
|
pu => $pu, # user that posted the comment
|
||
|
|
hr_ago => $hr_ago, # text of time posted
|
||
|
|
state => $state, # Screened, Deleted, or Frozen
|
||
|
|
del_link => $del_link,
|
||
|
|
del_img => $del_img,
|
||
|
|
screen_link => $screen_link,
|
||
|
|
screen_img => $screen_img,
|
||
|
|
freeze_link => $freeze_link,
|
||
|
|
freeze_img => $freeze_img,
|
||
|
|
comment_htmlid => $comment_htmlid,
|
||
|
|
esubject => $esubject,
|
||
|
|
ditemid_undef => $ditemid_undef,
|
||
|
|
ditemid => $ditemid,
|
||
|
|
csubject => $csubject,
|
||
|
|
comment => $comment,
|
||
|
|
talkurl => $talkurl, # direct link to comment
|
||
|
|
replyurl => $replyurl,
|
||
|
|
talkid => $talkid, # comment number
|
||
|
|
tdclass => $tdclass
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$vars->{LJ_cmtinfo} = to_json( \%LJ_cmtinfo );
|
||
|
|
|
||
|
|
return DW::Template->render_template( 'comments/recent.tt', $vars );
|
||
|
|
}
|
||
|
|
|
||
|
|
sub posted_handler {
|
||
|
|
my ( $ok, $rv ) = controller( authas => 1 );
|
||
|
|
return $rv unless $ok;
|
||
|
|
|
||
|
|
my $r = $rv->{r};
|
||
|
|
my $u = $rv->{u};
|
||
|
|
my $remote = $rv->{remote};
|
||
|
|
|
||
|
|
my $vars;
|
||
|
|
$vars->{u} = $u;
|
||
|
|
$vars->{authas_html} = $rv->{authas_html};
|
||
|
|
$vars->{getextra} = ( $u ne $remote ) ? { authas => $u->user } : {};
|
||
|
|
|
||
|
|
my %LJ_cmtinfo = %{ LJ::Comment->info($u) };
|
||
|
|
$LJ_cmtinfo{form_auth} = LJ::form_auth(1);
|
||
|
|
|
||
|
|
my $dbcr = LJ::get_cluster_reader($u);
|
||
|
|
die "Error: can't get DB for user" unless $dbcr;
|
||
|
|
|
||
|
|
$vars = initialize_count( $u, $r, $vars );
|
||
|
|
|
||
|
|
my ( @posted, %talkids );
|
||
|
|
my %need_userid;
|
||
|
|
$need_userid{ $u->{userid} } = 1 if $u->is_community; # Need to load the community for logtext
|
||
|
|
my %logrow; # "jid nodeid" -> $logrow
|
||
|
|
my %need_logids; # hash of "journalid jitemid" => [journalid, jitemid]
|
||
|
|
|
||
|
|
my $now = time();
|
||
|
|
my $sth;
|
||
|
|
|
||
|
|
$vars->{canedit} = $remote->can_edit_comments;
|
||
|
|
|
||
|
|
# Retrieve posted
|
||
|
|
if ( $u->is_individual ) {
|
||
|
|
$sth =
|
||
|
|
$dbcr->prepare( "SELECT posttime, journalid, nodetype, nodeid, jtalkid, publicitem "
|
||
|
|
. "FROM talkleft "
|
||
|
|
. "WHERE userid=? ORDER BY posttime DESC LIMIT $vars->{count}" );
|
||
|
|
$sth->execute( $u->{'userid'} );
|
||
|
|
my %jcount; # jid -> ct
|
||
|
|
while ( my $r = $sth->fetchrow_hashref ) {
|
||
|
|
push @posted, $r;
|
||
|
|
$need_logids{"$r->{journalid} $r->{nodeid}"} = [ $r->{journalid}, $r->{nodeid} ]
|
||
|
|
if $r->{nodetype} eq "L";
|
||
|
|
$need_userid{ $r->{journalid} } = 1;
|
||
|
|
}
|
||
|
|
|
||
|
|
my $us = LJ::load_userids( keys %need_userid );
|
||
|
|
|
||
|
|
# setup the parameter to get_posts_raw
|
||
|
|
my @need_logtext;
|
||
|
|
foreach my $need ( values %need_logids ) {
|
||
|
|
my ( $ownerid, $itemid ) = @$need;
|
||
|
|
my $ju = $us->{$ownerid} or next;
|
||
|
|
push @need_logtext, [ $ju->{clusterid}, $ownerid, $itemid ];
|
||
|
|
}
|
||
|
|
|
||
|
|
my $log_data = LJ::get_posts_raw( { text_only => 1 }, @need_logtext );
|
||
|
|
my $log_text = $log_data->{text};
|
||
|
|
my $root = $u->journal_base;
|
||
|
|
|
||
|
|
# Cycle through each comment to extract necessary data
|
||
|
|
foreach my $r (@posted) {
|
||
|
|
$jcount{ $r->{'journalid'} }++;
|
||
|
|
next unless $r->{'nodetype'} eq "L"; # log2 comment
|
||
|
|
|
||
|
|
my $ju = $us->{ $r->{journalid} };
|
||
|
|
my $lrow = $logrow{"$ju->{userid} $r->{nodeid}"} ||=
|
||
|
|
LJ::get_log2_row( $ju, $r->{'nodeid'} );
|
||
|
|
|
||
|
|
my $hr_ago = LJ::diff_ago_text( $r->{posttime}, $now );
|
||
|
|
|
||
|
|
# if entry exists
|
||
|
|
if ( defined $lrow->{ditemid} ) {
|
||
|
|
my $talkid = ( $r->{'jtalkid'} << 8 ) + $lrow->{'anum'};
|
||
|
|
my $ljcmt = $LJ_cmtinfo{$talkid} = {};
|
||
|
|
$ljcmt->{u} = $u->{user};
|
||
|
|
$ljcmt->{postedin} = $ju ? $ju->{user} : "";
|
||
|
|
|
||
|
|
my $comment = LJ::Comment->new( $ju, dtalkid => $talkid );
|
||
|
|
|
||
|
|
my $logurl = $ju->journal_base . "/$lrow->{ditemid}.html";
|
||
|
|
my $commentanchor = LJ::Talk::comment_anchor($talkid);
|
||
|
|
my $talkurl = "$logurl?thread=$talkid$commentanchor";
|
||
|
|
|
||
|
|
my $subject =
|
||
|
|
$log_text->{"$r->{journalid}:$r->{nodeid}"}[0] || "$lrow->{ditemid}.html";
|
||
|
|
LJ::CleanHTML::clean_subject( \$subject );
|
||
|
|
|
||
|
|
# add a sign if the comment has replies
|
||
|
|
my $hasreplies = $comment->has_nondeleted_children ? "*" : '';
|
||
|
|
|
||
|
|
# delete link, very helpful for when the user does not have access to that entry anymore
|
||
|
|
my $delete = $comment->is_deleted ? '' : LJ::create_url(
|
||
|
|
"/delcomment",
|
||
|
|
args => {
|
||
|
|
journal => $ju->{'user'},
|
||
|
|
id => $talkid
|
||
|
|
}
|
||
|
|
);
|
||
|
|
|
||
|
|
# edit link, if comment can be edited
|
||
|
|
my $editlink =
|
||
|
|
$comment->remote_can_edit ? LJ::Talk::talkargs( $comment->edit_url ) : '';
|
||
|
|
|
||
|
|
push @{ $vars->{comments} }, {
|
||
|
|
ju => $ju, # journal comment was posted in
|
||
|
|
talkurl => $talkurl, # direct link to comment
|
||
|
|
logurl => $logurl, # link to entry holding comment
|
||
|
|
subject => $subject, # subject of entry
|
||
|
|
candelete => $hasreplies, # '*' if comment has replies and cannot be deleted
|
||
|
|
hr_ago => $hr_ago, # text of time posted
|
||
|
|
deletelink => $delete, # link to delete comment (if available, otherwise blank)
|
||
|
|
editlink => $editlink, # link to edit comment (if available, otherwise blank)
|
||
|
|
talkid => $talkid # comment number
|
||
|
|
};
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
# entry has been deleted
|
||
|
|
else {
|
||
|
|
push @{ $vars->{comments} }, {
|
||
|
|
postdeleted => 1, # entry deleted
|
||
|
|
hr_ago => $hr_ago,
|
||
|
|
ju => $ju
|
||
|
|
};
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
$vars->{LJ_cmtinfo} = to_json( \%LJ_cmtinfo );
|
||
|
|
|
||
|
|
return DW::Template->render_template( 'comments/posted.tt', $vars );
|
||
|
|
}
|
||
|
|
|
||
|
|
# Ascertain number of comments to show
|
||
|
|
sub initialize_count {
|
||
|
|
my ( $u, $r, $vars ) = @_;
|
||
|
|
|
||
|
|
my $max = $u->count_recent_comments_display;
|
||
|
|
my $show = $r->get_args->{show} // 25;
|
||
|
|
|
||
|
|
# how many comments to display by default
|
||
|
|
$show = $max if $show > $max;
|
||
|
|
$show = 0 if $show < 1;
|
||
|
|
my $count = $show || ( $max > 25 ? 25 : $max );
|
||
|
|
$show = $max > 25 ? 25 : $max;
|
||
|
|
$vars->{count} = $count;
|
||
|
|
$vars->{show} = $show;
|
||
|
|
$vars->{max} = $max;
|
||
|
|
|
||
|
|
my @values = qw( 10 25 50 100 );
|
||
|
|
push @values, $count
|
||
|
|
unless grep { $count == $_ } @values;
|
||
|
|
push @values, $max
|
||
|
|
unless grep { $max == $_ } @values;
|
||
|
|
|
||
|
|
@values = sort { $a <=> $b } @values;
|
||
|
|
$vars->{values} = \@values;
|
||
|
|
$vars->{sitemax} = $LJ::TOOLS_RECENT_COMMENTS_MAX;
|
||
|
|
|
||
|
|
return $vars;
|
||
|
|
}
|
||
|
|
|
||
|
|
1;
|