-bm.pl
Changes
db.sql
gruntmaster-contest
POSIX 0
Term::ANSIColor 0
- Authen::Passphrase 0
- Authen::Passphrase::BlowfishCrypt 0
- Bytes::Random::Secure 0
- Class::Method::Modifiers 0
Date::Parse 0
DBI 0
- DBIx::Class 0
DBIx::Simple 0
DBD::Pg 0
- Digest::SHA 0
File::Slurp 0
IO::Prompter 0
- Lingua::EN::Inflect 0
JSON::MaybeXS 0
PerlX::Maybe 0
- SQL::Abstract 0
- Sub::Name 0/,
+ SQL::Abstract 0/,
},
BUILD_REQUIRES => {
qw/DBD::SQLite 0
+++ /dev/null
-#!/usr/bin/perl
-use v5.14;
-use warnings;
-
-use lib 'lib';
-
-use Benchmark;
-use Gruntmaster::Data;
-
-my $db = Gruntmaster::Data->connect('dbi:Pg:');
-
-timethese(-1, {
- orig => sub { $db->user_list_orig },
- new => sub { $db->user_entry },
-});
-
-timethese(-1, {
- orig => sub { $db->user_entry_orig('PlayLikeNeverB4') },
- new => sub { $db->user_entry('PlayLikeNeverB4') },
-});
-
-timethese(-1, {
- orig => sub { $db->contest_list_orig },
- new => sub { $db->contest_entry },
-});
-
-timethese(-1, {
- orig => sub { $db->contest_entry_orig('mc2015r4') },
- new => sub { $db->contest_entry('mc2015r4') },
-});
-
-timethese(-1, {
- orig => sub { $db->problem_list_orig },
- new => sub { $db->problem_list },
-});
-
-timethese(-1, {
- orig => sub { $db->problem_entry_orig('aplusb') },
- new => sub { $db->problem_entry('aplusb') },
-});
-
-timethese(50, {
- orig => sub { $db->job_list_orig },
- new => sub { $db->job_list },
-});
-
-timethese(-1, {
- orig => sub { $db->job_entry_orig(9000) },
- new => sub { $db->job_entry(9000) },
-});
-
-timethese(10, {
- orig => sub { $db->update_status_orig },
- new => sub { $db->update_status },
-});
-use utf8;
package Gruntmaster::Data;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-use strict;
+use v5.14;
use warnings;
-use base 'DBIx::Class::Schema';
-
-__PACKAGE__->load_namespaces;
-
-
-# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-03-05 13:11:39
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dAEmtAexvUaNXLgYz2rNEg
-
use parent qw/Exporter/;
our $VERSION = '5999.000_013';
our @EXPORT = qw/purge/; ## no critic (ProhibitAutomaticExportation)
-use Lingua::EN::Inflect qw/PL_N/;
use JSON::MaybeXS qw/decode_json/;
use HTTP::Tiny;
use PerlX::Maybe qw/maybe/;
-use Sub::Name qw/subname/;
-use Class::Method::Modifiers qw/around/;
use DBI;
use DBIx::Simple;
use constant USER_PUBLIC_COLUMNS => [qw/id admin name town university country level/];
use constant JOBS_PER_PAGE => 50;
-sub dynsub{
- our ($name, $sub) = @_;
- no strict 'refs'; ## no critic (Strict)
- *$name = subname $name => $sub
-}
-
-BEGIN {
- for my $rs (qw/contest contest_problem job open limit problem user problem_status contest_status/) {
- my $rsname = ucfirst $rs;
- $rsname =~ s/_([a-z])/\u$1/gs;
- dynsub PL_N($rs) => sub { $_[0]->resultset($rsname) };
- dynsub $rs => sub { $_[0]->resultset($rsname)->find($_[1]) };
- }
-}
-
my %statements = (
user_list_sth => 'SELECT * FROM user_list LIMIT 200',
user_entry_sth => 'SELECT * FROM user_data WHERE id = ?',
job_full_sth => 'SELECT * FROM jobs WHERE id = ?',
);
-around connect => sub {
- my $orig = shift;
- my $self = $orig->(@_);
- $self->{dbh} = DBI->connect($_[1]);
- $self->{dbis} = DBIx::Simple->new($self->{dbh});
+sub connect {
+ my ($class, @args) = @_;
+
+ my $self = {
+ dbis => DBIx::Simple->new(@args),
+ };
$self->{dbis}->keep_statements = 100;
- $self
+ bless $self, $class
};
sub purge;
$el
}
-sub user_list_orig {
- my ($self) = @_;
- my $rs = $self->users->search(undef, {columns => USER_PUBLIC_COLUMNS} );
- my (%solved, %attempted, %contests);
-
- for my $row ($self->problem_statuses->all) {
- $solved {$row->rawowner}++ if $row->solved;
- $attempted{$row->rawowner}++ unless $row->solved;
- }
- $contests{$_->rawowner}++ for $self->contest_statuses->all;
-
- my @users = sort { $b->{solved} <=> $a->{solved} or $b->{attempted} <=> $a->{attempted} } ## no critic (ProhibitReverseSort)
- map {
- my $id = $_->id;
- +{ $_->get_columns,
- solved => ($solved{$id} // 0),
- attempted => ($attempted{$id} // 0),
- contests => ($contests{$id} // 0) }
- } $rs->all;
- @users = @users[0 .. 199] if @users > 200;
- \@users
-}
-
-sub user_entry_orig {
- my ($self, $id) = @_;
- my $user = $self->users->find($id, {columns => USER_PUBLIC_COLUMNS, prefetch => [qw/problem_statuses contest_statuses/]});
- my @problems = map { {problem => $_->get_column('problem'), solved => $_->solved} } $user->problem_statuses->search(undef, {order_by => 'problem'});
- my @contests = map { {contest => $_->contest->id, contest_name => $_->contest->name, rank => $_->rank, score => $_->score} } $user->contest_statuses->search(undef, {prefetch => 'contest', order_by => 'contest.start DESC'});
- +{ $user->get_columns, problems => \@problems, contests => \@contests }
-}
-
sub user_list {
my ($self) = @_;
scalar $self->query('user_list_sth')->hashes
$ret;
}
-sub problem_list_orig {
- my ($self, %args) = @_;
- my @columns = @{PROBLEM_PUBLIC_COLUMNS()};
- push @columns, 'solution' if $args{solution} && $args{contest} && !$self->contest($args{contest})->is_running;
- my $rs = $self->problems->search(undef, {order_by => 'me.name', columns => \@columns, prefetch => 'owner'});
- $rs = $rs->search({'private' => 0}) unless $args{contest} || $args{private};
- $rs = $rs->search({'contest_problems.contest' => $args{contest}}, {join => 'contest_problems'}) if $args{contest};
- $rs = $rs->search({'me.owner' => $args{owner}}) if $args{owner};
- my %params;
- $params{contest} = $args{contest} if $args{contest} && $self->contest($args{contest})->is_running;
- for ($rs->all) {
- $params{$_->level} //= [];
- push @{$params{$_->level}}, {$_->get_columns, owner_name => $_->owner->name} ;
- }
- \%params
-}
-
sub problem_list {
my ($self, %args) = @_;
my @columns = @{PROBLEM_PUBLIC_COLUMNS()};
\%params
}
-sub problem_entry_orig {
- my ($self, $id, $contest, $user) = @_;
- my $running = $contest && $self->contest($contest)->is_running;
- my @columns = @{PROBLEM_PUBLIC_COLUMNS()};
- push @columns, 'statement';
- push @columns, 'solution' unless $running;
- my $pb = $self->problems->find($id, {columns => \@columns, prefetch => 'owner'});
- my @limits = map { +{
- format => $_->format,
- timeout => $_->timeout,
- } } $self->limits->search({problem => $id});
- my $open;
- $open = $self->opens->find_or_create({
- contest => $contest,
- problem => $id,
- owner => $user,
- time => time,
- }) if $running;
- $contest &&= $self->contest($contest);
- +{
- $pb->get_columns,
- @limits ? (limits => \@limits) : (),
- owner_name => $pb->owner->name,
- cansubmit => !$contest || !$contest->is_finished,
- $running ? (
- contest_start => $contest->start,
- contest_stop => $contest->stop,
- open_time => $open->time
- ) : (),
- }
-}
-
sub problem_entry {
my ($self, $id, $contest, $user) = @_;
$contest &&= $self->contest_entry($contest);
$ret
}
-sub contest_list_orig {
- my ($self, %args) = @_;
- my $rs = $self->contests->search(undef, {columns => CONTEST_PUBLIC_COLUMNS, order_by => {-desc => 'start'}, prefetch => 'owner'});
- $rs = $rs->search({owner => $args{owner}}) if $args{owner};
- my %params;
- for ($rs->all) {
- my $state = $_->is_pending ? 'pending' : $_->is_running ? 'running' : 'finished';
- $params{$state} //= [];
- push @{$params{$state}}, { $_->get_columns, owner_name => $_->owner->name };
- }
- \%params
-}
-
-sub contest_entry_orig {
- my ($self, $id) = @_;
- my $ct = $self->contests->find($id,{columns => CONTEST_PUBLIC_COLUMNS});
- +{ $ct->get_columns, started => !$ct->is_pending, finished => $ct->is_finished, owner_name => $ct->owner->name }
-}
-
sub contest_list {
my ($self) = @_;
my $ret = $self->query('contest_list_sth')->hashes;
$self->query('contest_has_problem_sth')->flat
}
-sub job_list_orig {
- my ($self, %args) = @_;
- $args{page} //= 1;
- my $rs = $self->jobs->search(undef, {order_by => {-desc => 'me.id'}, prefetch => ['problem', 'owner', 'contest'], rows => JOBS_PER_PAGE, page => $args{page}});
- $rs = $rs->search({contest => $args{contest} || undef}) if exists $args{contest};
- $rs = $rs->search({'me.private'=> 0}) unless $args{private};
- $rs = $rs->search({'me.owner' => $args{owner}}) if $args{owner};
- $rs = $rs->search({problem => $args{problem}}) if $args{problem};
- $rs = $rs->search({result => $args{result}}) if defined $args{result};
- return {
- log => [map {
- my %params = $_->get_columns;
- $params{owner_name} = $_->owner->name;
- $params{problem_name} = $_->problem->name;
- $params{contest_name} = $_->contest->name if $params{contest};
- $params{results} &&= decode_json $params{results};
- $params{size} = length $params{source};
- delete $params{source};
- \%params
- } $rs->all],
- current_page => $rs->pager->current_page,
- maybe previous_page => $rs->pager->previous_page,
- maybe next_page => $rs->pager->next_page,
- maybe last_page => $rs->pager->last_page,
- }
-}
-
-sub job_entry_orig {
- my ($self, $id) = @_;
- my $job = $self->jobs->find($id, {prefetch => ['problem', 'owner', 'contest']});
- my %params = $job->get_columns;
- $params{owner_name} = $job->owner->name;
- $params{problem_name} = $job->problem->name;
- $params{contest_name} = $job->contest->name if $params{contest};
- $params{results} &&= decode_json $params{results};
- $params{size} = length $params{source};
- delete $params{source};
- \%params
-}
-
sub job_list {
my ($self, %args) = @_;
$args{page} //= 1;
}
}
-sub update_status_orig {
- my ($self) = @_;
- my @jobs = $self->jobs->search({'me.private' => 0}, {cache => 1, prefetch => 'problem', order_by => 'me.id'})->all;
-
- my %private;
- my %hash;
- for (@jobs) {
- my $pb = $_->get_column('problem');
- $private{$pb} //= $_->problem->private;
- next if $private{$pb};
- $hash{$pb, $_->get_column('owner')} = [$_->id, $_->result ? 0 : 1];
- }
-
- my @problem_statuses = map { [split ($;), @{$hash{$_}} ] } keys %hash;
-
- my @contest_statuses = map {
- my $contest = $_->id;
- map { [$contest, $_->{user}, $_->{score}, $_->{rank}] } $_->standings
- } $self->contests->all;
-
- my $txn = sub {
- $self->problem_statuses->delete;
- $self->problem_statuses->populate([[qw/problem owner job solved/], @problem_statuses]);
- $self->contest_statuses->delete;
- $self->contest_statuses->populate([[qw/contest owner score rank/], @contest_statuses]);
- };
-
- $self->txn_do($txn);
-}
-
sub update_status {
my ($self) = @_;
my $jobs = $self->{dbis}->select('jobs', 'id,owner,problem,result', {}, 'id');
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::Contest;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::Contest - List of contests
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<contests>
-
-=cut
-
-__PACKAGE__->table("contests");
-
-=head1 ACCESSORS
-
-=head2 id
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 name
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 editorial
-
- data_type: 'text'
- is_nullable: 1
-
-HTML fragment placed before the editorial
-
-=head2 description
-
- data_type: 'text'
- is_nullable: 1
-
-HTML fragment placed on contest page
-
-=head2 start
-
- data_type: 'integer'
- is_nullable: 0
-
-Unix time when contest starts
-
-=head2 stop
-
- data_type: 'integer'
- is_nullable: 0
-
-Unix time when contest ends
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "id",
- { data_type => "text", is_nullable => 0 },
- "name",
- { data_type => "text", is_nullable => 0 },
- "editorial",
- { data_type => "text", is_nullable => 1 },
- "description",
- { data_type => "text", is_nullable => 1 },
- "start",
- { data_type => "integer", is_nullable => 0 },
- "stop",
- { data_type => "integer", is_nullable => 0 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("id");
-
-=head1 RELATIONS
-
-=head2 contest_problems
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ContestProblem>
-
-=cut
-
-__PACKAGE__->has_many(
- "contest_problems",
- "Gruntmaster::Data::Result::ContestProblem",
- { "foreign.contest" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 contest_statuses
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ContestStatus>
-
-=cut
-
-__PACKAGE__->has_many(
- "contest_statuses",
- "Gruntmaster::Data::Result::ContestStatus",
- { "foreign.contest" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 jobs
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Job>
-
-=cut
-
-__PACKAGE__->has_many(
- "jobs",
- "Gruntmaster::Data::Result::Job",
- { "foreign.contest" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 opens
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Open>
-
-=cut
-
-__PACKAGE__->has_many(
- "opens",
- "Gruntmaster::Data::Result::Open",
- { "foreign.contest" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problems
-
-Type: many_to_many
-
-Composing rels: L</contest_problems> -> problem
-
-=cut
-
-__PACKAGE__->many_to_many("problems", "contest_problems", "problem");
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2015-02-14 10:52:58
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:UTfqBbyhmo0r1HyWtGXidA
-
-use Class::Method::Modifiers qw/after/;
-use List::Util qw/sum/;
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/ct/';
- Gruntmaster::Data::purge '/ct/' . $self->id;
-};
-
-sub is_pending {
- my ($self, $time) = @_;
- $self->start > ($time // time)
-}
-
-sub is_finished {
- my ($self, $time) = @_;
- $self->stop <= ($time // time)
-}
-
-sub is_running {
- my ($self, $time) = @_;
- !$self->is_pending($time) && !$self->is_finished($time)
-}
-
-sub calc_score{
- my ($mxscore, $time, $tries, $totaltime) = @_;
- my $score = $mxscore;
- $time = 0 if $time < 0;
- $time = 300 if $time > $totaltime;
- $score = ($totaltime - $time) / $totaltime * $score;
- $score -= $tries / 10 * $mxscore;
- $score = $mxscore * 3 / 10 if $score < $mxscore * 3 / 10;
- int $score + 0.5
-}
-
-sub standings {
- my ($self) = @_;
- my $ct = $self->id;
-
- my @problems = map { $_->rawproblem } $self->contest_problems->search({contest => $ct}, {qw/join problem order_by problem.value/});
- my (%scores, %tries, %opens);
- $opens{$_->rawproblem, $_->rawowner} = $_ for $self->opens->search({contest => $ct});
- for my $job ($self->jobs->search({contest => $ct, result => {'!=', undef}}, {qw/order_by me.id prefetch/ => [qw/problem/]})) {
- my $open = $opens{$job->rawproblem, $job->rawowner};
- my $time = $job->date - ($open ? $open->time : $self->start);
- next if $time < 0;
- my $value = $job->problem->value;
- my $factor = $job->result ? 0 : 1;
- $factor = $1 / 100 if $job->result_text =~ /^(\d+ )/s;
- $scores{$job->rawowner}{$job->rawproblem} = int ($factor * calc_score ($value, $time, $tries{$job->rawowner}{$job->rawproblem}++, $self->stop - $self->start));
- }
-
- my %user_to_name = map { $_->id => $_->name } $self->result_source->schema->users->all;
-
- my @st = sort { $b->{score} <=> $a->{score} or $a->{user} cmp $b->{user} } map { ## no critic (ProhibitReverseSortBlock)
- my $user = $_;
- +{
- user => $user,
- user_name => $user_to_name{$user},
- score => sum (values %{$scores{$user}}),
- scores => [map { $scores{$user}{$_} // '-'} @problems],
- }
- } keys %scores;
-
- $st[0]->{rank} = 1 if @st;
- $st[$_]->{rank} = $st[$_ - 1]->{rank} + ($st[$_]->{score} < $st[$_ - 1]->{score}) for 1 .. $#st;
- @st
-}
-
-1;
-
-__END__
-
-=head1 METHODS
-
-=head2 is_pending(I<[$time]>)
-
-Returns true if the contest is pending at time I<$time> (which defaults to C<time>).
-
-=head2 is_finished(I<[$time]>)
-
-Returns true if the contest is finished at time I<$time> (which defaults to C<time>).
-
-=head2 is_running(I<[$time]>)
-
-Returns true if the contest is running at time I<$time> (which defaults to C<time>).
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::ContestProblem;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::ContestProblem - Many-to-many bridge between contests and problems
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<contest_problems>
-
-=cut
-
-__PACKAGE__->table("contest_problems");
-
-=head1 ACCESSORS
-
-=head2 contest
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 problem
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "contest",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "problem",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</contest>
-
-=item * L</problem>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("contest", "problem");
-
-=head1 RELATIONS
-
-=head2 contest
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Contest>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "contest",
- "Gruntmaster::Data::Result::Contest",
- { id => "contest" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "problem",
- "Gruntmaster::Data::Result::Problem",
- { id => "problem" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-19 16:44:22
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:dTFBC3ZKB2T9SCiyQxxe2w
-
-use Class::Method::Modifiers qw/after/;
-
-sub rawcontest { shift->get_column('contest') }
-sub rawproblem { shift->get_column('problem') }
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/pb/';
- Gruntmaster::Data::purge '/pb/' . $self->rawproblem;
-};
-
-1;
-
-__END__
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::ContestStatus;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::ContestStatus - List of (contest, user, result)
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<contest_status>
-
-=cut
-
-__PACKAGE__->table("contest_status");
-
-=head1 ACCESSORS
-
-=head2 contest
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 score
-
- data_type: 'integer'
- is_nullable: 0
-
-=head2 rank
-
- data_type: 'integer'
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "contest",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "score",
- { data_type => "integer", is_nullable => 0 },
- "rank",
- { data_type => "integer", is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</owner>
-
-=item * L</contest>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("owner", "contest");
-
-=head1 RELATIONS
-
-=head2 contest
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Contest>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "contest",
- "Gruntmaster::Data::Result::Contest",
- { id => "contest" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-19 16:44:22
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:IkY4FNON0SrxrP8oNOXoHg
-
-use Class::Method::Modifiers qw/after/;
-
-sub rawowner { shift->get_column('owner') }
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/us/';
- Gruntmaster::Data::purge '/us/' . $self->rawowner;
-};
-
-1;
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::Job;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::Job - List of jobs
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<jobs>
-
-=cut
-
-__PACKAGE__->table("jobs");
-
-=head1 ACCESSORS
-
-=head2 id
-
- data_type: 'integer'
- is_auto_increment: 1
- is_nullable: 0
- sequence: 'jobs_id_seq'
-
-=head2 contest
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 1
-
-=head2 daemon
-
- data_type: 'text'
- is_nullable: 1
-
-hostname:PID of daemon that last executed this job. NULL if never executed
-
-=head2 date
-
- data_type: 'bigint'
- is_nullable: 0
-
-Unix time when job was submitted
-
-=head2 errors
-
- data_type: 'text'
- is_nullable: 1
-
-Compiler errors
-
-=head2 extension
-
- data_type: 'text'
- is_nullable: 0
-
-File extension of submitted program, without a leading dot
-
-=head2 format
-
- data_type: 'text'
- is_nullable: 0
-
-Format (programming language) of submitted program
-
-=head2 private
-
- data_type: 'boolean'
- default_value: false
- is_nullable: 0
-
-=head2 problem
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 reference
-
- data_type: 'integer'
- is_nullable: 1
-
-If not null, this is a reference solution that should get this result. For example, set reference=0 on jobs that should be accepted, reference=3 on jobs that should get TLE, etc
-
-=head2 result
-
- data_type: 'integer'
- is_nullable: 1
-
-Job result (integer constant from Gruntmaster::Daemon::Constants)
-
-=head2 result_text
-
- data_type: 'text'
- is_nullable: 1
-
-Job result (human-readable text)
-
-=head2 results
-
- data_type: 'text'
- is_nullable: 1
-
-Per-test results (JSON array of hashes with keys id (test number, counting from 1), result (integer constant from Gruntmaster::Daemon::Constants), result_text (human-readable text), time (execution time in decimal seconds))
-
-=head2 source
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "id",
- {
- data_type => "integer",
- is_auto_increment => 1,
- is_nullable => 0,
- sequence => "jobs_id_seq",
- },
- "contest",
- { data_type => "text", is_foreign_key => 1, is_nullable => 1 },
- "daemon",
- { data_type => "text", is_nullable => 1 },
- "date",
- { data_type => "bigint", is_nullable => 0 },
- "errors",
- { data_type => "text", is_nullable => 1 },
- "extension",
- { data_type => "text", is_nullable => 0 },
- "format",
- { data_type => "text", is_nullable => 0 },
- "private",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
- "problem",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "reference",
- { data_type => "integer", is_nullable => 1 },
- "result",
- { data_type => "integer", is_nullable => 1 },
- "result_text",
- { data_type => "text", is_nullable => 1 },
- "results",
- { data_type => "text", is_nullable => 1 },
- "source",
- { data_type => "text", is_nullable => 0 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("id");
-
-=head1 RELATIONS
-
-=head2 contest
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Contest>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "contest",
- "Gruntmaster::Data::Result::Contest",
- { id => "contest" },
- {
- is_deferrable => 0,
- join_type => "LEFT",
- on_delete => "CASCADE",
- on_update => "NO ACTION",
- },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "problem",
- "Gruntmaster::Data::Result::Problem",
- { id => "problem" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem_statuses
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ProblemStatus>
-
-=cut
-
-__PACKAGE__->has_many(
- "problem_statuses",
- "Gruntmaster::Data::Result::ProblemStatus",
- { "foreign.job" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2015-03-16 15:40:48
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:aaVaCgk198pT0kBGMefkkA
-
-use Class::Method::Modifiers qw/after/;
-
-sub rawcontest { shift->get_column('contest') }
-sub rawowner { shift->get_column('owner') }
-sub rawproblem { shift->get_column('problem') }
-
-sub rerun {
- shift->update({daemon => undef, result => -2, result_text => undef});
-}
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/us/';
- Gruntmaster::Data::purge '/us/' . $self->rawowner;
- Gruntmaster::Data::purge '/st/' . $self->rawcontest if $self->rawcontest;
- Gruntmaster::Data::purge '/log/';
- Gruntmaster::Data::purge '/log/' . $self->id;
-};
-
-1;
-
-__END__
-
-=head1 METHODS
-
-=head2 rerun
-
-Reruns this job.
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::Limit;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::Limit - Time limit overrides for certain problem/format pairs
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<limits>
-
-=cut
-
-__PACKAGE__->table("limits");
-
-=head1 ACCESSORS
-
-=head2 problem
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 format
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 timeout
-
- data_type: 'real'
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "problem",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "format",
- { data_type => "text", is_nullable => 0 },
- "timeout",
- { data_type => "real", is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</problem>
-
-=item * L</format>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("problem", "format");
-
-=head1 RELATIONS
-
-=head2 problem
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "problem",
- "Gruntmaster::Data::Result::Problem",
- { id => "problem" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2015-03-16 17:16:58
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:ewngP+tVnk4GZ5K+ygUpLg
-
-
-# You can replace this text with custom code or comments, and it will be preserved on regeneration
-1;
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::Open;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::Open
-
-=head1 DESCRIPTION
-
-List of (contest, problem, user, time when user opened problem)
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<opens>
-
-=cut
-
-__PACKAGE__->table("opens");
-
-=head1 ACCESSORS
-
-=head2 contest
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 problem
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 time
-
- data_type: 'bigint'
- is_nullable: 0
-
-=cut
-
-__PACKAGE__->add_columns(
- "contest",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "problem",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "time",
- { data_type => "bigint", is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</contest>
-
-=item * L</problem>
-
-=item * L</owner>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("contest", "problem", "owner");
-
-=head1 RELATIONS
-
-=head2 contest
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Contest>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "contest",
- "Gruntmaster::Data::Result::Contest",
- { id => "contest" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "problem",
- "Gruntmaster::Data::Result::Problem",
- { id => "problem" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-19 16:44:22
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:jAao0vjOW87mO37ZQhm4Cw
-
-use Class::Method::Modifiers qw/after/;
-
-sub rawcontest { shift->get_column('contest') }
-sub rawowner { shift->get_column('owner') }
-sub rawproblem { shift->get_column('problem') }
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/st/' . $self->rawcontest;
-};
-
-1;
-
-__END__
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::Problem;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::Problem - List of problems
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<problems>
-
-=cut
-
-__PACKAGE__->table("problems");
-
-=head1 ACCESSORS
-
-=head2 id
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 author
-
- data_type: 'text'
- is_nullable: 1
-
-Full name(s) of problem author(s)/problemsetter(s)/tester(s)/etc
-
-=head2 writer
-
- data_type: 'text'
- is_nullable: 1
-
-Full name(s) of statement writer(s) (DEPRECATED)
-
-=head2 generator
-
- data_type: 'text'
- is_nullable: 0
-
-Generator class, without the leading Gruntmaster::Daemon::Generator::
-
-=head2 judge
-
- data_type: 'text'
- is_nullable: 0
-
-Judge class, without the leading Gruntmaster::Daemon::Judge::
-
-=head2 level
-
- data_type: 'text'
- is_nullable: 0
-
-Problem level, one of beginner, easy, medium, hard
-
-=head2 name
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 olimit
-
- data_type: 'integer'
- is_nullable: 1
-
-Output limit (in bytes)
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 private
-
- data_type: 'boolean'
- default_value: false
- is_nullable: 0
-
-=head2 runner
-
- data_type: 'text'
- is_nullable: 0
-
-Runner class, without the leading Gruntmaster::Daemon::Runner::
-
-=head2 solution
-
- data_type: 'text'
- is_nullable: 1
-
-Solution (HTML)
-
-=head2 statement
-
- data_type: 'text'
- is_nullable: 0
-
-Statement (HTML)
-
-=head2 testcnt
-
- data_type: 'integer'
- is_nullable: 0
-
-Number of tests
-
-=head2 precnt
-
- data_type: 'integer'
- is_nullable: 1
-
-Number of pretests. NULL indicates full feedback.
-
-=head2 tests
-
- data_type: 'text'
- is_nullable: 1
-
-JSON array of test values for ::Runner::File
-
-=head2 timeout
-
- data_type: 'real'
- is_nullable: 0
-
-Time limit (in seconds)
-
-=head2 value
-
- data_type: 'integer'
- is_nullable: 0
-
-Problem value when used in a contest.
-
-=head2 genformat
-
- data_type: 'text'
- is_nullable: 1
-
-Format (programming language) of the generator if using the Run generator
-
-=head2 gensource
-
- data_type: 'text'
- is_nullable: 1
-
-Source code of generator if using the Run generator
-
-=head2 verformat
-
- data_type: 'text'
- is_nullable: 1
-
-Format (programming language) of the verifier if using the Verifier runner
-
-=head2 versource
-
- data_type: 'text'
- is_nullable: 1
-
-Source code of verifier if using the Verifier runner
-
-=cut
-
-__PACKAGE__->add_columns(
- "id",
- { data_type => "text", is_nullable => 0 },
- "author",
- { data_type => "text", is_nullable => 1 },
- "writer",
- { data_type => "text", is_nullable => 1 },
- "generator",
- { data_type => "text", is_nullable => 0 },
- "judge",
- { data_type => "text", is_nullable => 0 },
- "level",
- { data_type => "text", is_nullable => 0 },
- "name",
- { data_type => "text", is_nullable => 0 },
- "olimit",
- { data_type => "integer", is_nullable => 1 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "private",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
- "runner",
- { data_type => "text", is_nullable => 0 },
- "solution",
- { data_type => "text", is_nullable => 1 },
- "statement",
- { data_type => "text", is_nullable => 0 },
- "testcnt",
- { data_type => "integer", is_nullable => 0 },
- "precnt",
- { data_type => "integer", is_nullable => 1 },
- "tests",
- { data_type => "text", is_nullable => 1 },
- "timeout",
- { data_type => "real", is_nullable => 0 },
- "value",
- { data_type => "integer", is_nullable => 0 },
- "genformat",
- { data_type => "text", is_nullable => 1 },
- "gensource",
- { data_type => "text", is_nullable => 1 },
- "verformat",
- { data_type => "text", is_nullable => 1 },
- "versource",
- { data_type => "text", is_nullable => 1 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("id");
-
-=head1 RELATIONS
-
-=head2 contest_problems
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ContestProblem>
-
-=cut
-
-__PACKAGE__->has_many(
- "contest_problems",
- "Gruntmaster::Data::Result::ContestProblem",
- { "foreign.problem" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 jobs
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Job>
-
-=cut
-
-__PACKAGE__->has_many(
- "jobs",
- "Gruntmaster::Data::Result::Job",
- { "foreign.problem" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 limits
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Limit>
-
-=cut
-
-__PACKAGE__->has_many(
- "limits",
- "Gruntmaster::Data::Result::Limit",
- { "foreign.problem" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 opens
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Open>
-
-=cut
-
-__PACKAGE__->has_many(
- "opens",
- "Gruntmaster::Data::Result::Open",
- { "foreign.problem" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem_statuses
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ProblemStatus>
-
-=cut
-
-__PACKAGE__->has_many(
- "problem_statuses",
- "Gruntmaster::Data::Result::ProblemStatus",
- { "foreign.problem" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 contests
-
-Type: many_to_many
-
-Composing rels: L</contest_problems> -> contest
-
-=cut
-
-__PACKAGE__->many_to_many("contests", "contest_problems", "contest");
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2015-03-16 17:16:58
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:N7cuqDEGSn5rf8V5GovRQQ
-
-use Class::Method::Modifiers qw/after/;
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/pb/';
- Gruntmaster::Data::purge '/pb/' . $self->id;
- Gruntmaster::Data::purge '/sol/' . $self->id;
-};
-
-sub rerun {
- $_->rerun for shift->jobs
-}
-
-1;
-
-__END__
-
-=head1 METHODS
-
-=head2 rerun
-
-Reruns all jobs for this problem.
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::ProblemStatus;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::ProblemStatus - List of (problem, user, result)
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<problem_status>
-
-=cut
-
-__PACKAGE__->table("problem_status");
-
-=head1 ACCESSORS
-
-=head2 problem
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 owner
-
- data_type: 'text'
- is_foreign_key: 1
- is_nullable: 0
-
-=head2 job
-
- data_type: 'integer'
- is_auto_increment: 1
- is_foreign_key: 1
- is_nullable: 0
- sequence: 'problem_status_job_seq'
-
-=head2 solved
-
- data_type: 'boolean'
- default_value: false
- is_nullable: 0
-
-True if the result is Accepted, False otherwise
-
-=cut
-
-__PACKAGE__->add_columns(
- "problem",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "owner",
- { data_type => "text", is_foreign_key => 1, is_nullable => 0 },
- "job",
- {
- data_type => "integer",
- is_auto_increment => 1,
- is_foreign_key => 1,
- is_nullable => 0,
- sequence => "problem_status_job_seq",
- },
- "solved",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</owner>
-
-=item * L</problem>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("owner", "problem");
-
-=head1 RELATIONS
-
-=head2 job
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Job>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "job",
- "Gruntmaster::Data::Result::Job",
- { id => "job" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 owner
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::User>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "owner",
- "Gruntmaster::Data::Result::User",
- { id => "owner" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-=head2 problem
-
-Type: belongs_to
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->belongs_to(
- "problem",
- "Gruntmaster::Data::Result::Problem",
- { id => "problem" },
- { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-19 16:44:22
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1OCTO6sM27DamVhQi3dWKg
-
-use Class::Method::Modifiers qw/after/;
-
-sub rawowner { shift->get_column('owner') }
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/us/';
- Gruntmaster::Data::purge '/us/' . $self->rawowner;
-};
-
-1;
+++ /dev/null
-use utf8;
-package Gruntmaster::Data::Result::User;
-
-# Created by DBIx::Class::Schema::Loader
-# DO NOT MODIFY THE FIRST PART OF THIS FILE
-
-=head1 NAME
-
-Gruntmaster::Data::Result::User - List of users
-
-=cut
-
-use strict;
-use warnings;
-
-use base 'DBIx::Class::Core';
-
-=head1 TABLE: C<users>
-
-=cut
-
-__PACKAGE__->table("users");
-
-=head1 ACCESSORS
-
-=head2 id
-
- data_type: 'text'
- is_nullable: 0
-
-=head2 passphrase
-
- data_type: 'text'
- is_nullable: 1
-
-RFC2307-encoded passphrase
-
-=head2 admin
-
- data_type: 'boolean'
- default_value: false
- is_nullable: 0
-
-=head2 name
-
- data_type: 'text'
- is_nullable: 1
-
-Full name of user
-
-=head2 email
-
- data_type: 'text'
- is_nullable: 1
-
-=head2 phone
-
- data_type: 'text'
- is_nullable: 1
-
-=head2 town
-
- data_type: 'text'
- is_nullable: 1
-
-=head2 university
-
- data_type: 'text'
- is_nullable: 1
-
-=head2 level
-
- data_type: 'text'
- is_nullable: 1
-
-Highschool, Undergraduate, Master, Doctorate or Other
-
-=head2 country
-
- data_type: 'text'
- is_nullable: 1
-
-=head2 lastjob
-
- data_type: 'bigint'
- is_nullable: 1
-
-Unix time when this user last submitted a job
-
-=head2 since
-
- data_type: 'bigint'
- default_value: (date_part('epoch'::text, now()))::bigint
- is_nullable: 1
-
-Unix time when this user was created
-
-=cut
-
-__PACKAGE__->add_columns(
- "id",
- { data_type => "text", is_nullable => 0 },
- "passphrase",
- { data_type => "text", is_nullable => 1 },
- "admin",
- { data_type => "boolean", default_value => \"false", is_nullable => 0 },
- "name",
- { data_type => "text", is_nullable => 1 },
- "email",
- { data_type => "text", is_nullable => 1 },
- "phone",
- { data_type => "text", is_nullable => 1 },
- "town",
- { data_type => "text", is_nullable => 1 },
- "university",
- { data_type => "text", is_nullable => 1 },
- "level",
- { data_type => "text", is_nullable => 1 },
- "country",
- { data_type => "text", is_nullable => 1 },
- "lastjob",
- { data_type => "bigint", is_nullable => 1 },
- "since",
- {
- data_type => "bigint",
- default_value => \"(date_part('epoch'::text, now()))::bigint",
- is_nullable => 1,
- },
-);
-
-=head1 PRIMARY KEY
-
-=over 4
-
-=item * L</id>
-
-=back
-
-=cut
-
-__PACKAGE__->set_primary_key("id");
-
-=head1 RELATIONS
-
-=head2 contest_statuses
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ContestStatus>
-
-=cut
-
-__PACKAGE__->has_many(
- "contest_statuses",
- "Gruntmaster::Data::Result::ContestStatus",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 contests
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Contest>
-
-=cut
-
-__PACKAGE__->has_many(
- "contests",
- "Gruntmaster::Data::Result::Contest",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 jobs
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Job>
-
-=cut
-
-__PACKAGE__->has_many(
- "jobs",
- "Gruntmaster::Data::Result::Job",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 opens
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Open>
-
-=cut
-
-__PACKAGE__->has_many(
- "opens",
- "Gruntmaster::Data::Result::Open",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 problem_statuses
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::ProblemStatus>
-
-=cut
-
-__PACKAGE__->has_many(
- "problem_statuses",
- "Gruntmaster::Data::Result::ProblemStatus",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-=head2 problems
-
-Type: has_many
-
-Related object: L<Gruntmaster::Data::Result::Problem>
-
-=cut
-
-__PACKAGE__->has_many(
- "problems",
- "Gruntmaster::Data::Result::Problem",
- { "foreign.owner" => "self.id" },
- { cascade_copy => 0, cascade_delete => 0 },
-);
-
-
-# Created by DBIx::Class::Schema::Loader v0.07042 @ 2015-02-10 18:42:04
-# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:L/ExLdA0pkJ1DeM+RzlDjw
-
-use Bytes::Random::Secure qw/random_bytes/;
-use Class::Method::Modifiers qw/after/;
-use Digest::SHA qw/hmac_sha1_base64/;
-
-after qw/insert update delete/ => sub {
- my ($self) = @_;
- Gruntmaster::Data::purge '/us/';
- Gruntmaster::Data::purge '/us/' . $self->id;
-};
-
-use Authen::Passphrase;
-use Authen::Passphrase::BlowfishCrypt;
-
-sub check_passphrase {
- my ($self, $pw) = @_;
- Authen::Passphrase->from_rfc2307($self->passphrase)->match($pw)
-}
-
-sub set_passphrase {
- my ($self, $pw) = @_;
- $self->update({passphrase => Authen::Passphrase::BlowfishCrypt->new(
- cost => 10,
- passphrase => $pw,
- salt_random => 1,
- )->as_rfc2307});
-}
-
-my $hmackey = $ENV{GRUNTMASTER_HMAC_KEY};
-
-sub make_reset_hmac {
- my ($self, $expire) = @_;
- $expire //= time + 60 * 60;
- $hmackey //= random_bytes 512;
- my $hmac = hmac_sha1_base64 $self->id . " $expire " . $self->passphrase, $hmackey;
- wantarray ? ($hmac, $expire) : $hmac
-}
-
-1;
-
-__END__
-
-=head1 METHODS
-
-=head2 check_passphrase(I<$passphrase>)
-
-Returns true if I<$passphrase> is the correct passphrase, false otherwise.
-
-=head2 set_passphrase(I<$passphrase>)
-
-Changes the passphrase to I<$passphrase>.
-
-=head1 AUTHOR
-
-Marius Gavrilescu E<lt>marius@ieval.roE<gt>
-
-=head1 COPYRIGHT AND LICENSE
-
-Copyright (C) 2014 by Marius Gavrilescu
-
-This library is free software; you can redistribute it and/or modify
-it under the same terms as Perl itself, either Perl version 5.18.1 or,
-at your option, any later version of Perl 5 you may have available.
-
-
-=cut
#!/usr/bin/perl -w
use v5.14;
-use Test::More tests => 6;
+use Test::More tests => 1;
BEGIN { use_ok('Gruntmaster::Data') };
-
-my $db = Gruntmaster::Data->connect('dbi:SQLite:dbname=:memory:');
-$db->deploy;
-
-$db->users->create({id => 'MGV'});
-$db->contests->create({id => 'fc', start => 10, stop => 20, name => 'Finished contest', owner => 'MGV'});
-$db->contests->create({id => 'rc', start => 20, stop => 30, name => 'Running contest', owner => 'MGV'});
-$db->contests->create({id => 'pc', start => 30, stop => 40, name => 'Pending contest', owner => 'MGV'});
-
-ok $db->contest('pc')->is_pending(25), 'is_pending';
-ok !$db->contest('rc')->is_pending(25), '!is_pending';
-ok $db->contest('fc')->is_finished(25), 'is_finished';
-ok !$db->contest('rc')->is_finished(25), '!is_finished';
-ok $db->contest('rc')->is_running(25), 'is_running';