Merge branch 'master' into gruntmaster
authorMarius Gavrilescu <marius@ieval.ro>
Sun, 23 Feb 2014 10:16:15 +0000 (12:16 +0200)
committerMarius Gavrilescu <marius@ieval.ro>
Sun, 23 Feb 2014 10:16:15 +0000 (12:16 +0200)
27 files changed:
MANIFEST
Makefile.PL
app.psgi
lib/Gruntmaster/Page/Base.pm
lib/Gruntmaster/Page/CSS.pm
lib/Gruntmaster/Page/Ct.pm [deleted file]
lib/Gruntmaster/Page/Ct/Entry.pm [deleted file]
lib/Gruntmaster/Page/Generic.pm [new file with mode: 0644]
lib/Gruntmaster/Page/JS.pm
lib/Gruntmaster/Page/Log.pm
lib/Gruntmaster/Page/Log/Entry.pm [deleted file]
lib/Gruntmaster/Page/Passwd.pm
lib/Gruntmaster/Page/Pb.pm [deleted file]
lib/Gruntmaster/Page/Pb/Entry.pm
lib/Gruntmaster/Page/Register.pm
lib/Gruntmaster/Page/Src.pm
lib/Gruntmaster/Page/St.pm
lib/Gruntmaster/Page/Submit.pm
lib/Gruntmaster/Page/Us.pm [deleted file]
lib/Gruntmaster/Page/Us/Entry.pm [deleted file]
lib/Plack/App/Gruntmaster.pm
t/mech.t [new file with mode: 0644]
tmpl/ct.en
tmpl/ct_entry.en
tmpl/log_entry.en
tmpl/pb.en
tmpl/us.en

index 80ce6d43105082ba0ad14e0ac9ad43731cf6a8e6..61687ff1f14b0491a9dcfdc353402331d919bb04 100644 (file)
--- a/MANIFEST
+++ b/MANIFEST
@@ -1,17 +1,51 @@
+a/account.en
+a/account.en.title
+a/index.en
+a/index.en.title
+app.psgi
 Changes
-gruntmaster-genallpages
-gruntmaster-genpage
-lib/Gruntmaster/Page/Common.pm
-lib/Gruntmaster/Page/Ct/Entry.pm
-lib/Gruntmaster/Page/Ct.pm
-lib/Gruntmaster/Page/Index.pm
-lib/Gruntmaster/Page/Log/Entry.pm
+css/custom.css
+css/orig/cerulean.css
+css/orig/cosmo.css
+css/orig/cyborg.css
+css/orig/slate.css
+css/themes/cerulean.css
+css/themes/cosmo.css
+css/themes/cyborg.css
+css/themes/slate.css
+js/00-zepto.js
+js/10-bootstrap-dropdown.js
+js/90-custom.js
+js/90-form.js
+lib/Gruntmaster/Page/Base.pm
+lib/Gruntmaster/Page/CSS.pm
+lib/Gruntmaster/Page/Generic.pm
+lib/Gruntmaster/Page/JS.pm
 lib/Gruntmaster/Page/Log.pm
+lib/Gruntmaster/Page/Passwd.pm
 lib/Gruntmaster/Page/Pb/Entry.pm
-lib/Gruntmaster/Page/Pb.pm
-lib/Gruntmaster/Page.pm
+lib/Gruntmaster/Page/Register.pm
+lib/Gruntmaster/Page/Src.pm
+lib/Gruntmaster/Page/St.pm
 lib/Gruntmaster/Page/Submit.pm
+lib/Plack/App/Gruntmaster.pm
+log.conf
 Makefile.PL
 MANIFEST
 README
+run
+static/gm.css
 t/Gruntmaster-Page.t
+t/mech.t
+tmpl/ct.en
+tmpl/ct_entry.en
+tmpl/footer.en
+tmpl/header.en
+tmpl/log.en
+tmpl/log_entry.en
+tmpl/pb.en
+tmpl/pb_entry.en
+tmpl/st.en
+tmpl/us.en
+tmpl/us_entry.en
+
index dfb22917dcc8f05004e6cde7d7d0e52a9ae4d09e..0c47a00ee5bbbdc2a55b05f9d392fada435a5f2d 100644 (file)
@@ -2,25 +2,43 @@ use 5.014000;
 use ExtUtils::MakeMaker;
 
 WriteMakefile(
-  NAME              => 'Gruntmaster::Page',
-  VERSION_FROM      => 'lib/Gruntmaster/Page.pm',
-  ABSTRACT_FROM     => 'lib/Gruntmaster/Page.pm',
-  AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
-  MIN_PERL_VERSION  => '5.14.0',
-  LICENSE           => 'perl',
-  SIGN              => 1,
-  PREREQ_PM         => {
-       qw/Fcntl 0
-          File::Basename 0
-          IO::File 0
-          POSIX 0
+       NAME              => 'Gruntmaster::Page',
+       VERSION_FROM      => 'lib/Plack/App/Gruntmaster.pm',
+       ABSTRACT_FROM     => 'lib/Plack/App/Gruntmaster.pm',
+       AUTHOR            => 'Marius Gavrilescu <marius@ieval.ro>',
+       MIN_PERL_VERSION  => '5.14.0',
+       LICENSE           => 'perl',
+       SIGN              => 1,
+       BUILD_REQUIRES    => {
+               qw/Test::More                 0
+                  Test::WWW::Mechanize::PSGI 0/,
+       },
+       PREREQ_PM         => {
+               qw/Carp        0
+                  Digest::SHA 0
+                  List::Util  0
+                  POSIX       0
+                  constant    0
+                  feature     0
+                  parent      0
+                  strict      0
+                  warnings    0
 
-          File::Slurp 0
-          HTML::Template::Compiled 0
-          IO::Compress::Gzip 0
-          YAML::Any 0/,
-  },
-  META_MERGE        => {
-       dynamic_config => 0,
-  }
-);
+                  Apache2::Authen::Passphrase 0
+                  Apache2::AuthzCaps          0
+                  CSS::Minifier::XS           0
+                  File::Slurp                 0
+                  Gruntmaster::Data           0
+                  HTML::Template::Compiled    0
+                  HTTP::Negotiate             0
+                  JavaScript::Minifier::XS    0
+                  JSON                        0
+                  Log::Log4perl               0
+                  LWP::UserAgent              0
+                  Plack::Builder              0
+                  Plack::Request              0/,
+       },
+       META_MERGE        => {
+               dynamic_config => 0,
+       }
+)
index 62a6f790815f47cbac9fa032b6fce550314c392e..f9753856a0ad7d0b60396bbc62b97413638de074 100644 (file)
--- a/app.psgi
+++ b/app.psgi
@@ -30,10 +30,13 @@ sub some_auth_required {
 
 sub admin_required {
        local $_ = $_[0];
-       return 1 if m,^/pb/$word, && problem_private $1;
-       return 1 if m,^/log/(?:job|src)/$word, && job_private $1;
-       return 1 if m,^/ct/$word/(?:pb|log), && time < contest_start $1;
-       return 1 if m,^/ct/$word/log/src, && time < contest_end $1;
+       return problem_owner $1 if m,^/pb/$word, && problem_private $1;
+       return job_owner $1  if m,^/log/(?:job|src)/$word, && job_private $1;
+       return contest_owner $1 if m,^/ct/$word/(?:pb|log), && time < contest_start $1;
+       if (m,^/ct/$word/log/(?:job|src)/$word, && time < contest_end $1){
+               local $Gruntmaster::Data::contest = $1;
+               return job_owner $2;
+       }
        0
 }
 
@@ -43,7 +46,7 @@ sub require_admin {
                local *__ANON__ = "require_admin_middleware";
                my $env = $_[0];
                my $r = Plack::Request->new($env);
-               $env->{'gruntmaster.reqadmin'} = 1 if admin_required $r->path;
+               $env->{'gruntmaster.reqadmin'} = admin_required $r->path;
                $app->($env)
        }
 }
@@ -66,7 +69,7 @@ sub authenticate {
        };
        $authen_cache{$cache_key} = time;
 
-       return if $env->{'gruntmaster.reqadmin'} && !hascaps $user, 'gmadm';
+       return if $env->{'gruntmaster.reqadmin'} && $env->{'gruntmaster.reqadmin'} ne $user && !hascaps $user, 'gmadm';
        1
 }
 
index 9e2d03034cc5c8550499301beb3a67d6825199e5..84d74510638108fd11117d166353bb883270dda0 100644 (file)
@@ -3,6 +3,7 @@ package Gruntmaster::Page::Base;
 use 5.014000;
 use strict;
 use warnings;
+our $VERSION = '0.001';
 
 use File::Slurp qw/read_file/;
 use HTML::Template::Compiled;
@@ -34,18 +35,27 @@ use POSIX ();
 use Gruntmaster::Data ();
 use List::Util ();
 use LWP::UserAgent;
+use Plack::Request ();
+use feature ();
 
 my $ua = LWP::UserAgent->new;
 my %templates;
 
-sub import {
-       my $caller = caller;
-       my ($self, $name, $title) = @_;
+use Carp qw/cluck/;
+
+sub import_to {
+       my ($self, $caller, $name, $title) = @_;
 
+       strict->import;
+       feature->import(':5.14');
+       warnings->import;
+       File::Slurp->export_to_level(1, $caller, qw/read_file/);
        Gruntmaster::Data->export_to_level(1, $caller);
        List::Util->export_to_level(1, $caller, qw/sum/);
 
        no strict 'refs';
+       *{"${caller}::ISA"} = [__PACKAGE__];
+       *{"${caller}::VERSION"} = $VERSION;
        *{"${caller}::strftime"} = \&POSIX::strftime;
        *{"${caller}::debug"} = sub {
                local $Log::Log4perl::caller_depth = $Log::Log4perl::caller_depth + 1;
@@ -65,12 +75,18 @@ sub import {
        }
 }
 
+sub import {
+       return unless $_[0] eq __PACKAGE__;
+       splice @_, 1, 0, scalar caller;
+       goto &import_to
+}
+
 ##################################################
 
 sub generate{
        my ($self, $lang, @args) = @_;
 
-       my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$self}{$lang}, default_escape => 'HTML',);
+       my $htc = HTML::Template::Compiled->new(scalarref => \$templates{$self}{$lang}, default_escape => 'HTML', use_perl => 1);
        $self->_generate($htc, $lang, @args);
        my $out = $htc->output;
        utf8::downgrade($out);
@@ -80,11 +96,12 @@ sub generate{
 
 sub _generate {}
 
-sub vary {}
+sub vary { '' }
 
 sub max_age { 60 }
 
 sub variants {
+       return [] unless exists $templates{$_[0]};
        [ map { [ $_, 1, 'text/html', undef, undef, $_, undef ]} keys $templates{$_[0]} ]
 }
 
index 2553ab6e5c0833f9371850f83a39d59031b5f65c..912e948a03600febf1f189a3dc3fe9126d2c389d 100644 (file)
@@ -1,13 +1,6 @@
 package Gruntmaster::Page::CSS;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-use File::Slurp qw/read_file/;
 use CSS::Minifier::XS qw/minify/;
 
 sub generate{
@@ -19,6 +12,4 @@ sub generate{
        [200, ['Content-Type' => 'text/css', 'Cache-Control' => 'public, max-age=604800', 'X-Forever' => 1], [minify $css] ]
 }
 
-sub variants{ [[css => 1, 'text/css', undef, undef, undef, undef]] }
-
 1
diff --git a/lib/Gruntmaster/Page/Ct.pm b/lib/Gruntmaster/Page/Ct.pm
deleted file mode 100644 (file)
index a21bf77..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-package Gruntmaster::Page::Ct;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base ct => 'Contests';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env) = @_;
-       debug $env => "language is '$lang'";
-
-       my (@running, @pending, @finished);
-       for (sort {contest_start $a <=> contest_start $b}contests) {
-               my $ct = { id => $_,
-                                  name => contest_name,
-                                  start => strftime ('%c', localtime contest_start),
-                                  end => strftime ('%c', localtime contest_end),
-                                  owner => contest_owner };
-
-               my $time = time;
-               push @pending, $ct if time < contest_start;
-               push @running, $ct if time >= contest_start && time < contest_end;
-               push @finished, $ct if time > contest_end;
-       }
-
-       $htc->param(running => \@running) if @running;
-       $htc->param(pending => \@pending) if @pending;
-       $htc->param(finished => \@finished) if @finished;
-}
-
-1
diff --git a/lib/Gruntmaster/Page/Ct/Entry.pm b/lib/Gruntmaster/Page/Ct/Entry.pm
deleted file mode 100644 (file)
index acc076e..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package Gruntmaster::Page::Ct::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base ct_entry => '<tmpl_var name>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env, $id) = @_;
-       debug $env => "language is '$lang' and id is '$id'";
-
-       $htc->param(id => $id);
-       $htc->param(name => contest_name $id);
-       $htc->param(start => strftime '%c', localtime contest_start $id);
-       $htc->param(end => strftime '%c', localtime contest_end $id);
-       $htc->param(started => time >= contest_start $id);
-}
-
-1
diff --git a/lib/Gruntmaster/Page/Generic.pm b/lib/Gruntmaster/Page/Generic.pm
new file mode 100644 (file)
index 0000000..95d1cd8
--- /dev/null
@@ -0,0 +1,127 @@
+package Gruntmaster::Page::Generic;
+
+use 5.014000;
+use strict;
+use warnings;
+our $VERSION = '0.001';
+
+use Gruntmaster::Data;
+use Gruntmaster::Page::Base;
+use JSON qw/encode_json decode_json/;
+
+sub hgetall {
+       my $hash = shift;
+       my $cp = $Gruntmaster::Data::contest ? "contest.$Gruntmaster::Data::contest." : '';
+       map { { id => $_, HGETALL "$cp$hash.$_" } } SMEMBERS "$cp$hash"
+}
+
+sub putsym {
+       my ($key, $value) = @_;
+       no strict 'refs';
+       *{"$key"} = $value;
+}
+
+sub makepkg {
+       my ($pkg, $id, $title) = @_;
+       my $fn = $pkg =~ s,::,/,gr;
+       return if $INC{"$fn.pm"};
+       $INC{"$fn.pm"} = 1;
+       Gruntmaster::Page::Base->import_to($pkg, $id, $title);
+       1
+}
+
+sub list {
+       my ($thing, $lang, $env, $ct) = @_;
+       my %thing = %$thing;
+       undef $ct unless $thing{contest};
+       debug $env => "Contest is $ct";
+       local $Gruntmaster::Data::contest = $ct if $ct;
+       my @thing = hgetall $thing{hash};
+       @thing = map  { $thing{mangle}->(); $_ } @thing if exists $thing{mangle};
+       @thing = grep { $thing{choose}->() } @thing if exists $thing{choose};
+       @thing = sort { $thing{sortby}->() } @thing if exists $thing{sortby};
+       my %params;
+       $thing{group} //= sub { $thing{id} };
+       for (@thing) {
+               my $group = $thing{group}->();
+               $params{$group} //= [];
+               push $params{$group}, $_
+       }
+       wantarray ? %params : \%params
+}
+
+sub entry {
+       my ($thing, $lang, $env, $id, $ct) = @_;
+       my %thing = %$thing;
+       ($id, $ct) = ($ct, $id) if $thing{contest};
+       local $Gruntmaster::Data::contest = $ct if $ct;
+       debug $env => "Hash is $thing{hash} and id is $id";
+       my %params = HGETALL "$thing{hash}.$id";
+       $thing{mangle}->(local $_ = \%params) if exists $thing{mangle};
+       wantarray ? %params : \%params
+}
+
+sub headers ($) { ['Content-Type' => 'application/json', 'Cache-Control' => 'max-age=' . $_[0]->max_age] }
+
+sub create_thing {
+       my %thing = @_;
+       my $ucid = ucfirst $thing{id};
+       my $pkg = "Gruntmaster::Page::$ucid";
+
+       putsym "${pkg}::_generate", sub { $_[1]->param(list \%thing, @_[2..$#_]) } if makepkg $pkg, @thing{qw/id title/};
+       putsym "${pkg}::Entry::_generate",  sub { $_[1]->param(entry \%thing, @_[2..$#_]) } if makepkg "${pkg}::Entry", "$thing{id}_entry", '<tmpl_var name>';
+       putsym "${pkg}::Read::generate", sub { [200, headers shift, [encode_json list \%thing, @_]] } if makepkg "${pkg}::Read";
+       putsym "${pkg}::Entry::Read::generate", sub { [200, headers shift, [encode_json entry \%thing, @_]] } if makepkg "${pkg}::Entry::Read";
+}
+
+sub params;
+sub contest;
+sub choose (&);
+sub sortby (&);
+sub group  (&);
+sub mangle (&);
+
+sub thing (&){
+       my %thing;
+       no strict 'refs';
+       local *{"params"} = sub { @thing{qw/id hash title/} = @_ };
+       local *{"choose"} = sub { $thing{choose} = shift };
+       local *{"sortby"} = sub { $thing{sortby} = shift };
+       local *{"mangle"} = sub { $thing{mangle} = shift };
+       local *{"group"} = sub { $thing{group} = shift };
+       local *{"contest"} = sub { $thing{contest} = 1 };
+       use strict 'refs';
+
+       shift->();
+       create_thing %thing
+}
+
+##################################################
+
+thing {
+       params qw/us user Users/;
+       choose { $_->{name} =~ /\w/ };
+       sortby { lc $a->{name} cmp lc $b->{name} };
+};
+
+thing {
+       params qw/pb problem Problems/;
+       contest;
+       sortby { $a->{name} cmp $b->{name} };
+       group { $_->{level} };
+};
+
+thing {
+       params qw/ct contest Contests/;
+       sortby { $a->{start} <=> $b->{start} };
+       group { time < $_->{start} ? 'pending' : time > $_->{end} ? 'finished' : 'running' };
+       mangle { $_->{started} = time >= $_->{start} };
+};
+
+thing {
+       params qw/log job/, 'Job log';
+       contest;
+       mangle { $_->{results} &&= decode_json $_->{results}; }
+};
+
+1
index b8ddafba37e714c23349ca4f24fb494c96fd52cc..f51000e85693665d81d3bcea6f5586fc1183c28e 100644 (file)
@@ -1,13 +1,6 @@
 package Gruntmaster::Page::JS;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-use File::Slurp qw/read_file/;
 use JavaScript::Minifier::XS qw/minify/;
 
 sub generate{
@@ -18,6 +11,4 @@ sub generate{
        [200, ['Content-Type' => 'application/javascript', 'Cache-Control' => 'public, max-age=604800', 'X-Forever' => 1], [minify $js] ]
 }
 
-sub variants{ [[js => 1, 'application/javascript', undef, undef, undef, undef]] }
-
 1
index 68f45fdc3790bfe8ca045740d0782c1a36cd911a..7fe888523f0809acda18af0cf88eb0545ff33dae 100644 (file)
@@ -1,11 +1,6 @@
 package Gruntmaster::Page::Log;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base log => 'Job log';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
 
 use constant PAGE_SIZE => 10;
 
diff --git a/lib/Gruntmaster/Page/Log/Entry.pm b/lib/Gruntmaster/Page/Log/Entry.pm
deleted file mode 100644 (file)
index 57591b5..0000000
+++ /dev/null
@@ -1,29 +0,0 @@
-package Gruntmaster::Page::Log::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base log_entry => 'Job <tmpl_var id>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env, $ct, $id) = @_;
-       debug $env => "language is '$lang', contest is '$ct' and id is '$id'";
-       local $Gruntmaster::Data::contest = $ct if $ct;
-
-       my @tests = ();
-
-       eval {
-               @tests = map {
-                       $_->{time} = sprintf "%.4fs", $_->{time};
-                       $_
-               } @{job_results $id};
-       };
-
-       $htc->param(id => $id);
-       $htc->param(tests => \@tests);
-       $htc->param(errors => job_errors $id)
-}
-
-1
index 86689ac04be0621a93bc59083e5e1f36d399a865..3a7522e4e6393a8a2a2d02cf6beb5105db491317 100644 (file)
@@ -1,14 +1,7 @@
 package Gruntmaster::Page::Passwd;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
 use Apache2::Authen::Passphrase qw/pwcheck pwset/;
-use Plack::Request;
 
 sub generate{
        my ($self, $format, $env) = @_;
@@ -22,6 +15,4 @@ sub generate{
        reply 'Password changed successfully';
 }
 
-sub variants{ [[reply => 1, undef, undef, undef, undef, undef]] }
-
 1
diff --git a/lib/Gruntmaster/Page/Pb.pm b/lib/Gruntmaster/Page/Pb.pm
deleted file mode 100644 (file)
index ba78869..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-package Gruntmaster::Page::Pb;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base pb => 'Problems';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env, $ct) = @_;
-       debug $env => "language is '$lang' and contest is '$ct'";
-       local $Gruntmaster::Data::contest = $ct if $ct;
-
-       my @problems = sort { $b->{name} cmp $a->{name} } map +{
-               id    => $_,
-               name  => problem_name,
-               level => problem_level}, problems;
-
-       for my $d (qw/beginner easy medium advanced hard/) {
-               $htc->param($d => [grep {$_->{level} and $_->{level} eq $d} @problems]);
-       }
-       $htc->param(levels => grep { $_->{level} } @problems);
-       $htc->param(problems => \@problems);
-}
-
-1
index 4cf007edcd1760d3eaf7dea49298ad942d52265f..f03fe7aa265b569dfbb03b046daac7f77f64e080 100644 (file)
@@ -1,11 +1,6 @@
 package Gruntmaster::Page::Pb::Entry;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base pb_entry => '<tmpl_var name>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
 
 use constant FORMATS => [qw/C CPP JAVA PERL PYTHON/];
 
index dcb9451ebd8c40b682372e728796a047fb58c9e0..be1d4bec513b312376fef765da8104febab40d7e 100644 (file)
@@ -1,14 +1,7 @@
 package Gruntmaster::Page::Register;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
 use Apache2::Authen::Passphrase qw/pwcheck pwset USER_REGEX/;
-use Plack::Request;
 
 sub generate{
        my ($self, $format, $env) = @_;
@@ -27,6 +20,4 @@ sub generate{
        reply 'Registered successfully';
 }
 
-sub variants{ [[reply => 1, undef, undef, undef, undef, undef]] }
-
 1
index 8e51d8ba71b676455badcb638a57a5ee1d7f6407..8f9ab1b89ea9b45d8194df8fa97db8bc57766ad1 100644 (file)
@@ -1,11 +1,6 @@
 package Gruntmaster::Page::Src;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
 
 use constant CONTENT_TYPES => +{
        c => 'text/x-csrc',
@@ -25,6 +20,4 @@ sub generate{
        [200, ['Content-Type' => CONTENT_TYPES->{$ext}, 'Cache-Control' => 'max-age=604800', 'X-Forever' => 1], [job_inmeta($job)->{files}{prog}{content}] ]
 }
 
-sub variants{ [[file => 1, undef, undef, undef, undef, undef]] }
-
 1
index 6486136cb09d362b6c0cd2f14294ba748c18217d..3857c1ad22f991a6c5e5745b1ee5e6b9ef1a67d8 100644 (file)
@@ -1,11 +1,6 @@
 package Gruntmaster::Page::St;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base st => 'Standings';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
 
 use constant LEVEL_VALUES => {
        beginner => 100,
@@ -24,7 +19,7 @@ sub calc_score{
        $score = ($totaltime - $timetaken) / $totaltime * $score;
        $score -= $tries / 10 * $mxscore;
        $score = $mxscore * 3 / 10 if $score < $mxscore * 3 / 10;
-       int $score
+       int $score + 0.5
 }
 
 sub _generate{
@@ -43,14 +38,15 @@ sub _generate{
        @problems = sort @problems;
        my (%scores, %tries);
        for (1 .. jobcard) {
+               next unless defined job_user && defined job_problem && defined job_result;
+               next if $Gruntmaster::Data::contest && job_date() < $start;
+
                if ($Gruntmaster::Data::contest) {
-                       $scores{job_user()}{job_problem()} = job_result() ? 0 : calc_score (job_user(), job_problem(), job_date(), $tries{job_user()}{job_problem()}++, $totaltime) if job_date() > $start;
-               } elsif (defined job_user && defined job_problem && defined job_result) {
-                       if (defined job_result_text && job_result_text =~ m/^(\scores+)/) {
-                               $scores{job_user()}{job_problem()} = $ct;
-                       } else {
-                               $scores{job_user()}{job_problem()} = job_result() ? 0 : 100;
-                       }
+                       $scores{job_user()}{job_problem()} = job_result() ? 0 : calc_score (job_user(), job_problem(), job_date(), $tries{job_user()}{job_problem()}, $totaltime);
+                       $tries{job_user()}{job_problem()}++;
+               } else {
+                       no warnings 'numeric';
+                       $scores{job_user()}{job_problem()} = 0 + job_result_text() || (job_result() ? 0 : 100)
                }
        }
 
index 0159a9d06865f7a3f1132324e171bf310a4c748a..e537765165bb64fe05646d9df0bb26a3df098a3e 100644 (file)
@@ -1,15 +1,6 @@
 package Gruntmaster::Page::Submit;
 
-use 5.014000;
-use strict;
-use warnings;
 use Gruntmaster::Page::Base;
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-use Apache2::Authen::Passphrase qw/pwcheck pwset USER_REGEX/;
-use File::Slurp qw/read_file/;
-use Plack::Request;
 
 use constant FORMAT_EXTENSION => {
        C => 'c',
@@ -61,6 +52,4 @@ sub generate{
        [303, [Location => $r->path =~ s,/pb/\w+/submit$,/log/,r], ['']]
 }
 
-sub variants{ [[reply => 1, undef, undef, undef, undef, undef]] }
-
 1
diff --git a/lib/Gruntmaster/Page/Us.pm b/lib/Gruntmaster/Page/Us.pm
deleted file mode 100644 (file)
index 915ee50..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-package Gruntmaster::Page::Us;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base us => 'Users';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env) = @_;
-       debug $env => "language is '$lang'";
-
-       $htc->param(users => [ sort { lc $a->{name} cmp lc $b->{name} }
-                                                        map { {id => $_, name => user_name} }
-                                                          grep { user_name =~ /\w/ } users ]);
-}
-
-1
diff --git a/lib/Gruntmaster/Page/Us/Entry.pm b/lib/Gruntmaster/Page/Us/Entry.pm
deleted file mode 100644 (file)
index 628f9fa..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-package Gruntmaster::Page::Us::Entry;
-
-use 5.014000;
-use strict;
-use warnings;
-use Gruntmaster::Page::Base us_entry => '<tmpl_var name>';
-our @ISA = qw/Gruntmaster::Page::Base/;
-our $VERSION = '0.001';
-
-sub _generate{
-       my ($self, $htc, $lang, $env, $us) = @_;
-       debug $env => "language is '$lang', user is '$us'";
-       local $_ = $us;
-
-       $htc->param(name => user_name);
-       $htc->param(town => user_town);
-       $htc->param(university => user_university);
-       $htc->param(level => user_level);
-}
-
-1
index a0711013f99fec760e5b36f50cb8f77ce495da7e..f3da5719fe584be22e0c3600ae9307ffe29e0e8a 100644 (file)
@@ -10,6 +10,9 @@ our $VERSION = '5999.000_001';
 use File::Slurp qw/read_file/;
 use HTTP::Negotiate qw/choose/;
 use Plack::Request;
+use Gruntmaster::Page::Log;
+use Gruntmaster::Page::Pb::Entry;
+use Gruntmaster::Page::Generic;
 
 my %handlers;
 
@@ -58,20 +61,33 @@ BEGIN{
        my $word = qr,(\w+),a;
        my $ct = qr,(?:\/ct/$word)?,a;
 
+       sub generic {
+               my ($thing, $ct, $fs) = @_;
+               $ct //= '', $fs //= '';
+               my $pkg = ucfirst $thing;
+               get qr,$ct/$thing/, => $pkg;
+               get qr,$ct/$thing/$word$fs, => "${pkg}::Entry";
+
+               get  qr,$ct/$thing/read,         => "${pkg}::Read";
+#              post qr,$ct/$thing/$word/create, => "${pkg}::Entry::Create";
+               get  qr,$ct/$thing/$word/read,   => "${pkg}::Entry::Read";
+#              post qr,$ct/$thing/$word/update, => "${pkg}::Entry::Update";
+#              post qr,$ct/$thing/$word/delete, => "${pkg}::Entry::Delete";
+       }
+
        get qr,/css/$word\.css, => 'CSS';
        get qr,/js\.js, => 'JS';
 
-       get qr,/ct/, => 'Ct';
-       get qr,/ct/$word/, => 'Ct::Entry';
-       get qr,/us/, => 'Us';
-       get qr,/us/$word, => 'Us::Entry';
+       generic 'us';
+       generic ct => '', '/';
+       generic pb => $ct;
+       #generic log => $ct;
 
        get qr,$ct/log/(\d+)?, => 'Log';
        get qr,$ct/log/st, => 'St';
        get qr,$ct/log/job/$word, => 'Log::Entry';
+       get qr,$ct/log/job/$word/read, => 'Log::Entry::Read';
        get qr,$ct/log/src/$word\.$word, => 'Src';
-       get qr,$ct/pb/, => 'Pb';
-       get qr,$ct/pb/$word, => 'Pb::Entry';
        post qr,$ct/pb/$word/submit, => 'Submit';
 
        post qr,/action/register, => 'Register';
diff --git a/t/mech.t b/t/mech.t
new file mode 100644 (file)
index 0000000..5ea673b
--- /dev/null
+++ b/t/mech.t
@@ -0,0 +1,14 @@
+#!/usr/bin/perl -w
+use strict;
+use warnings;
+
+use Test::More tests => 5;
+use Test::WWW::Mechanize::PSGI;
+
+my $mech = Test::WWW::Mechanize::PSGI->new(app => do 'app.psgi');
+$mech->get_ok('/');
+$mech->title_is('Gruntmaster 6000');
+
+$mech->get_ok('/pb/');
+$mech->title_is('Problems');
+$mech->content_contains('Spell');
index ab10185f323703859f27c4eca5500d4aeebc206c..045bf741e6653794ec120c048d67a969b5595834 100644 (file)
@@ -5,8 +5,8 @@
 <tr><th>Name<th>Start date<th>End date<th>Owner
 <tbody>
 <tmpl_loop running><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
-<td><tmpl_var start>
-<td><tmpl_var end>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end};   %>
 <td><tmpl_var owner>
 </tmpl_loop>
 </table>
@@ -19,8 +19,8 @@
 <tr><th>Name<th>Start date<th>End date<th>Owner
 <tbody>
 <tmpl_loop pending><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
-<td><tmpl_var start>
-<td><tmpl_var end>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end};   %>
 <td><tmpl_var owner>
 </tmpl_loop>
 </table>
@@ -33,8 +33,8 @@
 <tr><th>Name<th>Start date<th>End date<th>Owner
 <tbody>
 <tmpl_loop finished><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
-<td><tmpl_var start>
-<td><tmpl_var end>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
+<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end};   %>
 <td><tmpl_var owner>
 </tmpl_loop>
 </table>
index 14ac48e608fd2f985abebb17b6930435ba86300c..f95f345ad12b43eb32f501308aa272b6eccc6bd9 100644 (file)
@@ -1,5 +1,5 @@
-Contest start time: <tmpl_var start><br>
-Contest end time: <tmpl_var end><p>
+Contest start time: <%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %><br>
+Contest end time:   <%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end};   %><p>
 
 <tmpl_if started><a href="pb/">Problems</a><br>
 <a href="log/">Job log</a><br>
index 45cd40555a230dcea4d9b879f78acf4ccee69c64..adf6bfde3df7f1e85d98fc314bd19b23f178e7c7 100644 (file)
@@ -1,11 +1,15 @@
-Compiler output:
+<tmpl_if errors>
+<h2>Compiler output</h2>
 <pre><tmpl_var errors></pre>
+</tmpl_if>
 
-Results:
+<tmpl_if results>
+<h2>Results</h2>
 <table border class="table table-border table-striped">
 <thead>
 <tr><th>Test number<th>Result<th>Time
 <tbody>
-<tmpl_loop tests><tr><td><tmpl_var id><td class="r<tmpl_var result>"><tmpl_var result_text><td><tmpl_var time>
+<tmpl_loop results><tr><td><tmpl_var id><td class="r<tmpl_var result>"><tmpl_var result_text><td><%perl __OUT__ sprintf "%.4fs", __CURRENT__->{time}; %>
 </tmpl_loop>
 </table>
+</tmpl_if>
\ No newline at end of file
index 3a8194f6c0115b9bc46cc3d614a21bc22e6430d4..60205b1de2ee051fa2189495672362b4828fab6e 100644 (file)
@@ -1,26 +1,27 @@
-<tmpl_if levels>
+<tmpl_if beginner>
 <h2>Beginner</h2>
 <div class="list-group">
 <tmpl_loop beginner><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
 </tmpl_loop></div>
+</tmpl_if>
 
+<tmpl_if beginner>
 <h2>Easy</h2>
 <div class="list-group">
 <tmpl_loop easy><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
 </tmpl_loop></div>
+</tmpl_if>
 
+<tmpl_if beginner>
 <h2>Medium</h2>
 <div class="list-group">
 <tmpl_loop medium><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
 </tmpl_loop></div>
+</tmpl_if>
 
+<tmpl_if beginner>
 <h2>Hard</h2>
 <div class="list-group">
 <tmpl_loop hard><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
 </tmpl_loop></div>
-
-<tmpl_else>
-<div class="list-group">
-<tmpl_loop problems><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
-</tmpl_loop></div>
 </tmpl_if>
index 174bc8009e3b16e201b922bab243c0965a61e2e0..72c72c35876e08c33949a874f049d3765ebc2f4b 100644 (file)
@@ -1,2 +1,2 @@
-<div class="list-group"><tmpl_loop users><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
+<div class="list-group"><tmpl_loop us><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
 </tmpl_loop></ol>
This page took 0.038141 seconds and 4 git commands to generate.