2 package Gruntmaster
::Data
;
4 # Created by DBIx::Class::Schema::Loader
5 # DO NOT MODIFY THE FIRST PART OF THIS FILE
10 use base
'DBIx::Class::Schema';
12 __PACKAGE__
->load_namespaces;
15 # Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-03-05 13:11:39
16 # DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dAEmtAexvUaNXLgYz2rNEg
18 our $VERSION = '5999.000_011';
20 use Lingua
::EN
::Inflect qw
/PL_N/;
21 use JSON
::MaybeXS qw
/decode_json/;
22 use PerlX
::Maybe qw
/maybe/;
23 use Sub
::Name qw
/subname/;
25 use constant PROBLEM_PUBLIC_COLUMNS
=> [qw
/id author writer level name owner private statement timeout olimit value/];
26 use constant USER_PUBLIC_COLUMNS
=> [qw
/id admin name town university level/];
27 use constant JOBS_PER_PAGE
=> 10;
30 our ($name, $sub) = @_;
31 no strict
'refs'; ## no critic (Strict)
32 *$name = subname
$name => $sub
36 for my $rs (qw
/contest contest_problem job open problem user problem_status contest_status/) {
37 my $rsname = ucfirst $rs;
38 $rsname =~ s/_([a-z])/\u$1/gs;
39 dynsub PL_N
($rs) => sub { $_[0]->resultset($rsname) };
40 dynsub
$rs => sub { $_[0]->resultset($rsname)->find($_[1]) };
45 my $rs = $_[0]->users->search(undef, {columns
=> USER_PUBLIC_COLUMNS
, prefetch
=> [qw
/problem_statuses contest_statuses/]} );
46 [ sort { $b->{solved
} <=> $a->{solved
} or $b->{attempted
} <=> $a->{attempted
} }map {
47 my $solved = $_->problem_statuses->count(solved
=> 1);
48 my $attempted = $_->problem_statuses->count(solved
=> 0);
49 my $contests = $_->contest_statuses->count;
50 +{ $_->get_columns, solved
=> $solved, attempted
=> $attempted, contests
=> $contests }
56 my $user = $self->users->find($id, {columns
=> USER_PUBLIC_COLUMNS
, prefetch
=> [qw
/problem_statuses contest_statuses/]});
57 my @problems = map { {problem
=> $_->get_column('problem'), solved
=> $_->solved} } $user->problem_statuses;
58 my @contests = map { {contest
=> $_->contest->id, contest_name
=> $_->contest->name, rank
=> $_->rank, score
=> $_->score} } $user->contest_statuses->search(undef, {prefetch
=> 'contest'});
59 +{ $user->get_columns, problems
=> \
@problems, contests
=> \
@contests }
63 my ($self, %args) = @_;
64 my $rs = $self->problems->search(undef, {order_by
=> 'me.name', columns
=> PROBLEM_PUBLIC_COLUMNS
, prefetch
=> 'owner'});
65 $rs = $rs->search({-or => ['contest_problems.contest' => undef, 'contest.stop' => {'<=', time}], 'me.private' => 0}, {join => {'contest_problems' => 'contest'}, distinct
=> 1}) unless $args{contest
};
66 $rs = $rs->search({'contest_problems.contest' => $args{contest
}}, {join => 'contest_problems'}) if $args{contest
};
67 $rs = $rs->search({'me.owner' => $args{owner
}}) if $args{owner
};
69 $params{contest
} = $args{contest
} if $args{contest
};
71 $params{$_->level} //= [];
72 push @
{$params{$_->level}}, {$_->get_columns, owner_name
=> $_->owner->name} ;
78 my ($self, $id, $contest, $user) = @_;
79 my $running = $contest && $self->contest($contest)->is_running;
80 my $columns = PROBLEM_PUBLIC_COLUMNS
;
81 push @
$columns, 'solution' unless $running;
82 my $pb = $self->problems->find($id, {columns
=> $columns, prefetch
=> 'owner'});
83 eval { ## no critic (RequireCheckingReturnValueOfEval)
84 $self->opens->create({
91 $contest &&= $self->contest($contest);
92 +{ $pb->get_columns, owner_name
=> $pb->owner->name, cansubmit
=> $contest ?
$running : 1, $running ?
(contest_start
=> $contest->start, contest_stop
=> $contest->stop) : () }
96 my ($self, %args) = @_;
97 my $rs = $self->contests->search(undef, {order_by
=> {-desc
=> 'start'}, prefetch
=> 'owner'});
98 $rs = $rs->search({owner
=> $args{owner
}}) if $args{owner
};
101 my $state = $_->is_pending ?
'pending' : $_->is_running ?
'running' : 'finished';
102 $params{$state} //= [];
103 push @
{$params{$state}}, { $_->get_columns, started
=> !$_->is_pending, owner_name
=> $_->owner->name };
109 my ($self, $id) = @_;
110 my $ct = $self->contest($id);
111 +{ $ct->get_columns, started
=> !$ct->is_pending, owner_name
=> $ct->owner->name }
115 my ($self, %args) = @_;
117 my $rs = $self->jobs->search(undef, {order_by
=> {-desc
=> 'me.id'}, prefetch
=> ['problem', 'owner'], rows
=> JOBS_PER_PAGE
, page
=> $args{page
}});
118 $rs = $rs->search({'me.owner' => $args{owner
}}) if $args{owner
};
119 $rs = $rs->search({contest
=> $args{contest
}}) if $args{contest
};
120 $rs = $rs->search({problem
=> $args{problem
}}) if $args{problem
};
123 my %params = $_->get_columns;
124 $params{owner_name
} = $_->owner->name;
125 $params{problem_name
} = $_->problem->name;
126 $params{results
} &&= decode_json
$params{results
};
127 $params{size
} = length $params{source
};
128 delete $params{source
};
131 current_page
=> $rs->pager->current_page,
132 maybe previous_page
=> $rs->pager->previous_page,
133 maybe next_page
=> $rs->pager->next_page,
134 maybe last_page
=> $rs->pager->last_page,
139 my ($self, $id) = @_;
140 my $job = $self->jobs->find($id, {prefetch
=> ['problem', 'owner']});
141 my %params = $job->get_columns;
142 $params{owner_name
} = $job->owner->name;
143 $params{problem_name
} = $job->problem->name;
144 $params{results
} &&= decode_json
$params{results
};
145 $params{size
} = length $params{source
};
146 delete $params{source
};
152 my @jobs = $self->jobs->search(undef, {cache
=> 1})->all;
155 $hash{$_->get_column('problem'), $_->get_column('owner')} = [$_->id, $_->result ?
0 : 1] for @jobs;
156 my @problem_statuses = map { [split ($;), @
{$hash{$_}} ] } keys %hash;
158 my @contest_statuses = map {
159 my $contest = $_->id;
160 map { [$contest, $_->{user
}, $_->{score
}, $_->{rank
}] } $_->standings
161 } $self->contests->all;
164 $self->problem_statuses->delete;
165 $self->problem_statuses->populate([[qw
/problem owner job solved/], @problem_statuses]);
166 $self->contest_statuses->delete;
167 $self->contest_statuses->populate([[qw
/contest owner score rank/], @contest_statuses]);
181 Gruntmaster::Data - Gruntmaster 6000 Online Judge -- database interface and tools
185 my $db = Gruntmaster::Data->connect('dbi:Pg:');
187 my $problem = $db->problem('my_problem');
188 $problem->update({timeout => 2.5}); # Set time limit to 2.5 seconds
189 $problem->rerun; # And rerun all jobs for this problem
193 my $contest = $db->contests->create({ # Create a new contest
195 name => 'My Awesome Contest',
199 $db->contest_problems->create({ # Add a problem to the contest
200 contest => 'my_contest',
201 problem => 'my_problem',
204 say 'The contest has not started yet' if $contest->is_pending;
208 my @jobs = $db->jobs->search({contest => 'my_contest', owner => 'MGV'})->all;
209 $_->rerun for @jobs; # Rerun all jobs sent by MGV in my_contest
213 Gruntmaster::Data is the interface to the Gruntmaster 6000 database. Read the L<DBIx::Class> documentation for usage information.
215 In addition to the typical DBIx::Class::Schema methods, this module contains several convenience methods:
221 Equivalent to C<< $schema->resultset('Contest') >>
223 =item contest_problems
225 Equivalent to C<< $schema->resultset('ContestProblem') >>
229 Equivalent to C<< $schema->resultset('Job') >>
233 Equivalent to C<< $schema->resultset('Problem') >>
237 Equivalent to C<< $schema->resultset('User') >>
241 Equivalent to C<< $schema->resultset('Contest')->find($id) >>
245 Equivalent to C<< $schema->resultset('Job')->find($id) >>
249 Equivalent to C<< $schema->resultset('Problem')->find($id) >>
253 Equivalent to C<< $schema->resultset('User')->find($id) >>
257 Returns a list of users as an arrayref containing hashrefs.
259 =item user_entry($id)
261 Returns a hashref with information about the user $id.
263 =item problem_list([%args])
265 Returns a list of problems grouped by level. A hashref with levels as keys.
267 Takes the following arguments:
273 Only show problems owned by this user
277 Only show problems in this contest
281 =item problem_entry($id, [$contest, $user])
283 Returns a hashref with information about the problem $id. If $contest and $user are present, problem open data is updated.
285 =item contest_list([%args])
287 Returns a list of contests grouped by state. A hashref with the following keys:
293 An arrayref of hashrefs representing pending contests
297 An arrayref of hashrefs representing running contests
301 An arrayref of hashrefs representing finished contests
305 Takes the following arguments:
311 Only show contests owned by this user.
315 =item contest_entry($id)
317 Returns a hashref with information about the contest $id.
319 =item job_list([%args])
321 Returns a list of jobs as an arrayref containing hashrefs. Takes the following arguments:
327 Only show jobs submitted by this user.
331 Only show jobs submitted in this contest.
335 Only show jobs submitted for this problem.
339 Show this page of results. Defaults to 1. Pages have 10 entries, and the first page has the most recent jobs.
345 Returns a hashref with information about the job $id.
351 Marius Gavrilescu E<lt>marius@ieval.roE<gt>
353 =head1 COPYRIGHT AND LICENSE
355 Copyright (C) 2014 by Marius Gavrilescu
357 This library is free software; you can redistribute it and/or modify
358 it under the same terms as Perl itself, either Perl version 5.18.1 or,
359 at your option, any later version of Perl 5 you may have available.