summaryrefslogtreecommitdiff
path: root/lib/VNWeb/Discussions/Thread.pm
diff options
context:
space:
mode:
Diffstat (limited to 'lib/VNWeb/Discussions/Thread.pm')
-rw-r--r--lib/VNWeb/Discussions/Thread.pm130
1 files changed, 71 insertions, 59 deletions
diff --git a/lib/VNWeb/Discussions/Thread.pm b/lib/VNWeb/Discussions/Thread.pm
index ed357b5d..b3820dd7 100644
--- a/lib/VNWeb/Discussions/Thread.pm
+++ b/lib/VNWeb/Discussions/Thread.pm
@@ -10,7 +10,7 @@ my $POLL_OUT = form_compile any => {
num_votes => { uint => 1 },
can_vote => { anybool => 1 },
preview => { anybool => 1 },
- tid => { id => 1 },
+ tid => { vndbid => 't' },
options => { aoh => {
id => { id => 1 },
option => {},
@@ -20,7 +20,7 @@ my $POLL_OUT = form_compile any => {
};
my $POLL_IN = form_compile any => {
- tid => { id => 1 },
+ tid => { vndbid => 't' },
options => { type => 'array', values => { id => 1 } },
};
@@ -32,45 +32,47 @@ elm_api DiscussionsPoll => $POLL_OUT, $POLL_IN, sub {
return tuwf->resNotFound if !$t->{poll_question};
die 'Too many options' if $data->{options}->@* > $t->{poll_max_options};
- validate_dbid sql('SELECT id FROM threads_poll_options WHERE tid =', \$data->{tid}, 'AND id IN'), $data->{options}->@*;
+ my %opt = map +($_->{id},1), tuwf->dbAlli('SELECT id FROM threads_poll_options WHERE tid =', \$data->{tid})->@*;
+ die 'Invalid option' if grep !$opt{$_}, $data->{options}->@*;
- tuwf->dbExeci('DELETE FROM threads_poll_votes WHERE tid =', \$data->{tid}, 'AND uid =', \auth->uid);
- tuwf->dbExeci('INSERT INTO threads_poll_votes', { tid => $data->{tid}, uid => auth->uid, optid => $_ }) for $data->{options}->@*;
+ tuwf->dbExeci('DELETE FROM threads_poll_votes WHERE optid IN', [ keys %opt ], 'AND uid =', \auth->uid);
+ tuwf->dbExeci('INSERT INTO threads_poll_votes', { uid => auth->uid, optid => $_ }) for $data->{options}->@*;
elm_Success
};
-my $REPLY = {
- tid => { id => 1 },
- old => { _when => 'out', anybool => 1 },
- msg => { _when => 'in', maxlength => 32768 }
+my $REPLY = form_compile any => {
+ tid => { vndbid => 't' },
+ old => { anybool => 1 },
+ msg => { maxlength => 32768 }
};
-my $REPLY_IN = form_compile in => $REPLY;
-my $REPLY_OUT = form_compile out => $REPLY;
-
-elm_api DiscussionsReply => $REPLY_OUT, $REPLY_IN, sub {
+js_api DiscussionReply => $REPLY, sub {
my($data) = @_;
- my $t = tuwf->dbRowi('SELECT id, locked, count FROM threads t WHERE id =', \$data->{tid}, 'AND', sql_visible_threads());
+ my $t = tuwf->dbRowi('SELECT id, locked FROM threads t WHERE id =', \$data->{tid}, 'AND', sql_visible_threads());
return tuwf->resNotFound if !$t->{id};
- return elm_Unauth if !can_edit t => $t;
+ return tuwf->resDenied if !can_edit t => $t;
- my $num = $t->{count}+1;
+ my $num = sql '(SELECT MAX(num)+1 FROM threads_posts WHERE tid =', \$data->{tid}, ')';
my $msg = bb_subst_links $data->{msg};
- tuwf->dbExeci('INSERT INTO threads_posts', { tid => $t->{id}, num => $num, uid => auth->uid, msg => $msg });
- tuwf->dbExeci('UPDATE threads SET count =', \$num, 'WHERE id =', \$t->{id});
- elm_Redirect post_url $t->{id}, $num, 'last';
+ $num = tuwf->dbVali('INSERT INTO threads_posts', { tid => $t->{id}, num => $num, uid => auth->uid, msg => $msg }, 'RETURNING num');
+ +{ _redir => "/$t->{id}.$num#last" };
};
sub metabox_ {
- my($t) = @_;
- div_ class => 'mainbox', sub {
- h1_ $t->{title};
+ my($t, $posts) = @_;
+ article_ sub {
+ h1_ sub { lit_ bb_format $t->{title}, idonly => 1 };
+ # UGLY hack: private threads from Multi (u1) are sometimes (ab)used for system notifications, treat that case differently.
+ if ($t->{private} && $posts->[0]{user_id} && $posts->[0]{user_id} eq 'u1') {
+ h2_ 'System notification';
+ return;
+ }
h2_ 'Hidden' if $t->{hidden};
h2_ 'Private' if $t->{private};
h2_ 'Locked' if $t->{locked};
@@ -80,12 +82,12 @@ sub metabox_ {
a_ href => "/t/$_->{btype}", $BOARD_TYPE{$_->{btype}}{txt};
if($_->{iid}) {
txt_ ' > ';
- a_ style => 'font-weight: bold', href => "/t/$_->{btype}$_->{iid}", "$_->{btype}$_->{iid}";
+ a_ style => 'font-weight: bold', href => "/t/$_->{iid}", $_->{iid};
txt_ ':';
if($_->{title}) {
- a_ href => "/$_->{btype}$_->{iid}", title => $_->{original}||$_->{title}, $_->{title};
+ a_ href => "/$_->{iid}", tattr $_;
} else {
- b_ '[deleted]';
+ strong_ '[deleted]';
}
}
} for $t->{boards}->@*;
@@ -94,17 +96,18 @@ sub metabox_ {
}
+# Also used by Reviews::Page for review comments.
sub posts_ {
my($t, $posts, $page) = @_;
- my sub url { "/t$t->{id}".($_?"/$_":'') }
+ my sub url { "/$t->{id}".($_?"/$_":'') }
paginate_ \&url, $page, [ $t->{count}, 25 ], 't';
- div_ class => 'mainbox thread', sub {
+ article_ class => 'thread', id => 'threadstart', sub {
table_ class => 'stripe', sub {
- tr_ mkclass(deleted => $_->{hidden}), id => $_->{num}, sub {
- td_ class => 'tc1', $t->{count} == $_->{num} ? (id => 'last') : (), sub {
- a_ href => "/t$t->{id}.$_->{num}", "#$_->{num}";
- if(!$_->{hidden} || auth->permBoard) {
+ tr_ mkclass(deleted => defined $_->{hidden}), id => "p$_->{num}", sub {
+ td_ class => 'tc1', $_ == $posts->[$#$posts] ? (id => 'last') : (), sub {
+ a_ href => "/$t->{id}.$_->{num}", "#$_->{num}";
+ if(!defined $_->{hidden} || auth->permBoard) {
txt_ ' by ';
user_ $_;
br_;
@@ -112,16 +115,23 @@ sub posts_ {
}
};
td_ class => 'tc2', sub {
- i_ class => 'edit', sub {
+ small_ class => 'edit', sub {
txt_ '< ';
- a_ href => "/t$t->{id}.$_->{num}/edit", 'edit';
+ if(can_edit t => $_) {
+ a_ href => "/$t->{id}.$_->{num}/edit", 'edit';
+ txt_ ' - ';
+ }
+ a_ href => "/report/$t->{id}.$_->{num}", 'report';
txt_ ' >';
- } if can_edit t => $_;
- if($_->{hidden}) {
- i_ class => 'deleted', 'Post deleted.';
+ } if !defined $_->{hidden} || can_edit t => $_;
+ if(defined $_->{hidden}) {
+ small_ sub {
+ txt_ 'Post deleted';
+ lit_ length $_->{hidden} ? ': '.bb_format $_->{hidden}, inline => 1 : '.';
+ };
} else {
- lit_ bb2html $_->{msg};
- i_ class => 'lastmod', 'Last modified on '.fmtdate($_->{edited}, 'full') if $_->{edited};
+ lit_ bb_format $_->{msg};
+ small_ class => 'lastmod', 'Last modified on '.fmtdate($_->{edited}, 'full') if $_->{edited};
}
};
} for @$posts;
@@ -135,9 +145,9 @@ sub reply_ {
my($t, $posts, $page) = @_;
return if $t->{count} > $page*25;
if(can_edit t => $t) {
- elm_ 'Discussions.Reply' => $REPLY_OUT, { tid => $t->{id}, old => $posts->[$#$posts]{date} < time-182*24*3600 };
+ div_ widget(DiscussionReply => $REPLY, { tid => $t->{id}, old => $posts->[$#$posts]{date} < time-182*24*3600 }), '';
} else {
- div_ class => 'mainbox', sub {
+ article_ sub {
h1_ 'Reply';
p_ class => 'center',
!auth ? 'You must be logged in to reply to this thread.' :
@@ -147,12 +157,13 @@ sub reply_ {
}
-TUWF::get qr{/$RE{tid}(?:/$RE{num})?}, sub {
- my($id, $page) = (tuwf->capture('id'), tuwf->capture('num')||1);
+TUWF::get qr{/$RE{tid}(?:(?<sep>[\./])$RE{num})?}, sub {
+ my($id, $sep, $num) = (tuwf->capture('id'), tuwf->capture('sep')||'', tuwf->capture('num'));
my $t = tuwf->dbRowi(
- 'SELECT id, title, count, hidden, locked, private
+ 'SELECT id, title, hidden, locked, private
, poll_question, poll_max_options
+ , (SELECT COUNT(*) FROM threads_posts WHERE tid = id) AS count
FROM threads t
WHERE', sql_visible_threads(), 'AND id =', \$id
);
@@ -160,17 +171,21 @@ TUWF::get qr{/$RE{tid}(?:/$RE{num})?}, sub {
enrich_boards '', $t;
+ my $page = $sep eq '/' ? $num||1 : $sep ne '.' ? 1
+ : ceil((tuwf->dbVali('SELECT COUNT(*) FROM threads_posts WHERE num <=', \$num, 'AND tid =', \$id)||9999)/25);
+ $num = 0 if $sep ne '.';
+
my $posts = tuwf->dbPagei({ results => 25, page => $page },
'SELECT tp.tid as id, tp.num, tp.hidden, tp.msg',
',', sql_user(),
',', sql_totime('tp.date'), ' as date',
',', sql_totime('tp.edited'), ' as edited
FROM threads_posts tp
- JOIN users u ON tp.uid = u.id
+ LEFT JOIN users u ON tp.uid = u.id
WHERE tp.tid =', \$id, '
ORDER BY tp.num'
);
- return tuwf->resNotFound if !@$posts;
+ return tuwf->resNotFound if !@$posts || ($num && !grep $_->{num} == $num, @$posts);
my $poll_options = $t->{poll_question} && tuwf->dbAlli(
'SELECT tpo.id, tpo.option, count(u.id) as votes, tpm.optid IS NOT NULL as my
@@ -179,20 +194,23 @@ TUWF::get qr{/$RE{tid}(?:/$RE{num})?}, sub {
LEFT JOIN users u ON tpv.uid = u.id AND NOT u.ign_votes
LEFT JOIN threads_poll_votes tpm ON tpm.optid = tpo.id AND tpm.uid =', \auth->uid, '
WHERE tpo.tid =', \$id, '
- GROUP BY tpo.id, tpo.option, tpm.optid'
+ GROUP BY tpo.id, tpo.option, tpm.optid
+ ORDER BY tpo.id'
);
- # Mark a notification for this thread as read, if there is one.
- tuwf->dbExeci(
- 'UPDATE notifications SET read = NOW() WHERE uid =', \auth->uid, 'AND ltype = \'t\' AND iid = ', \$id, 'AND read IS NULL'
- ) if auth && $t->{count} <= $page*25;
+ auth->notiRead($id, [ map $_->{num}, $posts->@* ]) if @$posts;
- framework_ title => $t->{title}, sub {
- metabox_ $t;
+ framework_ title => $t->{title}, dbobj => $t, $num ? (js => 1, pagevars => {sethash=>"p$num"}) : (), sub {
+ metabox_ $t, $posts;
elm_ 'Discussions.Poll' => $POLL_OUT, {
question => $t->{poll_question},
max_options => $t->{poll_max_options},
- num_votes => tuwf->dbVali('SELECT COUNT(DISTINCT tpv.uid) FROM threads_poll_votes tpv JOIN users u ON tpv.uid = u.id WHERE NOT u.ign_votes AND tid =', \$id),
+ num_votes => tuwf->dbVali(
+ 'SELECT COUNT(DISTINCT tpv.uid)
+ FROM threads_poll_votes tpv
+ JOIN threads_poll_options tpo ON tpo.id = tpv.optid
+ JOIN users u ON tpv.uid = u.id
+ WHERE NOT u.ign_votes AND tpo.tid =', \$id),
preview => !!tuwf->reqGet('pollview'), # Old non-Elm way to preview poll results
can_vote => !!auth,
tid => $id,
@@ -203,10 +221,4 @@ TUWF::get qr{/$RE{tid}(?:/$RE{num})?}, sub {
}
};
-
-TUWF::get qr{/$RE{postid}}, sub {
- my($id, $num) = (tuwf->capture('id'), tuwf->capture('num'));
- tuwf->resRedirect(post_url($id, $num, $num), 'perm')
-};
-
1;