Moved css to separate file + Wrote minimal issue tracker for ncdc

I designed the issue tracker to be a separate module for use in TUWF
websites, and perhaps even as standalone. But for now it's just a small
file in this repository.
This commit is contained in:
Yorhel 2012-03-17 17:43:20 +01:00
parent ec64b3fa9d
commit 605b0643d3
3 changed files with 447 additions and 69 deletions

147
index.cgi
View file

@ -12,6 +12,7 @@ BEGIN { ($ROOT = abs_path $0) =~ s{index\.cgi$}{}; }
my @changes = (
[ '2012-03-17', '/ncdc/issue', 'Wrote a small issue 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.' ],
@ -74,11 +75,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)/issue} => \&issue_list,
qr{(ncdc)/issue/post} => \&issue_post,
qr{(ncdc)/issue/new} => \&issue_new,
qr{(ncdc)/issue/([1-9][0-9]*)} => \&issue_item,
);
TUWF::set(
logfile => '/www/err.log',
error_404_handler => \&notfound,
mail_from => 'Yorhel\'s issue tracker <projects@yorhel.nl>',
# 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; },
);
@ -190,6 +196,76 @@ sub notfound {
# Issue handling
sub _issue_init {
require "$ROOT/Issue.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} ]);
}
sub issue_list {
my($s, $p) = @_;
my $is = _issue_init(@_);
$s->htmlHeader(title => 'Ncdc 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;
$s->htmlFooter;
}
sub issue_new {
my($s, $p) = @_;
my $is = _issue_init(@_);
$s->htmlHeader(title => 'Ncdc: 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");
$s->htmlFooter;
}
sub issue_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 });
if($f->{_err}) {
$s->htmlHeader(title => 'Error creating message', page => $p, sec => 'issue');
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}}).'.';
return $s->htmlFooter;
}
$s->resRedirect("/$p/issue/$l->{issue}", 'post');
}
sub issue_item {
my($s, $p, $i) = @_;
my $is = _issue_init($s, $p);
my $item = $is->dbItem($i);
return $s->resNotFound if !@$item;
my $last = $item->[$#$item];
$s->htmlHeader(title => 'Ncdc: '.$last->{summary}, page => $p, sec => 'issue');
br; a href => "/$p/issue", 'Back to the issue 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;
$s->htmlFooter;
}
package TUWF::Object;
use TUWF ':html';
@ -266,9 +342,7 @@ sub htmlHeader {
my %o = (page => '', sec => '', sec2 => '', @_ );
html;
head;
style type => 'text/css';
$s->printCSS;
end;
Link rel => 'stylesheet', href => '/style.css', type => 'text/css', media => 'all';
Link rel => 'alternate', type => 'application/atom+xml', href => '/feed.atom', title => 'Site updates';
title $o{title};
end;
@ -337,6 +411,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->('/tuwf', 'Tuwf', $o{page} eq 'tuwf', sub {
$m->('/tuwf', 'Info', !$o{sec});
@ -361,69 +436,3 @@ sub htmlMenu {
end;
}
sub printCSS {
# font-face code from http://fonts.googleapis.com/css?family=Buenard:700,400
lit <<' E;';
@font-face {
font-family: 'Buenard';
font-style: normal;
font-weight: bold;
src: local('Buenard Bold'), local('Buenard-Bold'), url('http://themes.googleusercontent.com/static/fonts/buenard/v2/8T0adwz_RAtKrxbccQmEFC3USBnSvpkopQaUR-2r7iU.ttf') format('truetype');
}
@font-face {
font-family: 'Buenard';
font-style: normal;
font-weight: 400;
src: local('Buenard'), local('Buenard-Regular'), url('http://themes.googleusercontent.com/static/fonts/buenard/v2/UUYHasP8umGDjV-yeZf27Q.ttf') format('truetype');
}
html,body { background: #ccc; text-align: center; height: 100% }
* { margin: 0; padding: 0; font: 15px 'Buenard',serif; color: #222 }
#body { text-align: left; width: 800px; margin: 0 auto; background: #fff; border-left: 1px solid #aaa; border-right: 1px solid #aaa; min-height: 100% }
#uglyhack { height: 30px }
#main, #left { float: left; border-top: 0px dashed #aaa, margin-top: 50px }
#left { width: 130px; border-right: 1px dashed #aaa; padding: 20px 10px; margin-bottom: 30px }
#main { width: 609px; padding: 12px 20px 30px 20px }
#footer { clear: left; width: 150px; margin: 0 0 0 324px; border-top: 1px dashed #aaa; height: 20px; text-align: center }
#footer p { position: relative; top: -10px; padding: 0; background: #fff; display: inline; color: #aaa }
#left h1 { font-weight: bold; text-align: center; font-size: 15px }
#left li { margin: 20px 0 0 10px; list-style-type: none }
#left li a { text-decoration: none; display: block; width: 120px; border-bottom: 1px solid #fff }
#left li a:hover { border-bottom: 1px dashed #aaa }
#left li li { margin-top: 10px }
#left li li a { width: 110px }
#left li li li { margin-top: 2px }
#left li li li a { width: 100px }
#left .menusel { color: #03a }
#left .notes { margin-top: 50px; text-align: center }
#left .notes, #left .notes a { font-size: 12px; text-decoration: none }
#left .notes a:hover { text-decoration: underline }
img.right { float: right; margin: 0 0 5px 10px }
.indexgroup { margin: 30px 10px 0px 20px }
.indexgroup li { list-style-type: none; margin-left: 0px }
.indexgroup li li { margin-left: 20px }
.indexgroup + .dummyTopAnchor + p { margin-top: 20px }
a.external:after { content: url(/img/external.gif) }
b { font-weight: bold }
h1.title { margin-top: 0; font-size: 25px }
h1 { margin-top: 50px; }
h2 { margin-top: 25px; }
h3 { margin-top: 0; margin-left: 10px }
h1, h1 a { font-size: 19px; color: #000; margin-bottom: 5px; text-decoration: none }
h2, h2 a { font-size: 16px; color: #000; margin-bottom: 1px; text-decoration: none }
h3, h3 a { font-size: 15px; color: #000; margin-bottom: 1px; text-decoration: none }
li { margin-left: 35px; margin-right: 15px; text-align: justify }
p { margin: 3px 15px 13px 15px; text-align: justify }
p + ul, p + ol { margin-top: -10px }
pre { padding-left: 0 }
pre, code, pre b { font: 11px monospace; }
pre b { font-weight: bold }
pre { background: #f5f5f5; border: 1px dotted #aaa; margin: 5px 10px; display: block; padding: 5px 5px 5px 0; }
dd { margin-left: 15px }
dt a { color: #333 }
dt { margin-left: 10px }
i { font-style: normal } /* TODO */
.sig { vertical-align: super }
.sig, .sig a { font-size: 12px; color: #333; text-decoration: none }
E;
}