1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
|
package VNWeb::Discussions::Lib;
use VNWeb::Prelude;
use Exporter 'import';
our @EXPORT = qw/threadlist_ boardsearch_ boardtypes_/;
# Returns a WHERE condition to filter threads that the current user is allowed to see.
sub sql_visible_threads {
sql_and
auth->permBoardmod ? () : ('NOT t.hidden'),
sql('NOT t.private OR EXISTS(SELECT 1 FROM threads_boards WHERE tid = t.id AND type = \'u\' AND iid =', \auth->uid, ')');
}
# Generate a thread list table, options:
# where => SQL for the WHERE clause ('t' is available as alias for 'threads').
# boards => SQL for the WHERE clause of the boards ('tb' as alias for 'threads_boards').
# results => Number of threads to display.
# page => Current page number.
# paginate => sub {} reference that generates a url for paginate_(); pagination is disabled when not set.
# sort => SQL (default: tl.date DESC)
#
# Returns 1 if something was displayed, 0 if no threads matched the where clause.
sub threadlist_ {
my %opt = @_;
my $where = sql_and sql_visible_threads(), $opt{where}||();
my $count = $opt{paginate} && tuwf->dbVali('SELECT count(*) FROM threads t WHERE', $where);
return 0 if $opt{paginate} && !$count;
my $lst = tuwf->dbPagei(\%opt, q{
SELECT t.id, t.title, t.count, t.locked, t.private, t.hidden, t.poll_question IS NOT NULL AS haspoll
, }, sql_user('tfu', 'firstpost_'), ',', sql_totime('tf.date'), q{ as firstpost_date
, }, sql_user('tlu', 'lastpost_'), ',', sql_totime('tl.date'), q{ as lastpost_date
FROM threads t
JOIN threads_posts tf ON tf.tid = t.id AND tf.num = 1
JOIN threads_posts tl ON tl.tid = t.id AND tl.num = t.count
JOIN users tfu ON tfu.id = tf.uid
JOIN users tlu ON tlu.id = tl.uid
WHERE }, $where, q{
ORDER BY}, $opt{sort}||'tl.date DESC'
);
return 0 if !@$lst;
enrich boards => id => tid => sub { sql q{
SELECT tb.tid, tb.type, tb.iid, COALESCE(u.username, v.title, p.name) AS title, COALESCE(u.username, v.original, p.original) AS original
FROM threads_boards tb
LEFT JOIN vn v ON tb.type = 'v' AND v.id = tb.iid
LEFT JOIN producers p ON tb.type = 'p' AND p.id = tb.iid
LEFT JOIN users u ON tb.type = 'u' AND u.id = tb.iid
WHERE }, sql_and(sql('tb.tid IN', $_[0]), $opt{boards}||()), q{
ORDER BY tb.type, tb.iid
}}, $lst;
paginate_ $opt{paginate}, $opt{page}, [ $count, $opt{results} ], 't' if $opt{paginate};
div_ class => 'mainbox browse discussions', sub {
table_ class => 'stripe', sub {
thead_ sub { tr_ sub {
td_ class => 'tc1', sub { txt_ 'Topic'; debug_ $lst };
td_ class => 'tc2', 'Replies';
td_ class => 'tc3', 'Starter';
td_ class => 'tc4', 'Last post';
}};
tr_ sub {
my $l = $_;
td_ class => 'tc1', sub {
a_ mkclass(locked => $l->{locked}), href => "/t$l->{id}", sub {
span_ class => 'pollflag', '[poll]' if $l->{haspoll};
span_ class => 'pollflag', '[private]' if $l->{private};
span_ class => 'pollflag', '[hidden]' if $l->{hidden};
txt_ shorten $l->{title}, 50;
};
b_ class => 'boards', sub {
join_ ', ', sub {
a_ href => "/t/$_->{type}".($_->{iid}||''),
title => $_->{original}||$BOARD_TYPE{$_->{type}}{txt},
shorten $_->{title}||$BOARD_TYPE{$_->{type}}{txt}, 30;
}, $l->{boards}->@[0 .. min 4, $#{$l->{boards}}];
txt_ ', ...' if $l->{boards}->@* > 4;
};
};
td_ class => 'tc2', $l->{count}-1;
td_ class => 'tc3', sub { user_ $l, 'firstpost_' };
td_ class => 'tc4', sub {
user_ $l, 'lastpost_';
txt_ ' @ ';
a_ href => "/t$l->{id}.$l->{count}", fmtdate $l->{lastpost_date}, 'full';
};
} for @$lst;
}
};
paginate_ $opt{paginate}, $opt{page}, [ $count, $opt{results} ], 'b' if $opt{paginate};
1;
}
sub boardsearch_ {
my($type) = @_;
form_ action => '/t/search', sub {
fieldset_ class => 'search', sub {
input_ type => 'text', name => 'bq', id => 'bq', class => 'text';
input_ type => 'hidden', name => 'b', value => $type if $type && $type ne 'all';
input_ type => 'submit', class => 'submit', value => 'Search!';
}
}
}
sub boardtypes_ {
my($type) = @_;
p_ class => 'browseopts', sub {
a_ href => $_->[0] eq 'index' ? '/t' : '/t/'.$_->[0], mkclass(optselected => $type && $type eq $_->[0]), $_->[1] for (
[ index => 'Index' ],
[ all => 'All boards' ],
map [ $_, $BOARD_TYPE{$_}{txt} ], keys %BOARD_TYPE
);
};
}
1;
|