diff --git a/Issue.pm b/Bug.pm
similarity index 64%
rename from Issue.pm
rename to Bug.pm
index 3c35a30..ec27808 100644
--- a/Issue.pm
+++ b/Bug.pm
@@ -22,7 +22,7 @@
# TODO: Atom feed?
-package TUWF::Issue;
+package TUWF::Bug;
use TUWF ':html', 'html_escape';
@@ -100,21 +100,21 @@ sub dbSave {
# TODO: pagination / filtering
sub htmlListing {
my($s, $l, $lnk) = @_;
- table class => 'issue_listing';
+ table class => 'bug_listing';
thead; Tr;
- td class => 'issue_col_id', 'Id';
- td class => 'issue_col_type', 'Type';
- td class => 'issue_col_status', 'Status';
- td class => 'issue_col_date', 'Updated';
- td class => 'issue_col_summary','Summary';
+ td class => 'bug_col_id', 'Id';
+ td class => 'bug_col_type', 'Type';
+ td class => 'bug_col_status', 'Status';
+ td class => 'bug_col_date', 'Updated';
+ td class => 'bug_col_summary','Summary';
end; end;
for(@$l) {
- Tr $_->{closed} ? (class => 'issue_closed') : ();
- td class => 'issue_col_id', $_->{issue};
- td class => 'issue_col_type', $_->{type};
- td class => 'issue_col_status', $_->{status};
- td class => 'issue_col_date', $_->{date};
- td class => 'issue_col_summary';
+ Tr $_->{closed} ? (class => 'bug_closed') : ();
+ 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_summary';
a href => $lnk->($_->{issue}), $_->{summary};
end;
end;
@@ -138,16 +138,16 @@ sub _escape_url {
sub htmlItem {
my($s, $d) = @_;
my $last = $d->[$#$d];
- dl class => 'issue_status';
+ dl class => 'bug_status';
dt 'Id'; dd $last->{issue};
dt 'Messages'; dd $#$d+1;
dt 'Type'; dd $last->{type};
dt 'Status'; dd $last->{status};
end;
- div class => 'issue_item';
+ div class => 'bug_item';
my $num = -1;
for my $m (@$d) {
- div class => 'issue_message';
+ div class => 'bug_message';
h1 !++$num ? 'Description' : "Reply $num";
dl;
dt !$num ? 'Created' : 'Added'; dd $m->{date};
@@ -172,49 +172,49 @@ sub htmlItem {
sub htmlForm {
my($s, $l, $url) = @_;
# TODO: anti-spam JS
- form class => 'issue_frm', action => $url, method => 'post';
+ form class => 'bug_frm', action => $url, method => 'post';
fieldset;
- input type => 'hidden', name => 'issue_id', value => $l ? $l->{issue} : 0;
- legend $l ? 'Reply' : 'Report a new issue';
+ input type => 'hidden', name => 'bug_id', value => $l ? $l->{issue} : 0;
+ legend $l ? 'Reply' : 'Report a new bug';
ul;
- li class => 'issue_frm_summary';
- label for => 'issue_summary', 'Summary';
- input type => 'text', name => 'issue_summary', id => 'issue_summary', size => 45, value => $l?$l->{summary}:'';
+ li class => 'bug_frm_summary';
+ label for => 'bug_summary', 'Summary';
+ input type => 'text', name => 'bug_summary', id => 'bug_summary', size => 45, value => $l?$l->{summary}:'';
end;
- li class => 'issue_frm_mail';
- label for => 'issue_email', 'Email';
- input type => 'text', name => 'issue_email', id => 'issue_email', size => 20;
+ li class => 'bug_frm_mail';
+ label for => 'bug_email', 'Email';
+ input type => 'text', name => 'bug_email', id => 'bug_email', size => 20;
lit ' ';
txt 'Optional, only used for notifications.';
end;
if($l) {
- li class => 'issue_frm_admin';
- label for => 'issue_type', 'Admin';
- Select name => 'issue_type';
+ li class => 'bug_frm_admin';
+ label for => 'bug_type', 'Admin';
+ Select name => 'bug_type';
option value => $_, $_ eq $l->{type} ? (selected => 'selected') : (), $_ for @{$s->{types}};
end;
- Select name => 'issue_status';
+ Select name => 'bug_status';
option value => $_, $_ eq $l->{status} ? (selected => 'selected') : (), $_ for @{$s->{statusses}};
end;
- Select name => 'issue_closed';
+ Select name => 'bug_closed';
option value => 0, !$l->{closed} ? (selected => 'selected') : (), 'Open';
option value => 1, $l->{closed} ? (selected => 'selected') : (), 'Closed';
end;
- input type => 'password', name => 'issue_code', id => 'issue_code', size => 10, value => 'code';
+ input type => 'password', name => 'bug_code', id => 'bug_code', size => 10, value => 'code';
end;
} else {
- li class => 'issue_frm_type';
- label for => 'issue_type', 'Type';
- Select name => 'issue_type';
+ li class => 'bug_frm_type';
+ label for => 'bug_type', 'Type';
+ Select name => 'bug_type';
option value => $_, $_ eq $s->{default_type} ? (selected => 'selected') : (), $_ for @{$s->{types}};
end;
end;
}
- li class => 'issue_frm_message';
- textarea name => 'issue_message';end; br;
+ li class => 'bug_frm_message';
+ textarea name => 'bug_message';end; br;
lit 'Please use a pastebin if you want to include large chunks of code or program output.';
end;
- li class => 'issue_frm_submit';
+ li class => 'bug_frm_submit';
input type => 'submit', value => 'Submit';
end;
end 'ul';
@@ -226,60 +226,60 @@ sub htmlForm {
sub handleForm {
my($s, $url) = @_;
my $f = $TUWF::OBJ->formValidate(
- { post => 'issue_id', min => 0 },
- { post => 'issue_summary', maxlength => 200, minlength => 2 },
- { post => 'issue_email', required => 0, regex => qr/^[^@<>]+@[^@.<>]+(?:\.[^@.<>]+)+$/ },
- { post => 'issue_code', required => 0, default => '' },
- { post => 'issue_message', maxlength => 256*1024, minlength => 1 },
+ { post => 'bug_id', min => 0 },
+ { post => 'bug_summary', maxlength => 200, minlength => 2 },
+ { post => 'bug_email', required => 0, regex => qr/^[^@<>]+@[^@.<>]+(?:\.[^@.<>]+)+$/ },
+ { post => 'bug_code', required => 0, default => '' },
+ { post => 'bug_message', maxlength => 256*1024, minlength => 1 },
);
return($f, undef) if $f->{_err};
my $l;
# Reply
- if($f->{issue_id} > 0) {
- $l = $s->dbListing(id => $f->{issue_id})->[0];
- push @{$f->{_err}}, ['issue_id', 'db_check', ''] and return($f, undef) if !$l;
+ if($f->{bug_id} > 0) {
+ $l = $s->dbListing(id => $f->{bug_id})->[0];
+ push @{$f->{_err}}, ['bug_id', 'db_check', ''] and return($f, undef) if !$l;
# Check admin things
- if(grep $_ eq $f->{issue_code}, @{$s->{admins}}) {
+ if(grep $_ eq $f->{bug_code}, @{$s->{admins}}) {
my $fa = $TUWF::OBJ->formValidate(
- { post => 'issue_type', enum => $s->{types} },
- { post => 'issue_status', enum => $s->{statusses} },
- { post => 'issue_closed', enum => [0,1] },
+ { post => 'bug_type', enum => $s->{types} },
+ { post => 'bug_status', enum => $s->{statusses} },
+ { post => 'bug_closed', enum => [0,1] },
);
$f = { %$f, %$fa };
return($f, $l) if $f->{_err};
} else {
- $f->{issue_type} = $l->{type};
- $f->{issue_status} = $l->{status};
- $f->{issue_closed} = $l->{closed};
+ $f->{bug_type} = $l->{type};
+ $f->{bug_status} = $l->{status};
+ $f->{bug_closed} = $l->{closed};
}
- # New issue
+ # New bug
} else {
- $f->{issue_status} = $s->{default_status};
- $f->{issue_closed} = 0;
- my $fa = $TUWF::OBJ->formValidate({ post => 'issue_type', enum => $s->{types} });
+ $f->{bug_status} = $s->{default_status};
+ $f->{bug_closed} = 0;
+ my $fa = $TUWF::OBJ->formValidate({ post => 'bug_type', enum => $s->{types} });
$f = { %$f, %$fa };
return($f, $l) if $f->{_err};
}
# No errors? Save!
- my $id = $s->dbSave(map $f->{"issue_$_"}, qw|id closed summary email type status message|);
+ my $id = $s->dbSave(map $f->{"bug_$_"}, qw|id closed summary email type status message|);
# For replies, send out notification emails
if($l) {
my $mails = $s->dbEmails($id);
my $u = $url->($id);
- for(grep $_ ne $f->{issue_email}, @$mails) {
+ for(grep $_ ne $f->{bug_email}, @$mails) {
$TUWF::OBJ->mail(
"Hello!\n\n".
- "A new reply has been posted to an issue you have previously shown\n".
+ "A new reply has been posted to an bug you have previously shown\n".
"an interest in. You can view the reply at the following URL:\n".
" $u\n\n".
"If you do not wish to receive any more notifications for this (and\n".
- "perhaps other) issues, please reply to this email stating your intent.",
- Subject => "Reply to $f->{issue_summary}",
+ "perhaps other) bugs, please reply to this email stating your intent.",
+ Subject => "Reply to $f->{bug_summary}",
To => "$_",
);
}
diff --git a/dat/dump b/dat/dump
index d8f4dab..5b57b5a 100644
--- a/dat/dump
+++ b/dat/dump
@@ -59,5 +59,5 @@ it. L
December 2011. Playing around with the Go programming language, I wrote another
transfer log parser and statistics generator for ncdc.
-L (L).
+L<0.3|http://p.blicky.net/h25z8>
+(L<0.2|http://p.blicky.net/6yx2d>, L<0.1|http://p.blicky.net/ab4lm>).
diff --git a/dat/ncdc-faq b/dat/ncdc-faq
index 0d91612..88cd026 100644
--- a/dat/ncdc-faq
+++ b/dat/ncdc-faq
@@ -157,5 +157,5 @@ myself, though. I just run ncdc directly on my router. :-)
Nothing like that is included in the release yet, but there is a simple Perl
script available: L, and a short
-Go program: L.
+Go program: L.
diff --git a/index.cgi b/index.cgi
index 229430f..7857b1d 100755
--- a/index.cgi
+++ b/index.cgi
@@ -12,8 +12,9 @@ BEGIN { ($ROOT = abs_path $0) =~ s{index\.cgi$}{}; }
my @changes = (
- [ '2012-03-24', '/ncdu/issue', 'Moved issue tracker from sourceforge to this site' ],
- [ '2012-03-17', '/ncdc/issue', 'Wrote a small issue tracker for ncdc' ],
+ [ '2012-03-30', '/dump', 'Updated ncdc-share-report for Go 1' ],
+ [ '2012-03-24', '/ncdu/bug', 'Moved ncdu bug tracker from sourceforge to this site' ],
+ [ '2012-03-17', '/ncdc/bug', 'Wrote a small bug tracker for ncdc' ],
[ '2012-03-14', '/ncdc', 'ncdc 1.9 released.' ],
[ '2012-02-15', '/doc/commvis', 'Added an article on my new communication system.' ],
[ '2012-02-13', '/ncdc', 'ncdc 1.8 released.' ],
@@ -76,16 +77,16 @@ TUWF::register(
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{feed\.atom} => \&atom,
- qr{(ncdc|ncdu)/issue} => \&issue_list,
- qr{(ncdc|ncdu)/issue/post} => \&issue_post,
- qr{(ncdc|ncdu)/issue/new} => \&issue_new,
- qr{(ncdc|ncdu)/issue/([1-9][0-9]*)} => \&issue_item,
+ qr{(ncdc|ncdu)/bug} => \&bug_list,
+ qr{(ncdc|ncdu)/bug/post} => \&bug_post,
+ qr{(ncdc|ncdu)/bug/new} => \&bug_new,
+ qr{(ncdc|ncdu)/bug/([1-9][0-9]*)} => \&bug_item,
);
TUWF::set(
logfile => '/www/err.log',
error_404_handler => \¬found,
- mail_from => 'Yorhel\'s issue tracker ',
+ mail_from => 'Yorhel\'s Bug Tracker ',
# this is a fairly static site, allow some aggressive caching
pre_request_handler => sub { $_[0]->resHeader('Cache-Control', 's-max-age=86400, max-age=3600'); 1; },
);
@@ -189,6 +190,7 @@ sub notfound {
[ 'dump/grenamr', '/dump/grenamr' ],
);
return $s->resRedirect("/$u", 'perm') if $u =~ s/\/$//;
+ return $s->resRedirect("/$1/bug$2", 'perm') if $u =~ /^(ncd[uc])\/issue(.*)$/;
$s->resStatus(404);
$s->htmlHeader(title => '404', page => '404');
txt 'Sorry, there is no page at this URI. Try one of the links from the menu to find the page you are looking for.';
@@ -198,69 +200,69 @@ sub notfound {
-# Issue handling
+# Bug tracker
-sub _issue_init {
- require "$ROOT/Issue.pm";
+sub _bug_init {
+ require "$ROOT/Bug.pm";
my($s, $p) = @_;
$s->resHeader('Cache-Control', 'no-cache');
$s->_load_module('TUWF::DB');
$s->{_TUWF}{db_login} = [ undef, undef, undef ];
$s->dbInit;
- return TUWF::Issue->new(prefix => $p.'_', admins => [ $ENV{ISSUE_CODE} ]);
+ return TUWF::Bug->new(prefix => $p.'_', admins => [ $ENV{ISSUE_CODE} ]);
}
-sub issue_list {
+sub bug_list {
my($s, $p) = @_;
- my $is = _issue_init(@_);
- $s->htmlHeader(title => "\u$p Issue tracker", page => $p, sec => 'issue');
- br; a href => "/$p/issue/new", 'Report new issue'; br; br;
- $is->htmlListing((scalar $is->dbListing()), sub { "/$p/issue/".shift });
- br; a href => "/$p/issue/new", 'Report new issue'; br; br;
+ my $is = _bug_init(@_);
+ $s->htmlHeader(title => "\u$p Bug tracker", page => $p, sec => 'bug');
+ br; a href => "/$p/bug/new", 'Report new bug'; br; br;
+ $is->htmlListing((scalar $is->dbListing()), sub { "/$p/bug/".shift });
+ br; a href => "/$p/bug/new", 'Report new bug'; br; br;
$s->htmlFooter;
}
-sub issue_new {
+sub bug_new {
my($s, $p) = @_;
- my $is = _issue_init(@_);
- $s->htmlHeader(title => "\u$p: Report new issue", page => $p, sec => 'issue');
- br; a href => "/$p/issue", 'Back to the issue index'; br; br;
- $is->htmlForm(undef, "/$p/issue/post");
+ my $is = _bug_init(@_);
+ $s->htmlHeader(title => "\u$p: Report new bug", page => $p, sec => 'bug');
+ br; a href => "/$p/bug", 'Back to the bug index'; br; br;
+ $is->htmlForm(undef, "/$p/bug/post");
$s->htmlFooter;
}
-sub issue_post {
+sub bug_post {
my($s, $p) = @_;
return $s->resNotFound if $s->reqMethod() ne 'POST';
- my $is = _issue_init($s, $p);
- my($f, $l) = $is->handleForm(sub { "http://dev.yorhel.nl/$p/issue/".shift });
+ my $is = _bug_init($s, $p);
+ my($f, $l) = $is->handleForm(sub { "http://dev.yorhel.nl/$p/bug/".shift });
if($f->{_err}) {
- $s->htmlHeader(title => 'Error creating message', page => $p, sec => 'issue');
+ $s->htmlHeader(title => 'Error creating message', page => $p, sec => 'bug');
p 'There was an error in the form. Please use the \'back\' button of your
browser to go back to the form (hopefully) without losing your message.
- There was an error in the following fields: '.join(', ', map {(my$f=$_->[0])=~s/issue_// ;"\u$f"} @{$f->{_err}}).'.';
+ There was an error in the following fields: '.join(', ', map {(my$f=$_->[0])=~s/bug_// ;"\u$f"} @{$f->{_err}}).'.';
return $s->htmlFooter;
}
- $s->resRedirect("/$p/issue/$l->{issue}", 'post');
+ $s->resRedirect("/$p/bug/$l->{bug}", 'post');
}
-sub issue_item {
+sub bug_item {
my($s, $p, $i) = @_;
- my $is = _issue_init($s, $p);
+ my $is = _bug_init($s, $p);
my $item = $is->dbItem($i);
return $s->resNotFound if !@$item;
my $last = $item->[$#$item];
- $s->htmlHeader(title => "\u$p: $last->{summary}", page => $p, sec => 'issue');
- br; a href => "/$p/issue", 'Back to the issue index'; br; br;
+ $s->htmlHeader(title => "\u$p: $last->{summary}", page => $p, sec => 'bug');
+ br; a href => "/$p/bug", 'Back to the bug index'; br; br;
$is->htmlItem($item);
- $is->htmlForm($last, "/$p/issue/post") if !$last->{closed};
- br; a href => "/$p/issue", 'Back to the issue index'; br; br;
+ $is->htmlForm($last, "/$p/bug/post") if !$last->{closed};
+ br; a href => "/$p/bug", 'Back to the bug index'; br; br;
$s->htmlFooter;
}
@@ -404,7 +406,7 @@ sub htmlMenu {
$m->('/ncdu/man', 'Manual', $o{sec} eq 'man');
$m->('/ncdu/changes', 'Changelog', $o{sec} eq 'changes');
$m->('/ncdu/scr', 'Screenshots', $o{sec} eq 'scr');
- $m->('/ncdu/issue', 'Issue tracker', $o{sec} eq 'issue');
+ $m->('/ncdu/bug', 'Bug tracker', $o{sec} eq 'bug');
});
$m->('/ncdc', 'Ncdc', $o{page} eq 'ncdc', sub {
$m->('/ncdc', 'Info', !$o{sec});
@@ -412,7 +414,7 @@ sub htmlMenu {
$m->('/ncdc/man', 'Manual', $o{sec} eq 'man');
$m->('/ncdc/changes', 'Changelog', $o{sec} eq 'changes');
$m->('/ncdc/scr', 'Screenshots', $o{sec} eq 'scr');
- $m->('/ncdc/issue', 'Issue tracker', $o{sec} eq 'issue');
+ $m->('/ncdc/bug', 'Bug tracker', $o{sec} eq 'bug');
});
$m->('/tuwf', 'Tuwf', $o{page} eq 'tuwf', sub {
$m->('/tuwf', 'Info', !$o{sec});
diff --git a/style.css b/style.css
index 0d34403..c0e8252 100644
--- a/style.css
+++ b/style.css
@@ -65,23 +65,23 @@ textarea:focus, input:focus { background: #fff }
table { border-collapse: collapse }
table td { padding: 0 2px }
table thead td { font-weight: bold }
-.issue_listing tbody tr:nth-child(odd) { background-color: #f4f4f4 }
-.issue_listing { width: 95% }
-.issue_col_id, .issue_col_type, .issue_col_status, .issue_col_date { white-space: nowrap }
-.issue_closed td { text-decoration: line-through }
-.issue_status { display: block; height: 20px }
-.issue_status dt { float: left; font-weight: bold }
-.issue_status dd { float: left; }
-.issue_item h1 { margin-top: 30px }
-.issue_item dt { clear: left; float: left; font-weight: bold; width: 60px }
-.issue_item dd { float: left; padding-right: 20px }
-.issue_item p { clear: left; padding-top: 5px }
-.issue_frm fieldset { border: 0; margin-top: 40px }
-.issue_frm legend { font-size: 19px; color: #000; }
-.issue_frm li { list-style-type: none; margin-left: 10px; clear: left; padding-top: 5px }
-.issue_frm label { display: block; width: 80px; float: left }
-.issue_frm input, .issue_frm select { float: left }
-.issue_frm textarea { width: 100%; height: 200px }
-.issue_frm_submit input { float: right; width: 200px }
+.bug_listing tbody tr:nth-child(odd) { background-color: #f4f4f4 }
+.bug_listing { width: 95% }
+.bug_col_id, .bug_col_type, .bug_col_status, .bug_col_date { white-space: nowrap }
+.bug_closed td { text-decoration: line-through }
+.bug_status { display: block; height: 20px }
+.bug_status dt { float: left; font-weight: bold }
+.bug_status dd { float: left; }
+.bug_item h1 { margin-top: 30px }
+.bug_item dt { clear: left; float: left; font-weight: bold; width: 60px }
+.bug_item dd { float: left; padding-right: 20px }
+.bug_item p { clear: left; padding-top: 5px }
+.bug_frm fieldset { border: 0; margin-top: 40px }
+.bug_frm legend { font-size: 19px; color: #000; }
+.bug_frm li { list-style-type: none; margin-left: 10px; clear: left; padding-top: 5px }
+.bug_frm label { display: block; width: 80px; float: left }
+.bug_frm input, .bug_frm select { float: left }
+.bug_frm textarea { width: 100%; height: 200px }
+.bug_frm_submit input { float: right; width: 200px }
-.issue_status dt::after, .issue_item dt::after, .issue_frm label::after { content: ":" }
+.bug_status dt::after, .bug_item dt::after, .bug_frm label::after { content: ":" }