#!/usr/bin/perl -w
use v5.14;
+no if $] >= 5.017011, warnings => 'experimental::smartmatch';
use Apache2::Authen::Passphrase qw/pwcheck/;
use Apache2::AuthzCaps qw/hascaps/;
}
}
+sub mangle_request {
+ my $app = $_[0];
+ sub {
+ local *__ANON__ = 'mangle_request_middleware';
+ my $env = $_[0];
+ my ($number, $word) = (qr,(\d+),a, qr,(\w+),a);
+ for ($env->{PATH_INFO}) {
+ $env->{'gruntmaster.page'} = $1 if s,/page/$number$,/,;
+ $env->{'gruntmaster.problem'} = $1 if s,^/pb/$word/,/,;
+ $env->{'gruntmaster.contest'} = $1 if s,^/ct/$word/,/,;
+ $env->{'gruntmaster.user'} = $1 if s,^/us/$word/,/,;
+ }
+ $app->($env);
+ }
+}
+
my %authen_cache;
sub authenticate {
enable 'Log4perl', category => 'plack';
enable \&require_admin;
enable_if \&some_auth_required, 'Auth::Basic', authenticator => \&authenticate, realm => 'Gruntmaster 6000';
+ enable \&mangle_request;
enable sub { my $app = $_[0]; sub { $_[0]->{'gruntmaster.dbic'} = $db; $app->($_[0]) } };
Plack::App::Gruntmaster->to_app
}
}
sub list {
- my ($thing, $lang, $env, $ct) = @_;
+ my ($thing, $lang, $env) = @_;
my %thing = %$thing;
- my $req = Plack::Request->new($env);
- debug $env => "Contest is $ct";
- $thing{makers} //= sub { shift->resultset($thing{rsname}) };
- my $rs = $thing{makers}->(db $env)->search(undef, {order_by => 'me.id'});
- if (my $page = $req->param('page')) {
+ #debug $env => "Contest is $ct";
+ $thing{makers} //= sub { db(shift)->resultset($thing{rsname}) };
+ my $rs = $thing{makers}->($env);
+ $rs = $rs->search(undef, {order_by => 'me.id'}) unless $rs->is_ordered;
+ if (my $page = $env->{'gruntmaster.page'}) {
my $pages = $rs->count / PAGE_SIZE;
$rs = $rs->search(undef, {offset => ($page - 1) * PAGE_SIZE, ($page == $pages ? () : (rows => PAGE_SIZE))});
}
}
sub entry {
- my ($thing, $lang, $env, $id, $ct) = @_;
+ my ($thing, $lang, $env, $id) = @_;
my %thing = %$thing;
- ($id, $ct) = ($ct, $id) if $ct;
debug $env => "Rsname is $thing{rsname} and id is $id";
- $thing{makers} //= sub { shift->resultset($thing{rsname}) };
- my %params = map {+ rs => $_, $_->get_columns } $thing{makers}->(db $env)->find($id);
- $params{contest} = $ct if $ct;
+ $thing{makers} //= sub { db(shift)->resultset($thing{rsname}) };
+ my %params = map {+ rs => $_, $_->get_columns } $thing{makers}->($env)->find($id);
$thing{mangle}->(local $_ = \%params) if exists $thing{mangle};
wantarray ? %params : \%params
}
thing {
params qw/pb Problem Problems/;
prefetch 'owner';
- makers { my ($db, $ct) = @_; $ct ? $db->contest($ct)->problems : $db->problems->search({private => 0}) };
+ makers {
+ my $env = $_[0];
+ my $db = db $env;
+ return $db->contest($env->{'gruntmaster.contest'})->problems->search(undef, {order_by => 'problem.id'}) if exists $env->{'gruntmaster.contest'};
+ return $db->problems->search({owner => $env->{'gruntmaster.user'}}) if exists $env->{'gruntmaster.user'};
+ $db->problems->search({private => 0});
+ };
sortby { $a->{name} cmp $b->{name}};
group { $_->{level} };
mangle {
thing {
params qw/log Job/, 'Job log';
prefetch 'owner', 'problem';
- makers { shift->jobs->search({contest => shift}) };
+ makers {
+ my $env = $_[0];
+ my $db = db $env;
+ return $db->jobs->search({'me.owner' => $env->{'gruntmaster.user'}}) if exists $env->{'gruntmaster.user'};
+ return $db->jobs->search({problem => $env->{'gruntmaster.problem'}}) if exists $env->{'gruntmaster.problem'};
+ $db->jobs->search({contest => $env->{'gruntmaster.contest'}})
+ };
sortby { $b->{id} <=> $a->{id}};
mangle {
$_->{results} &&= decode_json $_->{results};
}
BEGIN{
- my $word = qr,(\w+),a;
- my $ct = qr,(?:\/ct/$word)?,a;
+ my $word = qr,(\w+),a;
+ my $number = qr,(\d+),a;
sub generic {
- my ($thing, $ct, $fs) = @_;
- $ct //= '', $fs //= '';
- my $pkg = ucfirst $thing;
- get qr,$ct/$thing/, => $pkg;
- get qr,$ct/$thing/read, => "${pkg}::Read";
- get qr,$ct/$thing/$word$fs, => "${pkg}::Entry";
-# 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";
+ for my $thing (@_) {
+ my $pkg = ucfirst $thing;
+ get qr,/$thing/, => $pkg;
+ get qr,/$thing/read, => "${pkg}::Read";
+ get qr,/$thing/$word, => "${pkg}::Entry";
+# post qr,/$thing/$word/create, => "${pkg}::Entry::Create";
+ get qr,/$thing/$word/read, => "${pkg}::Entry::Read";
+# post qr,/$thing/$word/update, => "${pkg}::Entry::Update";
+# post qr,/$thing/$word/delete, => "${pkg}::Entry::Delete";
+ }
}
get qr,/css/$word\.css, => 'CSS';
get qr,/js\.js, => 'JS';
- generic 'us';
- generic ct => '', '/';
- generic pb => $ct;
- #generic log => $ct;
+ generic qw/us ct pb log/;
- 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';
- post qr,$ct/pb/$word/submit, => 'Submit';
+ get qr,/log/st, => 'St';
+ get qr,/log/src/$number\.$word, => 'Src';
+ post qr,/pb/$word/submit, => 'Submit';
post qr,/action/register, => 'Register';
post qr,/action/passwd, => 'Passwd';
<thead>
<tr><th>Name<th>Start date<th>Stop date<th>Owner
<tbody>
-<tmpl_loop running><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
+<tmpl_loop running><tr><td><a href="/ct/<tmpl_var id>"><tmpl_var name></a>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{stop}; %>
<td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
<thead>
<tr><th>Name<th>Start date<th>Stop date<th>Owner
<tbody>
-<tmpl_loop pstoping><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
+<tmpl_loop pstoping><tr><td><a href="/ct/<tmpl_var id>"><tmpl_var name></a>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{stop}; %>
<td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
<thead>
<tr><th>Name<th>Start date<th>Stop date<th>Owner
<tbody>
-<tmpl_loop finished><tr><td><a href="<tmpl_var id>/"><tmpl_var name></a>
+<tmpl_loop finished><tr><td><a href="/ct/<tmpl_var id>"><tmpl_var name></a>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{start}; %>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{stop}; %>
<td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
<tmpl_var ESCAPE=0 description>
-<tmpl_if started><a href="pb/">Problems</a><br>
-<a href="log/">Job log</a><br>
-<a href="log/st">Standings</a></tmpl_if>
+<tmpl_if started><a href="/ct/<tmpl_var id>/pb/">Problems</a><br>
+<a href="/ct/<tmpl_var id>/log/">Job log</a><br>
+<a href="/ct/<tmpl_var id>/log/st">Standings</a></tmpl_if>
<thead>
<tr><th>ID<th>Problem<th>Date<th>Size<th>User<th>Result
<tbody>
-<tmpl_loop log><tr><td><a href="job/<tmpl_var id>"><tmpl_var id></a>
-<td><a href="../pb/<tmpl_var problem>"><tmpl_var problem_name></a>
+<tmpl_loop log><tr><td><a href="/log/<tmpl_var id>"><tmpl_var id></a>
+<td><a href="/pb/<tmpl_var problem>"><tmpl_var problem_name></a>
<td><%perl __OUT__ POSIX::strftime '%c', localtime __CURRENT__->{date}; %>
-<td><a href="src/<tmpl_var id>.<tmpl_var extension>"<tmpl_if private> data-private</tmpl_if>><%perl __OUT__ sprintf '%.2fKB', __CURRENT__->{size}/1024; %></a>
+<td><a href="/log/src/<tmpl_var id>.<tmpl_var extension>"<tmpl_if private> data-private</tmpl_if>><%perl __OUT__ sprintf '%.2fKB', __CURRENT__->{size}/1024; %></a>
<td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var user></tmpl_if></a>
<td class="r<tmpl_var result>"><tmpl_var result_text>
</tmpl_loop>
<table border class="table table-bordered table-striped table-fixed">
<thead><tr><th>Name<th>Author<th>Owner
<tbody>
-<tmpl_loop beginner><tr><td><a href="<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
+<tmpl_loop beginner><tr><td><a href="/pb/<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
</tmpl_loop>
</table>
</tmpl_if>
<table border class="table table-bordered table-striped table-fixed">
<thead><tr><th>Name<th>Author<th>Owner
<tbody>
-<tmpl_loop easy><tr><td><a href="<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
+<tmpl_loop easy><tr><td><a href="/pb/<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
</tmpl_loop>
</table>
</tmpl_if>
<table border class="table table-bordered table-striped table-fixed">
<thead><tr><th>Name<th>Author<th>Owner
<tbody>
-<tmpl_loop medium><tr><td><a href="<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
+<tmpl_loop medium><tr><td><a href="/pb/<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
</tmpl_loop>
</table>
</tmpl_if>
<table border class="table table-bordered table-striped table-fixed">
<thead><tr><th>Name<th>Author<th>Owner
<tbody>
-<tmpl_loop hard><tr><td><a href="<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
+<tmpl_loop hard><tr><td><a href="/pb/<tmpl_var id>"><tmpl_var name></a><td><tmpl_var author><td><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a>
</tmpl_loop>
</table>
</tmpl_if>
<dt>Owner</dt> <dd><a href="/us/<tmpl_var owner>"><tmpl_if owner_name><tmpl_var owner_name><tmpl_else><tmpl_var owner></tmpl_if></a></dd>
</dl>
+<a href="/pb/<tmpl_var id>/log/">Job log</a>
+
<tmpl_if cansubmit>
<h1>Submit solution</h1>
-<form action="<tmpl_var id>/submit" method="POST" enctype="multipart/form-data" role="form">
+<form action="/pb/<tmpl_var id>/submit" method="POST" enctype="multipart/form-data" role="form">
<input type="hidden" name="problem" value="<tmpl_var id>">
<tmpl_if_defined contest><input type="hidden" name="contest" value="<tmpl_var contest>"></tmpl_if_defined>
</form>
</tmpl_if>
</div>
-</div>
\ No newline at end of file
+</div>
<table border class="table table-border table-striped">
<thead>
-<tmpl_if problems><tr><th>Rank<th>User<tmpl_loop problems><th><a href="../pb/<tmpl_var _.id>"><tmpl_var _.name></a></tmpl_loop><th>Total
+<tmpl_if problems><tr><th>Rank<th>User<tmpl_loop problems><th><a href="/pb/<tmpl_var _.id>"><tmpl_var _.name></a></tmpl_loop><th>Total
<tmpl_else><tr><th>Rank<th>User<th>Score
</tmpl_if>
-<div class="list-group"><tmpl_loop us><a class="list-group-item" href="<tmpl_var id>"><tmpl_var name></a>
-</tmpl_loop></ol>
+<div class="list-group"><tmpl_loop us><a class="list-group-item" href="/us/<tmpl_var id>"><tmpl_var name></a>
+</tmpl_loop><div>
<dt>University</dt> <dd><tmpl_var university></dd>
<dt>Level</dt> <dd><tmpl_var level></dd>
</dl>
+
+<a href="/us/<tmpl_var id>/log/">Job log</a><br>
+<a href="/us/<tmpl_var id>/pb/">Owned problems</a>