Should have committed earlier

Lots of changes:
- Article about IPC
- New TUWF release
- New ncdu release
- Atom feeds for the bug tracker
- Bug tracker switch to sqlite
This commit is contained in:
Yorhel 2016-06-18 15:18:24 +02:00
parent 3b837d8564
commit 7cf772d968
33 changed files with 978 additions and 159 deletions

104
Bug.pm
View file

@ -2,34 +2,25 @@
=head1 SQL Schema
CREATE TABLE $p (
id SERIAL PRIMARY KEY,
issue integer NOT NULL,
date timestamptz NOT NULL DEFAULT NOW(),
summary varchar(200) NOT NULL,
type varchar NOT NULL DEFAULT '',
status varchar NOT NULL DEFAULT '',
closed boolean NOT NULL DEFAULT false,
email varchar NOT NULL DEFAULT '',
message varchar NOT NULL DEFAULT '',
admin boolean NOT NULL DEFAULT false,
name varchar(200) NOT NULL DEFAULT ''
id integer PRIMARY KEY AUTOINCREMENT NOT NULL,
issue integer NOT NULL,
date integer NOT NULL,
name text DEFAULT '' NOT NULL,
email text DEFAULT '' NOT NULL,
admin integer DEFAULT 0 NOT NULL,
closed integer DEFAULT 0 NOT NULL,
type text DEFAULT '' NOT NULL,
status text DEFAULT '' NOT NULL,
summary text NOT NULL,
message text DEFAULT '' NOT NULL
);
=head2 Update queries
ALTER TABLE ${p}messages RENAME TO $p;
DROP TABLE ${p}issues;
ALTER TABLE ${p}messages ADD COLUMN admin boolean NOT NULL DEFAULT false;
ALTER TABLE ${p}messages ADD COLUMN name varchar(200) NOT NULL DEFAULT '';
=cut
# TODO: Atom feed?
package TUWF::Bug;
use TUWF ':html', 'html_escape';
use TUWF ':xml', ':html', 'html_escape';
use POSIX 'strftime';
sub new {
my $class = shift;
@ -58,7 +49,7 @@ sub dbListing {
my %where = (
'NOT EXISTS(SELECT 1 FROM !s im WHERE im.id > m.id AND im.issue = m.issue)' => $self->{table},
$o{id} ? ('issue = ?' => $o{id}) : (),
$o{closed} != 2 ? ('!s closed' => !$o{closed} ? 'NOT' : '') : (),
$o{closed} != 2 ? ('closed = ?' => $o{closed}?1:0) : (),
);
my $order = sprintf {
@ -66,7 +57,7 @@ sub dbListing {
}->{$o{sort}||'date'}, $o{reverse} ? 'DESC' : 'ASC';
my($r, $np) = $TUWF::OBJ->dbPage(\%o, q{
SELECT issue, summary, to_char(date, 'YYYY-MM-DD') AS date, type, status, closed
SELECT issue, summary, date, type, status, closed
FROM !s m
!W
ORDER BY !s}, $self->{table}, \%where, $order
@ -78,7 +69,7 @@ sub dbListing {
sub dbItem {
my($self, $id) = @_;
return $TUWF::OBJ->dbAll(q{
SELECT issue, summary, to_char(date, 'YYYY-MM-DD HH24:MI:SS (tz)') AS date, type, status, closed, name, admin, message
SELECT issue, summary, date, type, status, closed, name, admin, message
FROM !s
WHERE issue = ?
ORDER BY id}, $self->{table}, $id
@ -86,6 +77,16 @@ sub dbItem {
}
sub dbRecent {
my $self = shift;
return $TUWF::OBJ->dbAll(q{
SELECT issue, summary, date, name
FROM !s
ORDER BY id DESC LIMIT 10}, $self->{table}
);
}
sub dbEmails {
my($self, $id) = @_;
return [ map $_->{email}, @{$TUWF::OBJ->dbAll(q|SELECT DISTINCT email FROM !s WHERE issue = ? AND email <> ''|, $self->{table}, $id)} ];
@ -96,14 +97,13 @@ sub dbSave {
my($self, $id, $closed, @a) = @_;
# TODO: Issue ID allocation may currently cause two bug reports created at
# the same time to get the same id. It'd be better to use a PostgreSQL
# sequence...
# the same time to get the same id.
my $issue = $id ? '?' : '(SELECT COALESCE(MAX(issue)+1, 1) FROM !s)';
return $TUWF::OBJ->dbRow(
"INSERT INTO !s (issue, closed, summary, name, email, type, status, message, admin) VALUES ($issue, ?, !l) RETURNING issue",
$self->{table}, $id || $self->{table}, $closed?1:0, \@a
)->{issue}
$TUWF::OBJ->dbExec(
"INSERT INTO !s (issue, date, closed, summary, name, email, type, status, message, admin) VALUES ($issue, ?, ?, !l)",
$self->{table}, $id || $self->{table}, time(), $closed?1:0, \@a);
return $TUWF::OBJ->dbRow('SELECT MAX(issue) AS issue FROM !s', $self->{table})->{issue};
}
@ -127,7 +127,7 @@ sub htmlListing {
td class => 'bug_col_id', $_->{issue};
td class => 'bug_col_type', $_->{type};
td class => 'bug_col_status', $_->{status};
td class => 'bug_col_date', $_->{date};
td class => 'bug_col_date', strftime '%Y-%m-%d', gmtime $_->{date};
td class => 'bug_col_summary';
a href => $lnk->($_->{issue}), $_->{summary};
end;
@ -166,7 +166,8 @@ sub htmlItem {
dl;
dt !$num ? 'Created' : 'Added';
dd;
txt "$m->{date} by ";
txt strftime '%Y-%m-%d %T GMT', gmtime $m->{date};
txt ' by ';
txt $m->{name}||'Anonymous' if !$m->{admin};
b $m->{name}||'Admin' if $m->{admin};
end;
@ -251,15 +252,16 @@ sub htmlForm {
sub handleForm {
my($s, $url) = @_;
my $f = $TUWF::OBJ->formValidate(
{ post => 'bug_id', min => 0 },
{ post => 'bug_id', template => 'uint' },
{ post => 'bug_summary', maxlength => 200, minlength => 2 },
{ post => 'bug_name', required => 0, default => '', maxlength => 200 },
{ post => 'bug_email', required => 0, regex => qr/^[^@<>]+@[^@.<>]+(?:\.[^@.<>]+)+$/ },
{ post => 'bug_email', required => 0, template => 'email' },
{ post => 'bug_code', required => 0, default => '' },
{ post => 'bug_message', maxlength => 256*1024, minlength => 1 },
);
return($f, undef) if $f->{_err};
return({ _err => [['bug_summary']], %$f}, undef) if $f->{bug_summary} =~ qr{http://}; # SPAM
return({ _err => [['bug_summary']], %$f}, undef) if $f->{bug_message} =~ qr{(?:<a href=|\[url=|\[link=)}i; # SPAM
$f->{bug_code} = '' if $f->{bug_code} eq 'code';
my $admin = grep($_ eq $f->{bug_code}, @{$s->{admins}}) ? 1 : 0;
@ -326,4 +328,36 @@ sub handleForm {
}
sub atomFeed {
my($s, $lnk) = @_;
my $r = $s->dbRecent();
my $t = $r->[0]{date}||1463296545;
$TUWF::OBJ->resHeader('Last-Modified' => strftime '%a, %d %b %Y %H:%M:%S GMT', gmtime $t);
$TUWF::OBJ->resHeader('Content-Type' => 'application/atom+xml');
xml;
tag feed => xmlns => 'http://www.w3.org/2005/Atom', 'xml:lang' => 'en', 'xml:base' => 'https://dev.yorhel.nl/';
tag title => "\u$s->{table} Recent Comments";
tag updated => strftime('%Y-%m-%dT%H:%M:%SZ', gmtime $t);
tag id => $lnk->('feed.atom');
tag link => rel => 'self', type => 'application/atom+xml', href => $lnk->('feed.atom'), undef;
tag link => rel => 'alternate', type => 'text/html', href => $lnk->(''), undef;
for(@$r) {
my $d = strftime('%Y-%m-%dT%H:%M:%SZ', gmtime $_->{date});
tag 'entry';
tag id => $lnk->($_->{issue})."#$d";
tag title => $_->{summary};
tag updated => $d;
tag published => $d;
tag 'author';
tag name => $_->{name};
end;
tag link => rel => 'alternate', type => 'text/html', href => $lnk->($_->{issue}), undef;
end 'entry';
}
end 'feed';
}
1;