From adb42d4d148fdb3dd145e4a7452b7b7eda88f66c Mon Sep 17 00:00:00 2001 From: Marius Gavrilescu Date: Fri, 12 Dec 2014 13:22:32 +0200 Subject: [PATCH] Add problem_status, contest_status and a method that updates them --- db.sql | 18 +++ lib/Gruntmaster/Data.pm | 30 +++- lib/Gruntmaster/Data/Result/Contest.pm | 19 ++- lib/Gruntmaster/Data/Result/ContestStatus.pm | 113 +++++++++++++++ lib/Gruntmaster/Data/Result/Job.pm | 19 ++- lib/Gruntmaster/Data/Result/Problem.pm | 19 ++- lib/Gruntmaster/Data/Result/ProblemStatus.pm | 138 +++++++++++++++++++ lib/Gruntmaster/Data/Result/User.pm | 34 ++++- 8 files changed, 380 insertions(+), 10 deletions(-) create mode 100644 lib/Gruntmaster/Data/Result/ContestStatus.pm create mode 100644 lib/Gruntmaster/Data/Result/ProblemStatus.pm diff --git a/db.sql b/db.sql index 1556202..696cec1 100644 --- a/db.sql +++ b/db.sql @@ -20,6 +20,15 @@ CREATE TABLE contests ( CONSTRAINT positive_duration CHECK (stop > start) ); +CREATE TABLE contest_status ( + contest TEXT NOT NULL REFERENCES contests ON DELETE CASCADE, + owner TEXT NOT NULL REFERENCES users ON DELETE CASCADE, + score INT NOT NULL, + rank INT NOT NULL, + + PRIMARY KEY (owner, contest) +); + CREATE TABLE problems ( id TEXT PRIMARY KEY, author TEXT, @@ -67,6 +76,15 @@ CREATE TABLE jobs ( owner TEXT NOT NULL REFERENCES users ON DELETE CASCADE ); +CREATE TABLE problem_status ( + problem TEXT NOT NULL REFERENCES problems ON DELETE CASCADE, + owner TEXT NOT NULL REFERENCES users ON DELETE CASCADE, + job SERIAL NOT NULL REFERENCES jobs ON DELETE CASCADE, + solved BOOLEAN NOT NULL DEFAULT FALSE, + + PRIMARY KEY (owner, problem) +); + CREATE TABLE opens ( contest TEXT NOT NULL REFERENCES contests ON DELETE CASCADE, problem TEXT NOT NULL REFERENCES problems ON DELETE CASCADE, diff --git a/lib/Gruntmaster/Data.pm b/lib/Gruntmaster/Data.pm index 9cb313d..2422e77 100644 --- a/lib/Gruntmaster/Data.pm +++ b/lib/Gruntmaster/Data.pm @@ -34,7 +34,7 @@ sub dynsub{ } BEGIN { - for my $rs (qw/contest contest_problem job open problem user/) { + for my $rs (qw/contest contest_problem job open 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) }; @@ -96,7 +96,10 @@ sub user_list { sub user_entry { my ($self, $id) = @_; - +{ $self->users->find($id, {columns => USER_PUBLIC_COLUMNS})->get_columns } + 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; + my @contests = map { {contest => $_->get_column('contest'), rank => $_->rank, score => $_->score} } $user->contest_statuses; + +{ $user->get_columns, problems => \@problems, contests => \@contests } } sub problem_list { @@ -187,6 +190,29 @@ sub job_entry { \%params } +sub update_status { + my ($self) = @_; + my @jobs = $self->jobs->search(undef, {cache => 1})->all; + my %hash; + $hash{$_->get_column('problem'), $_->get_column('owner')} = [$_, $_->result ? 1 : 0] for @jobs; + my @problem_statuses = map { [split ($;), @{$hash{$_}} ] } keys %hash; + + my @contest_statuses = map { + my $contest = $_->id; + my @standings = $self->standings($contest); + 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); +} + 1; __END__ diff --git a/lib/Gruntmaster/Data/Result/Contest.pm b/lib/Gruntmaster/Data/Result/Contest.pm index 166d544..5933443 100644 --- a/lib/Gruntmaster/Data/Result/Contest.pm +++ b/lib/Gruntmaster/Data/Result/Contest.pm @@ -93,6 +93,21 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +=head2 contest_statuses + +Type: has_many + +Related object: L + +=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 @@ -149,8 +164,8 @@ Composing rels: L -> problem __PACKAGE__->many_to_many("problems", "contest_problems", "problem"); -# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-05-16 15:03:32 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:8PPzBpDmSTq4ukKuxIlLlQ +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:nu+Io9AhYkzYCky5UpCaKQ sub is_pending { my ($self, $time) = @_; diff --git a/lib/Gruntmaster/Data/Result/ContestStatus.pm b/lib/Gruntmaster/Data/Result/ContestStatus.pm new file mode 100644 index 0000000..dae7cbe --- /dev/null +++ b/lib/Gruntmaster/Data/Result/ContestStatus.pm @@ -0,0 +1,113 @@ +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 + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=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 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("owner", "contest"); + +=head1 RELATIONS + +=head2 contest + +Type: belongs_to + +Related object: L + +=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 + +=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-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:vfOfZeATPRODifpgHO4L0A + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/lib/Gruntmaster/Data/Result/Job.pm b/lib/Gruntmaster/Data/Result/Job.pm index 0bb76b9..66aed55 100644 --- a/lib/Gruntmaster/Data/Result/Job.pm +++ b/lib/Gruntmaster/Data/Result/Job.pm @@ -201,9 +201,24 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" }, ); +=head2 problem_statuses -# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-05-16 15:03:32 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:k3Oq7pNqFoCI5NwY5GaWfQ +Type: has_many + +Related object: L + +=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 @ 2014-12-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:D49ekK0vGg/7b8xXZoYTWQ sub rerun { shift->update({daemon => undef, result => -2, result_text => undef}); diff --git a/lib/Gruntmaster/Data/Result/Problem.pm b/lib/Gruntmaster/Data/Result/Problem.pm index 098701e..6359b99 100644 --- a/lib/Gruntmaster/Data/Result/Problem.pm +++ b/lib/Gruntmaster/Data/Result/Problem.pm @@ -251,6 +251,21 @@ __PACKAGE__->belongs_to( { is_deferrable => 0, on_delete => "CASCADE", on_update => "NO ACTION" }, ); +=head2 problem_statuses + +Type: has_many + +Related object: L + +=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 @@ -262,8 +277,8 @@ Composing rels: L -> contest __PACKAGE__->many_to_many("contests", "contest_problems", "contest"); -# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-07 00:51:56 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:KjAtOerTqBqtcMrBtwJ3Bw +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:1SnNCeJdFr5lM3mmO6rtqA sub is_private { my ($self, $time) = @_; diff --git a/lib/Gruntmaster/Data/Result/ProblemStatus.pm b/lib/Gruntmaster/Data/Result/ProblemStatus.pm new file mode 100644 index 0000000..09920a7 --- /dev/null +++ b/lib/Gruntmaster/Data/Result/ProblemStatus.pm @@ -0,0 +1,138 @@ +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 + +=cut + +use strict; +use warnings; + +use base 'DBIx::Class::Core'; + +=head1 TABLE: C + +=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 + +=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 + +=item * L + +=back + +=cut + +__PACKAGE__->set_primary_key("owner", "problem"); + +=head1 RELATIONS + +=head2 job + +Type: belongs_to + +Related object: L + +=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 + +=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 + +=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-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:SUAwYQhgBtoCjtFSOMc4FQ + + +# You can replace this text with custom code or comments, and it will be preserved on regeneration +1; diff --git a/lib/Gruntmaster/Data/Result/User.pm b/lib/Gruntmaster/Data/Result/User.pm index 54e6b52..c5547c1 100644 --- a/lib/Gruntmaster/Data/Result/User.pm +++ b/lib/Gruntmaster/Data/Result/User.pm @@ -113,6 +113,21 @@ __PACKAGE__->set_primary_key("id"); =head1 RELATIONS +=head2 contest_statuses + +Type: has_many + +Related object: L + +=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 @@ -158,6 +173,21 @@ __PACKAGE__->has_many( { cascade_copy => 0, cascade_delete => 0 }, ); +=head2 problem_statuses + +Type: has_many + +Related object: L + +=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 @@ -174,8 +204,8 @@ __PACKAGE__->has_many( ); -# Created by DBIx::Class::Schema::Loader v0.07039 @ 2014-05-16 15:23:08 -# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:Cho4zmn58Mytf2jHvgP+4g +# Created by DBIx::Class::Schema::Loader v0.07042 @ 2014-12-11 23:51:27 +# DO NOT MODIFY THIS OR ANYTHING ABOVE! md5sum:JcVHC/n8J+NgJge9LkckYA use Authen::Passphrase; use Authen::Passphrase::BlowfishCrypt; -- 2.30.2