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_012';
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]) };
46 my $rs = $self->users->search(undef, {columns
=> USER_PUBLIC_COLUMNS
} );
47 my (%solved, %attempted, %contests);
49 for my $row ($self->problem_statuses->all) {
50 $solved {$row->rawowner}++ if $row->solved;
51 $attempted{$row->rawowner}++ unless $row->solved;
53 $contests{$_->rawowner}++ for $self->contest_statuses->all;
55 [ sort { $b->{solved
} <=> $a->{solved
} or $b->{attempted
} <=> $a->{attempted
} } map { ## no critic (ProhibitReverseSort)
58 solved
=> ($solved{$id} // 0),
59 attempted
=> ($attempted{$id} // 0),
60 contests
=> ($contests{$id} // 0) }
66 my $user = $self->users->find($id, {columns
=> USER_PUBLIC_COLUMNS
, prefetch
=> [qw
/problem_statuses contest_statuses/]});
67 my @problems = map { {problem
=> $_->get_column('problem'), solved
=> $_->solved} } $user->problem_statuses;
68 my @contests = map { {contest
=> $_->contest->id, contest_name
=> $_->contest->name, rank
=> $_->rank, score
=> $_->score} } $user->contest_statuses->search(undef, {prefetch
=> 'contest'});
69 +{ $user->get_columns, problems
=> \
@problems, contests
=> \
@contests }
73 my ($self, %args) = @_;
74 my $rs = $self->problems->search(undef, {order_by
=> 'me.name', columns
=> PROBLEM_PUBLIC_COLUMNS
, prefetch
=> 'owner'});
75 $rs = $rs->search({-or => ['contest_problems.contest' => undef, 'contest.stop' => {'<=', time}], 'me.private' => 0}, {join => {'contest_problems' => 'contest'}, distinct
=> 1}) unless $args{contest
};
76 $rs = $rs->search({'contest_problems.contest' => $args{contest
}}, {join => 'contest_problems'}) if $args{contest
};
77 $rs = $rs->search({'me.owner' => $args{owner
}}) if $args{owner
};
79 $params{contest
} = $args{contest
} if $args{contest
};
81 $params{$_->level} //= [];
82 push @
{$params{$_->level}}, {$_->get_columns, owner_name
=> $_->owner->name} ;
88 my ($self, $id, $contest, $user) = @_;
89 my $running = $contest && $self->contest($contest)->is_running;
90 my $columns = PROBLEM_PUBLIC_COLUMNS
;
91 push @
$columns, 'solution' unless $running;
92 my $pb = $self->problems->find($id, {columns
=> $columns, prefetch
=> 'owner'});
93 eval { ## no critic (RequireCheckingReturnValueOfEval)
94 $self->opens->create({
101 $contest &&= $self->contest($contest);
102 +{ $pb->get_columns, owner_name
=> $pb->owner->name, cansubmit
=> $contest ?
$running : 1, $running ?
(contest_start
=> $contest->start, contest_stop
=> $contest->stop) : () }
106 my ($self, %args) = @_;
107 my $rs = $self->contests->search(undef, {order_by
=> {-desc
=> 'start'}, prefetch
=> 'owner'});
108 $rs = $rs->search({owner
=> $args{owner
}}) if $args{owner
};
111 my $state = $_->is_pending ?
'pending' : $_->is_running ?
'running' : 'finished';
112 $params{$state} //= [];
113 push @
{$params{$state}}, { $_->get_columns, started
=> !$_->is_pending, owner_name
=> $_->owner->name };
119 my ($self, $id) = @_;
120 my $ct = $self->contest($id);
121 +{ $ct->get_columns, started
=> !$ct->is_pending, owner_name
=> $ct->owner->name }
125 my ($self, %args) = @_;
127 my $rs = $self->jobs->search(undef, {order_by
=> {-desc
=> 'me.id'}, prefetch
=> ['problem', 'owner'], rows
=> JOBS_PER_PAGE
, page
=> $args{page
}});
128 $rs = $rs->search({'me.owner' => $args{owner
}}) if $args{owner
};
129 $rs = $rs->search({contest
=> $args{contest
}}) if $args{contest
};
130 $rs = $rs->search({problem
=> $args{problem
}}) if $args{problem
};
133 my %params = $_->get_columns;
134 $params{owner_name
} = $_->owner->name;
135 $params{problem_name
} = $_->problem->name;
136 $params{results
} &&= decode_json
$params{results
};
137 $params{size
} = length $params{source
};
138 delete $params{source
};
141 current_page
=> $rs->pager->current_page,
142 maybe previous_page
=> $rs->pager->previous_page,
143 maybe next_page
=> $rs->pager->next_page,
144 maybe last_page
=> $rs->pager->last_page,
149 my ($self, $id) = @_;
150 my $job = $self->jobs->find($id, {prefetch
=> ['problem', 'owner']});
151 my %params = $job->get_columns;
152 $params{owner_name
} = $job->owner->name;
153 $params{problem_name
} = $job->problem->name;
154 $params{results
} &&= decode_json
$params{results
};
155 $params{size
} = length $params{source
};
156 delete $params{source
};
162 my @jobs = $self->jobs->search(undef, {cache
=> 1})->all;
165 $hash{$_->get_column('problem'), $_->get_column('owner')} = [$_->id, $_->result ?
0 : 1] for @jobs;
166 my @problem_statuses = map { [split ($;), @
{$hash{$_}} ] } keys %hash;
168 my @contest_statuses = map {
169 my $contest = $_->id;
170 map { [$contest, $_->{user
}, $_->{score
}, $_->{rank
}] } $_->standings
171 } $self->contests->all;
174 $self->problem_statuses->delete;
175 $self->problem_statuses->populate([[qw
/problem owner job solved/], @problem_statuses]);
176 $self->contest_statuses->delete;
177 $self->contest_statuses->populate([[qw
/contest owner score rank/], @contest_statuses]);
191 Gruntmaster::Data - Gruntmaster 6000 Online Judge -- database interface and tools
195 my $db = Gruntmaster::Data->connect('dbi:Pg:');
197 my $problem = $db->problem('my_problem');
198 $problem->update({timeout => 2.5}); # Set time limit to 2.5 seconds
199 $problem->rerun; # And rerun all jobs for this problem
203 my $contest = $db->contests->create({ # Create a new contest
205 name => 'My Awesome Contest',
209 $db->contest_problems->create({ # Add a problem to the contest
210 contest => 'my_contest',
211 problem => 'my_problem',
214 say 'The contest has not started yet' if $contest->is_pending;
218 my @jobs = $db->jobs->search({contest => 'my_contest', owner => 'MGV'})->all;
219 $_->rerun for @jobs; # Rerun all jobs sent by MGV in my_contest
223 Gruntmaster::Data is the interface to the Gruntmaster 6000 database. Read the L<DBIx::Class> documentation for usage information.
225 In addition to the typical DBIx::Class::Schema methods, this module contains several convenience methods:
231 Equivalent to C<< $schema->resultset('Contest') >>
233 =item contest_problems
235 Equivalent to C<< $schema->resultset('ContestProblem') >>
239 Equivalent to C<< $schema->resultset('Job') >>
243 Equivalent to C<< $schema->resultset('Problem') >>
247 Equivalent to C<< $schema->resultset('User') >>
251 Equivalent to C<< $schema->resultset('Contest')->find($id) >>
255 Equivalent to C<< $schema->resultset('Job')->find($id) >>
259 Equivalent to C<< $schema->resultset('Problem')->find($id) >>
263 Equivalent to C<< $schema->resultset('User')->find($id) >>
267 Returns a list of users as an arrayref containing hashrefs.
269 =item user_entry($id)
271 Returns a hashref with information about the user $id.
273 =item problem_list([%args])
275 Returns a list of problems grouped by level. A hashref with levels as keys.
277 Takes the following arguments:
283 Only show problems owned by this user
287 Only show problems in this contest
291 =item problem_entry($id, [$contest, $user])
293 Returns a hashref with information about the problem $id. If $contest and $user are present, problem open data is updated.
295 =item contest_list([%args])
297 Returns a list of contests grouped by state. A hashref with the following keys:
303 An arrayref of hashrefs representing pending contests
307 An arrayref of hashrefs representing running contests
311 An arrayref of hashrefs representing finished contests
315 Takes the following arguments:
321 Only show contests owned by this user.
325 =item contest_entry($id)
327 Returns a hashref with information about the contest $id.
329 =item job_list([%args])
331 Returns a list of jobs as an arrayref containing hashrefs. Takes the following arguments:
337 Only show jobs submitted by this user.
341 Only show jobs submitted in this contest.
345 Only show jobs submitted for this problem.
349 Show this page of results. Defaults to 1. Pages have 10 entries, and the first page has the most recent jobs.
355 Returns a hashref with information about the job $id.
361 Marius Gavrilescu E<lt>marius@ieval.roE<gt>
363 =head1 COPYRIGHT AND LICENSE
365 Copyright (C) 2014 by Marius Gavrilescu
367 This library is free software; you can redistribute it and/or modify
368 it under the same terms as Perl itself, either Perl version 5.18.1 or,
369 at your option, any later version of Perl 5 you may have available.