Use only a single table for each bug tracker + add tracker for Globster

This commit is contained in:
Yorhel 2013-04-01 12:53:27 +02:00
parent 76bb10482a
commit ac3c5676d3
5 changed files with 43 additions and 47 deletions

59
Bug.pm
View file

@ -1,12 +1,7 @@
=head1 SQL Schema =head1 SQL Schema
CREATE TABLE ${p}issues ( CREATE TABLE $p (
issue SERIAL PRIMARY KEY,
latest integer NOT NULL
);
CREATE TABLE ${p}messages (
id SERIAL PRIMARY KEY, id SERIAL PRIMARY KEY,
issue integer NOT NULL, issue integer NOT NULL,
date timestamptz NOT NULL DEFAULT NOW(), date timestamptz NOT NULL DEFAULT NOW(),
@ -22,6 +17,9 @@
=head2 Update queries =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 admin boolean NOT NULL DEFAULT false;
ALTER TABLE ${p}messages ADD COLUMN name varchar(200) NOT NULL DEFAULT ''; ALTER TABLE ${p}messages ADD COLUMN name varchar(200) NOT NULL DEFAULT '';
@ -36,7 +34,7 @@ use TUWF ':html', 'html_escape';
sub new { sub new {
my $class = shift; my $class = shift;
return bless { return bless {
prefix => 'issue_', table => 'issues',
types => [qw|bug feature docs other|], types => [qw|bug feature docs other|],
default_type => 'other', default_type => 'other',
statusses => [qw|new accepted duplicate confirmed fixed wontfix worksforme|], statusses => [qw|new accepted duplicate confirmed fixed wontfix worksforme|],
@ -58,20 +56,20 @@ sub dbListing {
$o{reverse} = 1 if !$o{sort}; $o{reverse} = 1 if !$o{sort};
my %where = ( my %where = (
$o{id} ? ('i.issue = ?' => $o{id}) : (), 'NOT EXISTS(SELECT 1 FROM !s im WHERE im.id > m.id AND im.issue = m.issue)' => $self->{table},
$o{closed} != 2 ? ('!s m.closed' => !$o{closed} ? 'NOT' : '') : (), $o{id} ? ('issue = ?' => $o{id}) : (),
$o{closed} != 2 ? ('!s closed' => !$o{closed} ? 'NOT' : '') : (),
); );
my $order = sprintf { my $order = sprintf {
date => 'm.id %s', date => 'id %s',
}->{$o{sort}||'date'}, $o{reverse} ? 'DESC' : 'ASC'; }->{$o{sort}||'date'}, $o{reverse} ? 'DESC' : 'ASC';
my($r, $np) = $TUWF::OBJ->dbPage(\%o, q{ my($r, $np) = $TUWF::OBJ->dbPage(\%o, q{
SELECT i.issue, m.summary, to_char(m.date, 'YYYY-MM-DD') AS date, m.type, m.status, m.closed SELECT issue, summary, to_char(date, 'YYYY-MM-DD') AS date, type, status, closed
FROM !sissues i FROM !s m
JOIN !smessages m ON m.id = i.latest
!W !W
ORDER BY !s}, $self->{prefix}, $self->{prefix}, \%where, $order ORDER BY !s}, $self->{table}, \%where, $order
); );
return wantarray ? ($r, $np) : $r; return wantarray ? ($r, $np) : $r;
} }
@ -80,29 +78,32 @@ sub dbListing {
sub dbItem { sub dbItem {
my($self, $id) = @_; my($self, $id) = @_;
return $TUWF::OBJ->dbAll(q{ return $TUWF::OBJ->dbAll(q{
SELECT m.issue, m.summary, to_char(m.date, 'YYYY-MM-DD HH24:MI:SS (tz)') AS date, m.type, m.status, m.closed, m.name, m.admin, m.message SELECT issue, summary, to_char(date, 'YYYY-MM-DD HH24:MI:SS (tz)') AS date, type, status, closed, name, admin, message
FROM !smessages m FROM !s
WHERE m.issue = ? WHERE issue = ?
ORDER BY m.id}, $self->{prefix}, $id ORDER BY id}, $self->{table}, $id
); );
} }
sub dbEmails { sub dbEmails {
my($self, $id) = @_; my($self, $id) = @_;
return [ map $_->{email}, @{$TUWF::OBJ->dbAll(q|SELECT DISTINCT m.email FROM !smessages m WHERE m.issue = ? AND m.email <> ''|, $self->{prefix}, $id)} ]; return [ map $_->{email}, @{$TUWF::OBJ->dbAll(q|SELECT DISTINCT email FROM !s WHERE issue = ? AND email <> ''|, $self->{table}, $id)} ];
} }
sub dbSave { sub dbSave {
my($self, $id, $closed, @a) = @_; my($self, $id, $closed, @a) = @_;
$id = $TUWF::OBJ->dbRow('INSERT INTO !sissues (latest) VALUES (0) RETURNING issue', $self->{prefix})->{issue} if !$id;
my $latest = $TUWF::OBJ->dbRow( # TODO: Issue ID allocation may currently cause two bug reports created at
'INSERT INTO !smessages (issue, closed, summary, name, email, type, status, message, admin) VALUES (?, ?, !l) RETURNING id', # the same time to get the same id. It'd be better to use a PostgreSQL
$self->{prefix}, $id, $closed?1:0, \@a # sequence...
)->{id}; my $issue = $id ? '?' : '(SELECT COALESCE(MAX(issue)+1, 1) FROM !s)';
$TUWF::OBJ->dbExec('UPDATE !sissues SET latest = ? WHERE issue = ?', $self->{prefix}, $latest, $id);
return $id; 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}
} }
@ -232,7 +233,7 @@ sub htmlForm {
} }
li class => 'bug_frm_message'; li class => 'bug_frm_message';
textarea name => 'bug_message';end; br; textarea name => 'bug_message';end; br;
lit 'Please use a <a href="http://p.blicky.net/">pastebin</a> if you want to include large chunks of code or program output.'; lit 'Please use a <a href="http://p.blicky.net/">pastebin</a> if you want to include chunks of code or program output.';
end; end;
li class => 'bug_frm_submit'; li class => 'bug_frm_submit';
input type => 'submit', value => 'Submit'; input type => 'submit', value => 'Submit';
@ -302,12 +303,12 @@ sub handleForm {
$TUWF::OBJ->mail( $TUWF::OBJ->mail(
"Hello!\n\n". "Hello!\n\n".
"A new reply has been posted to a bug you have previously shown\n". "A new reply has been posted to a bug you have previously shown\n".
"an interest in. You can find the reply at the following URL:\n". "an interest in. You can find the reply at the following URL:\n\n".
" $base$u\n\n". " $base$u\n\n".
"If you do not wish to receive any more notifications for this (and\n". "If you do not wish to receive any more notifications for this (and\n".
"perhaps other) bugs, please reply to this email stating your intent.", "perhaps other) bugs, please reply to this email stating your intent.",
Subject => "Reply to $f->{bug_summary}", Subject => "Reply to $f->{bug_summary}",
To => "$_", To => $_,
); );
} }
} }

13
dat/doc
View file

@ -1,15 +1,8 @@
=pod =pod
When programming stuff, I often come across a situation where I am not I don't often write stuff. Certainly not enough to warrant a blog. But
happy with the documentation or articles available online, and feel the urge to sometimes I do feel the need to write down my thoughts. The results of those
do something about this situation. Most of the time I resist this urge because rare occasions are published on this page.
I otherwise won't get any programming done, but sometimes this urge is just too
hard to resist.
I don't really have a blog - at least not one that I take seriously - so I'll
just use this site to publish my articles. Since I've just started writing
these, this page is still quite empty. I'll add more as soon as my urge to
write an article surprasses my urge to get some programming done again.
=over =over

View file

@ -38,11 +38,11 @@ compiling and/or installing it, I also offer statically linked binaries:
=over =over
=item * L<Linux, 64-bit|http://dev.yorhel.nl/download/ncdc-linux-x86_64-1.15.tar.gz> =item * L<Linux, 64-bit|http://dev.yorhel.nl/download/ncdc-linux-x86_64-1.16.1.tar.gz>
=item * L<Linux, 32-bit|http://dev.yorhel.nl/download/ncdc-linux-i486-1.15.tar.gz> =item * L<Linux, 32-bit|http://dev.yorhel.nl/download/ncdc-linux-i486-1.16.1.tar.gz>
=item * L<Linux, ARM|http://dev.yorhel.nl/download/ncdc-linux-arm-1.15.tar.gz> =item * L<Linux, ARM|http://dev.yorhel.nl/download/ncdc-linux-arm-1.16.1.tar.gz>
=back =back

View file

@ -99,10 +99,10 @@ TUWF::register(
qr{dump/grenamr} => sub { podpage(shift, 'dump-grenamr', 'dump', 'grenamr', 'GTK+ Mass File Renamer') }, qr{dump/grenamr} => sub { podpage(shift, 'dump-grenamr', 'dump', 'grenamr', 'GTK+ Mass File Renamer') },
qr{dump/nccolour} => sub { podpage(shift, 'dump-nccolour', 'dump', 'nccolour', 'Colours in NCurses') }, qr{dump/nccolour} => sub { podpage(shift, 'dump-nccolour', 'dump', 'nccolour', 'Colours in NCurses') },
qr{feed\.atom} => \&atom, qr{feed\.atom} => \&atom,
qr{(ncdc|ncdu)/bug} => \&bug_list, qr{(ncdc|ncdu|globster)/bug} => \&bug_list,
qr{(ncdc|ncdu)/bug/post} => \&bug_post, qr{(ncdc|ncdu|globster)/bug/post} => \&bug_post,
qr{(ncdc|ncdu)/bug/new} => \&bug_new, qr{(ncdc|ncdu|globster)/bug/new} => \&bug_new,
qr{(ncdc|ncdu)/bug/([1-9][0-9]*)} => \&bug_item, qr{(ncdc|ncdu|globster)/bug/([1-9][0-9]*)} => \&bug_item,
); );
TUWF::set( TUWF::set(
@ -232,7 +232,7 @@ sub _bug_init {
$s->_load_module('TUWF::DB'); $s->_load_module('TUWF::DB');
$s->{_TUWF}{db_login} = [ undef, undef, undef ]; $s->{_TUWF}{db_login} = [ undef, undef, undef ];
$s->dbInit; $s->dbInit;
return TUWF::Bug->new(prefix => $p.'_', admins => [ $ENV{ISSUE_CODE} ]); return TUWF::Bug->new(table => $p, admins => [ $ENV{ISSUE_CODE} ]);
} }
@ -494,6 +494,7 @@ sub htmlMenu {
$m->('/globster/launch', 'globster-launch', $o{sec} eq 'launch', undef, 1); $m->('/globster/launch', 'globster-launch', $o{sec} eq 'launch', undef, 1);
}); });
$m->('/globster/api', 'API Doc', $o{sec} eq 'api'); $m->('/globster/api', 'API Doc', $o{sec} eq 'api');
$m->('/globster/bug', 'Bug tracker', $o{sec} eq 'bug');
} elsif($o{page} eq 'tuwf') { } elsif($o{page} eq 'tuwf') {
$m->('/tuwf', 'Info', !$o{sec}); $m->('/tuwf', 'Info', !$o{sec});
$m->('/tuwf/man', 'Manual', $o{sec} eq 'man', sub { $m->('/tuwf/man', 'Manual', $o{sec} eq 'man', sub {

View file

@ -3,4 +3,5 @@ Disallow: /download
Disallow: /dat Disallow: /dat
Disallow: /ncdc/bug Disallow: /ncdc/bug
Disallow: /ncdu/bug Disallow: /ncdu/bug
Disallow: /globster/bug