mourningdove/cgi-bin/DW/Controller/Comments.pm

423 lines
15 KiB
Perl
Raw Permalink Normal View History

2026-05-24 01:03:05 +00:00
#!/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;