From: Marius Gavrilescu Date: Sun, 23 Feb 2014 10:16:15 +0000 (+0200) Subject: Merge branch 'master' into gruntmaster X-Git-Url: http://git.ieval.ro/?p=gruntmaster-page.git;a=commitdiff_plain;h=97f591f3b1dad315d68eb63313f7a129291b4d8a;hp=4da2c0022f346a63f42336c32f38c300fb74e884 Merge branch 'master' into gruntmaster --- diff --git a/MANIFEST b/MANIFEST index 80ce6d4..61687ff 100644 --- 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 + diff --git a/Makefile.PL b/Makefile.PL index dfb2291..0c47a00 100644 --- a/Makefile.PL +++ b/Makefile.PL @@ -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 ', - 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 ', + 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, + } +) diff --git a/app.psgi b/app.psgi index 62a6f79..f975385 100644 --- 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 } diff --git a/lib/Gruntmaster/Page/Base.pm b/lib/Gruntmaster/Page/Base.pm index 9e2d030..84d7451 100644 --- a/lib/Gruntmaster/Page/Base.pm +++ b/lib/Gruntmaster/Page/Base.pm @@ -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]} ] } diff --git a/lib/Gruntmaster/Page/CSS.pm b/lib/Gruntmaster/Page/CSS.pm index 2553ab6..912e948 100644 --- a/lib/Gruntmaster/Page/CSS.pm +++ b/lib/Gruntmaster/Page/CSS.pm @@ -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 index a21bf77..0000000 --- a/lib/Gruntmaster/Page/Ct.pm +++ /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 index acc076e..0000000 --- a/lib/Gruntmaster/Page/Ct/Entry.pm +++ /dev/null @@ -1,21 +0,0 @@ -package Gruntmaster::Page::Ct::Entry; - -use 5.014000; -use strict; -use warnings; -use Gruntmaster::Page::Base ct_entry => ''; -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 index 0000000..95d1cd8 --- /dev/null +++ b/lib/Gruntmaster/Page/Generic.pm @@ -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", ''; + 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 diff --git a/lib/Gruntmaster/Page/JS.pm b/lib/Gruntmaster/Page/JS.pm index b8ddafb..f51000e 100644 --- a/lib/Gruntmaster/Page/JS.pm +++ b/lib/Gruntmaster/Page/JS.pm @@ -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 diff --git a/lib/Gruntmaster/Page/Log.pm b/lib/Gruntmaster/Page/Log.pm index 68f45fd..7fe8885 100644 --- a/lib/Gruntmaster/Page/Log.pm +++ b/lib/Gruntmaster/Page/Log.pm @@ -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 index 57591b5..0000000 --- a/lib/Gruntmaster/Page/Log/Entry.pm +++ /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 '; -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 diff --git a/lib/Gruntmaster/Page/Passwd.pm b/lib/Gruntmaster/Page/Passwd.pm index 86689ac..3a7522e 100644 --- a/lib/Gruntmaster/Page/Passwd.pm +++ b/lib/Gruntmaster/Page/Passwd.pm @@ -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 index ba78869..0000000 --- a/lib/Gruntmaster/Page/Pb.pm +++ /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 diff --git a/lib/Gruntmaster/Page/Pb/Entry.pm b/lib/Gruntmaster/Page/Pb/Entry.pm index 4cf007e..f03fe7a 100644 --- a/lib/Gruntmaster/Page/Pb/Entry.pm +++ b/lib/Gruntmaster/Page/Pb/Entry.pm @@ -1,11 +1,6 @@ package Gruntmaster::Page::Pb::Entry; -use 5.014000; -use strict; -use warnings; use Gruntmaster::Page::Base pb_entry => ''; -our @ISA = qw/Gruntmaster::Page::Base/; -our $VERSION = '0.001'; use constant FORMATS => [qw/C CPP JAVA PERL PYTHON/]; diff --git a/lib/Gruntmaster/Page/Register.pm b/lib/Gruntmaster/Page/Register.pm index dcb9451..be1d4be 100644 --- a/lib/Gruntmaster/Page/Register.pm +++ b/lib/Gruntmaster/Page/Register.pm @@ -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 diff --git a/lib/Gruntmaster/Page/Src.pm b/lib/Gruntmaster/Page/Src.pm index 8e51d8b..8f9ab1b 100644 --- a/lib/Gruntmaster/Page/Src.pm +++ b/lib/Gruntmaster/Page/Src.pm @@ -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 diff --git a/lib/Gruntmaster/Page/St.pm b/lib/Gruntmaster/Page/St.pm index 6486136..3857c1a 100644 --- a/lib/Gruntmaster/Page/St.pm +++ b/lib/Gruntmaster/Page/St.pm @@ -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) } } diff --git a/lib/Gruntmaster/Page/Submit.pm b/lib/Gruntmaster/Page/Submit.pm index 0159a9d..e537765 100644 --- a/lib/Gruntmaster/Page/Submit.pm +++ b/lib/Gruntmaster/Page/Submit.pm @@ -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 index 915ee50..0000000 --- a/lib/Gruntmaster/Page/Us.pm +++ /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 index 628f9fa..0000000 --- a/lib/Gruntmaster/Page/Us/Entry.pm +++ /dev/null @@ -1,21 +0,0 @@ -package Gruntmaster::Page::Us::Entry; - -use 5.014000; -use strict; -use warnings; -use Gruntmaster::Page::Base us_entry => ''; -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 diff --git a/lib/Plack/App/Gruntmaster.pm b/lib/Plack/App/Gruntmaster.pm index a071101..f3da571 100644 --- a/lib/Plack/App/Gruntmaster.pm +++ b/lib/Plack/App/Gruntmaster.pm @@ -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 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'); diff --git a/tmpl/ct.en b/tmpl/ct.en index ab10185..045bf74 100644 --- a/tmpl/ct.en +++ b/tmpl/ct.en @@ -5,8 +5,8 @@ NameStart dateEnd dateOwner - - +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %> +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end}; %> @@ -19,8 +19,8 @@ NameStart dateEnd dateOwner - - +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %> +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end}; %> @@ -33,8 +33,8 @@ NameStart dateEnd dateOwner - - +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %> +<%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end}; %> diff --git a/tmpl/ct_entry.en b/tmpl/ct_entry.en index 14ac48e..f95f345 100644 --- a/tmpl/ct_entry.en +++ b/tmpl/ct_entry.en @@ -1,5 +1,5 @@ -Contest start time:
-Contest end time:

+Contest start time: <%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
+Contest end time: <%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{end}; %>

Problems
Job log
diff --git a/tmpl/log_entry.en b/tmpl/log_entry.en index 45cd405..adf6bfd 100644 --- a/tmpl/log_entry.en +++ b/tmpl/log_entry.en @@ -1,11 +1,15 @@ -Compiler output: + +

Compiler output

+ -Results: + +

Results

-
Test numberResultTime
+
<%perl __OUT__ sprintf "%.4fs", __CURRENT__->{time}; %>
+
\ No newline at end of file diff --git a/tmpl/pb.en b/tmpl/pb.en index 3a8194f..60205b1 100644 --- a/tmpl/pb.en +++ b/tmpl/pb.en @@ -1,26 +1,27 @@ - +

Beginner

+
+

Easy

+
+

Medium

+
+

Hard

- - -
- -
diff --git a/tmpl/us.en b/tmpl/us.en index 174bc80..72c72c3 100644 --- a/tmpl/us.en +++ b/tmpl/us.en @@ -1,2 +1,2 @@ -
+