From 0e5d1bbf468035c98c012ad1cc49dd495d97c2ec Mon Sep 17 00:00:00 2001 From: Thomas Date: Fri, 17 Apr 2020 20:54:21 +1200 Subject: [PATCH 1/6] Show all results publiclly. Previously students results would only be shown on the public scoreboard if equal to or better than the median score. --- app/views/contests/scoreboard.html.erb | 4 ---- 1 file changed, 4 deletions(-) diff --git a/app/views/contests/scoreboard.html.erb b/app/views/contests/scoreboard.html.erb index 1b54bce2..81e366e9 100644 --- a/app/views/contests/scoreboard.html.erb +++ b/app/views/contests/scoreboard.html.erb @@ -35,13 +35,9 @@ - <% median = @scoreboard[@scoreboard.length/2-1] %> <% rank = 1 %> <% previous_record = @scoreboard.first %> <% @scoreboard.each_with_index do |record,index| %> - <% if !user_signed_in? or record.user && record.user.id != current_user.id && !policy(@contest).inspect? %> - <% next if record.score < median.score || (record.score == median.score && record.time_taken > median.time_taken) # no permission to view %> - <% end %> class="emphasized"<% end %>> <% if record.user %> From f3fdfabcdb4745e62e6b291f774f0eadda8b493b Mon Sep 17 00:00:00 2001 From: puqeko <12654833+puqeko@users.noreply.github.com> Date: Fri, 17 Apr 2020 23:32:16 +1200 Subject: [PATCH 2/6] Simplify compilation commands (#70) Remove /usr/bin prefix from compile commands (#70) Since commit 32dcf29 (add Java support, 2014-12-25), the compilation commands are executed using bash instead of directly using isolate. They no longer need the first argument to be the full path to the compiler. Note that the interpreter commands are still executed directly using isolate and need to keep using the full path to the interpreter. Co-authored-by: Tom Levy --- db/languages.yml | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/db/languages.yml b/db/languages.yml index d2b41755..e27ec4b7 100644 --- a/db/languages.yml +++ b/db/languages.yml @@ -2,6 +2,9 @@ # database stores the variants and their language group # programs will reference a language variant, and will be upgraded if their behaviour is the same across multiple versions +# compiler_command is a shell command executed using bash (see Language#compile) +# interpreter_command is executed directly using 'isolate' (so the first argument must be the full path to the interpreter) + c++: :name: "C++" :lexer: c++ @@ -15,19 +18,19 @@ c++: :variants: c++03: # deprecated :name: "C++03" - :compiler: /usr/bin/g++ + :compiler: g++ :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu++03 -O2 -o %{output} %{source} -lm" c++11: :name: "C++11" - :compiler: /usr/bin/g++ + :compiler: g++ :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu++11 -O2 -o %{output} %{source} -lm" c++14: # Changes since C++11: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p1319r0.html :name: "C++14" - :compiler: /usr/bin/g++ + :compiler: g++ :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu++14 -O2 -o %{output} %{source} -lm" c++17: # Changes since C++14: https://isocpp.org/files/papers/p0636r0.html :name: "C++17" - :compiler: /usr/bin/g++ + :compiler: g++ :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu++17 -O2 -o %{output} %{source} -lm" c: :name: "C" @@ -42,11 +45,11 @@ c: :variants: c99: # deprecated :name: C99 - :compiler: /usr/bin/gcc + :compiler: gcc :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu99 -O2 -o %{output} %{source} -lm" c11: # Changes since c99: https://en.wikipedia.org/wiki/C11_(C_standard_revision) :name: C11 - :compiler: /usr/bin/gcc + :compiler: gcc :compiler_command: "%{compiler} --version | head -n 1 1>&2 && %{compiler} -std=gnu11 -O2 -o %{output} %{source} -lm" java: @@ -62,13 +65,13 @@ java: :variants: java6: :name: Java 1.6 # deprecated (note: uses '-source 1.6', which will be removed in a future JDK release) - :compiler: /usr/bin/javac;/usr/bin/jar + :compiler: javac;jar :compiler_command: '%{compiler[0]} -version | head -n 1 1>&2 && %{compiler[0]} -O -source 1.6 -J-Xms16m -J-Xmx256m %{source} && %{compiler[1]} cfe %{output} Main -C %{source_dir} .' :interpreter: /usr/bin/java :interpreter_command: '%{interpreter} -jar %{source}' java11: :name: Java 11 - :compiler: /usr/bin/javac;/usr/bin/jar + :compiler: javac;jar :compiler_command: '%{compiler[0]} -version | head -n 1 1>&2 && %{compiler[0]} -O -source 11 -J-Xms16m -J-Xmx256m %{source} && %{compiler[1]} cfe %{output} Main -C %{source_dir} .' :interpreter: /usr/bin/java :interpreter_command: '%{interpreter} -jar %{source}' @@ -85,7 +88,7 @@ haskell: :variants: haskell2010: :name: "Haskell 2010" - :compiler: /usr/bin/ghc + :compiler: ghc :compiler_command: '%{compiler} --version 1>&2 && %{compiler} --make -O2 -o %{output} %{source} -lm' python: :name: Python @@ -168,6 +171,6 @@ csharp: :variants: csharp8: :name: "C# 8.0" - :compiler: /usr/local/bin/dotnet-csc # custom shell script (also prints SDK version number) + :compiler: dotnet-csc # custom shell script (also prints SDK version number) :compiler_command: '%{compiler} %{source} -optimize+ -out:%{output} -langversion:8.0 -nologo' :interpreter_command: '%{interpreter} %{source}' From fe28dc734c05351c494b05ac88963e57a24ea393 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Apr 2020 20:28:24 +1200 Subject: [PATCH 3/6] Add description about Public/Protected/Private to new contest form. --- app/views/contests/_form.html.erb | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/app/views/contests/_form.html.erb b/app/views/contests/_form.html.erb index edc4d545..48394f4a 100644 --- a/app/views/contests/_form.html.erb +++ b/app/views/contests/_form.html.erb @@ -29,11 +29,18 @@
<%= f.label :duration %>
- <%= f.text_field :duration %> + <%= f.text_field :duration, :value=>3.0 %> hours
<%= f.label :observation %>
- <%= f.select :observation, Contest::OBSERVATION.entries.invert %> + <%= f.select :observation, Contest::OBSERVATION.entries.invert %>
+ Students can only join a contest if they belong to a group that the contest also belongs to. +
    +
  • Public: Anyone can see the contest.
  • +
  • Protected: Only those in one of the contest's groups can see the contest.
  • +
  • Private: Only those explicitly added as competitors can see the contest.
  • +
+
<%= f.label :startcode %>
From af301f9d98c35688fec6d0f5065079d4533b91e2 Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Apr 2020 20:31:44 +1200 Subject: [PATCH 4/6] Add 'hours' and remove owner id --- app/views/contests/_index.html.erb | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/app/views/contests/_index.html.erb b/app/views/contests/_index.html.erb index 71e1321d..51784528 100644 --- a/app/views/contests/_index.html.erb +++ b/app/views/contests/_index.html.erb @@ -5,7 +5,6 @@ Start time End time Duration - User Score <% if policy(Contest).update? %> @@ -27,8 +26,7 @@ <%= contest.name %> <%= contest.start_time.strftime("%b %d, %H:%M") unless contest.start_time.nil? %> <%= contest.end_time.strftime("%b %d, %H:%M") unless contest.end_time.nil? %> - <%= contest.duration %> - <%= contest.owner_id %> + <%= contest.duration %> hours <%= contest.get_score(current_user.id) if user_signed_in? %> <% if contest.is_running? && (policy(contest).start?) %> From e1384a5d4bc5a4bf22f8ef00f175d709d2a945cc Mon Sep 17 00:00:00 2001 From: Thomas Date: Sat, 18 Apr 2020 20:49:08 +1200 Subject: [PATCH 5/6] Show contest problem set --- app/views/contests/_admin.html.erb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/views/contests/_admin.html.erb b/app/views/contests/_admin.html.erb index 67178654..7916b8b0 100644 --- a/app/views/contests/_admin.html.erb +++ b/app/views/contests/_admin.html.erb @@ -16,3 +16,7 @@ <% end %> +

+ Problem set: + <%= link_to @contest.problem_set.name, @contest.problem_set %> +

\ No newline at end of file From 6a1414a0bdb53c84e054c733ae22b3889a30c61a Mon Sep 17 00:00:00 2001 From: Thomas Date: Sun, 19 Apr 2020 01:17:32 +1200 Subject: [PATCH 6/6] Update contest scoreboard and edit page plus remove info tab. - Add two boolean feilds to the database live_scoreboard: If true, show problem scores on the live scoreboard show_unofficial_competitors: Mark non highschool students on scoreboard - Add these to the contest edit form - Update the scoreboard page itself Also: - Removed the contest info tab because it seems useless - Set the default tab to scoreboard if logged out - No longer show Owner ID from contest information - Use "hours" so that the duration setting is more clear --- app/assets/stylesheets/main_table.css | 3 + app/controllers/contests_controller.rb | 13 +-- app/views/contests/_form.html.erb | 10 +- app/views/contests/edit.html.erb | 11 +-- app/views/contests/info.html.erb | 20 ---- app/views/contests/scoreboard.html.erb | 98 ++++++++++++------- app/views/layouts/contest.html.erb | 4 +- ...0200418113600_add_live_scoreboard_field.rb | 5 + .../20200418113601_add_offical_competitors.rb | 5 + db/schema.rb | 10 +- 10 files changed, 93 insertions(+), 86 deletions(-) delete mode 100644 app/views/contests/info.html.erb create mode 100644 db/migrate/20200418113600_add_live_scoreboard_field.rb create mode 100644 db/migrate/20200418113601_add_offical_competitors.rb diff --git a/app/assets/stylesheets/main_table.css b/app/assets/stylesheets/main_table.css index dfc0f782..b8c1f7ad 100644 --- a/app/assets/stylesheets/main_table.css +++ b/app/assets/stylesheets/main_table.css @@ -70,3 +70,6 @@ table.main_table > thead > tr > th { font-weight: bold; } +.unofficial > td { + opacity: 0.4; +} \ No newline at end of file diff --git a/app/controllers/contests_controller.rb b/app/controllers/contests_controller.rb index d08a58b6..0511962c 100644 --- a/app/controllers/contests_controller.rb +++ b/app/controllers/contests_controller.rb @@ -1,7 +1,7 @@ class ContestsController < ApplicationController def permitted_params @_permitted_params ||= begin - permitted_attributes = [:name, :start_time, :end_time, :duration, :problem_set_id, :startcode, :observation] + permitted_attributes = [:name, :start_time, :end_time, :duration, :problem_set_id, :startcode, :observation, :live_scoreboard, :show_unofficial_competitors] permitted_attributes << :owner_id if policy(@contest || Contest).transfer? params.require(:contest).permit(*permitted_attributes) end @@ -49,7 +49,7 @@ def browse def show @contest = Contest.find(params[:id]) if !policy(@contest).overview? - redirect_to info_contest_path(@contest) + redirect_to scoreboard_contest_path(@contest) return end @problem_associations = @contest.problem_set.problem_associations.includes(:problem) @@ -64,15 +64,6 @@ def show render :layout => 'contest' end - def info - @contest = Contest.find(params[:id]) - authorize @contest, :show? - @groups = Group.all - @contest_relation = @contest.get_relation(current_user.id) if user_signed_in? - - render :layout => 'contest' - end - def scoreboard @contest = Contest.find(params[:id]) authorize @contest, :scoreboard? diff --git a/app/views/contests/_form.html.erb b/app/views/contests/_form.html.erb index 48394f4a..1f6a77d7 100644 --- a/app/views/contests/_form.html.erb +++ b/app/views/contests/_form.html.erb @@ -53,8 +53,16 @@ <% else %> <%= handle(@contest.owner) %> <% end %> -
+
+ <%= f.label :live_scoreboard %> - If true, individual problem scores are shown on the live scoreboard. Otherwise, only total scores are shown.
+ <%= f.check_box :live_scoreboard %> +
+
+ <%= f.label :show_unofficial_competitors %> - If true, unofficial competitors are greyed out. An offical competitor is any student enrolled in school.
+ <%= f.check_box :show_unofficial_competitors %> +
+
<%= f.submit %>
diff --git a/app/views/contests/edit.html.erb b/app/views/contests/edit.html.erb index 3074094a..d1413622 100644 --- a/app/views/contests/edit.html.erb +++ b/app/views/contests/edit.html.erb @@ -3,13 +3,4 @@

<%= render 'form' %> -

-<% if false # COMMENTED %> -

- Problems: -<% @problems.each do |problem| %> - <%= link_to problem.name, problem_path(problem) %> - (<%= link_to "remove", :controller => "problem_contest", :action => "remove", :method => "post", :problem_id => problem, :contest_id => @contest %>) -<% end %> -

-<% end %> +

\ No newline at end of file diff --git a/app/views/contests/info.html.erb b/app/views/contests/info.html.erb deleted file mode 100644 index c3d77457..00000000 --- a/app/views/contests/info.html.erb +++ /dev/null @@ -1,20 +0,0 @@ -<% if !@contest.started? && !@contest.start_time.nil? %> - -<% end %> - -<% if false && !@contest_relation.nil? %> -

Contest Registration

- - Country: <%= @contest_relation.country_code %> - School: <%= @contest_relation.school.name %> -<% end %> - -

Contest Settings

-Mode: Closed book (you cannot access other problems on the site while competing)
-Judge feedback: Real-time
-Scoreboard: Live
- diff --git a/app/views/contests/scoreboard.html.erb b/app/views/contests/scoreboard.html.erb index 81e366e9..be46dfdb 100644 --- a/app/views/contests/scoreboard.html.erb +++ b/app/views/contests/scoreboard.html.erb @@ -14,59 +14,83 @@ <% else %>

<%= @contest.finalized? ? "Final Results" : "Preliminary Results" %>

- +
- - <% @contest.problem_set.problems.each_with_index do |problem, prob_num|%> - + + + + <% if @contest.live_scoreboard %> + <% @contest.problem_set.problems.each_with_index do |problem, prob_num|%> + + <% end %> <% end %> - - - + + <% rank = 1 %> + <% num_unofficial = 0 %> <% previous_record = @scoreboard.first %> <% @scoreboard.each_with_index do |record,index| %> - class="emphasized"<% end %>> - + <% rank = index + 1 unless previous_record.score == record.score and previous_record.time_taken == record.time_taken%> + <% previous_record = record %> + + <% if record.user %> + + - <% link_to_submissions = user_signed_in? && (record.id == current_user.id || current_user.is_admin?) %> - <% @problems.each do |prob|%> - + + <% else %> + + + <% end %> + <% link_to_submissions = user_signed_in? && (record.id == current_user.id || current_user.is_admin?) %> + <% if @contest.live_scoreboard %> + <% @problems.each do |prob|%> + + <% end %> <% end %> - <% rank = index + 1 unless previous_record.score == record.score and previous_record.time_taken == record.time_taken %> - <% previous_record = record %> - <% end %>
User - <% if policy(@contest).show_details? %> - <%= link_to problem.name, problem_path(problem) %> - <% else %> - <% prob_num += 1 %> - Problem <% while !prob_num.zero? %><% prob_num, rem = (prob_num - 1).divmod(26) %><%= ('A'..'Z').to_a[rem] %><% end %> - <% end %> - (<%= @weighting[problem.id] %>) - # Username + <% if policy(@contest).show_details? %> + <%= link_to problem.name, problem_path(problem) %> + <% else %> + <% prob_num += 1 %> + Problem <% while !prob_num.zero? %><% prob_num, rem = (prob_num - 1).divmod(26) %><%= ('A'..'Z').to_a[rem] %><% end %> + <% end %> + (<%= @weighting[problem.id] %>) + Score Time Rank Score Time
- <% if record.user %> + <% is_official = true %> + <% if @contest.show_unofficial_competitors and record.user %> + <% is_official = record.user.estimated_year_level(@contest.end_time) %> + <% end %> + <% num_unofficial = num_unofficial + 1 unless is_official %> +
<%= rank - (is_official ? num_unofficial : 0)%> + <%= flag_list(24){ flag(record.user.country_code.downcase, record.user.country_name, title: true) } if record.user.country_code %> + <%= link_to handle(record.user), record.user %> - <% else %> - <%= "Deleted User ID #{record[:user_id]}" %> - <% end %> - - - <%= record["score_#{prob.id}"].nil? ? "-":link_to_if(link_to_submissions, record["score_#{prob.id}"], submission_path(record["sub_#{prob.id}"])) %> - - - <%= raw record["score_#{prob.id}"].nil? ? " ":"#{record["attempt_#{prob.id}"].to_i.ordinalize} 
try" %> -
- - (<%= link_to_if link_to_submissions, (record["attempts_#{prob.id}"] || 0), :controller => "submissions", :by_user => record[:user_id], :by_problem => prob.id %>) -
<%= "Deleted User ID #{record[:user_id]}" %> + + <%= record["score_#{prob.id}"].nil? ? "-":link_to_if(link_to_submissions, record["score_#{prob.id}"], submission_path(record["sub_#{prob.id}"])) %> + + + <%= raw record["score_#{prob.id}"].nil? ? " ":"#{record["attempt_#{prob.id}"].to_i.ordinalize} 
try" %> +
+ + (<%= link_to_if link_to_submissions, (record["attempts_#{prob.id}"] || 0), :controller => "submissions", :by_user => record[:user_id], :by_problem => prob.id %>) + +
<%= record.score %> <%= format("%d:%02d:%02d",record.time_taken.to_i/3600,record.time_taken.to_i/60%60,record.time_taken.to_i%60) %> <%= rank %>
+
+ Key + + + + + +
Official competitor
Unofficial competitor
<% end %> diff --git a/app/views/layouts/contest.html.erb b/app/views/layouts/contest.html.erb index 7703cca2..eb132ee7 100644 --- a/app/views/layouts/contest.html.erb +++ b/app/views/layouts/contest.html.erb @@ -71,8 +71,7 @@

Start time: <%= @contest.start_time %>
End time: <%= @contest.end_time %>
- Duration: <%= @contest.duration %>
- Owner: <%= @contest.owner_id %>
+ Duration: <%= @contest.duration %> <%= @contest.duration == 1.0 ? "hour" : "hours"%>

<% if @contest.ended? and @contest.finalized_at.nil? and policy(@contest).update? %> <%= link_to "Finalize results", finalize_contest_path(@contest), :data => { :confirm => 'Are you sure?' }, :method => :put %> @@ -85,7 +84,6 @@ # SimpleNavigation::ItemContainer.new do |menu| render_navigation do |menu| menu.dom_class = :tab_menu - menu.item :info, "info", info_contest_path(@contest) if policy(@contest).show? menu.item :problems, "problems", contest_path(@contest) if policy(@contest).overview? menu.item :contestants, "contestants", contestants_contest_path(@contest) if policy(@contest).contestants? menu.item :supervisors, "supervisors", supervisors_contest_path(@contest) if policy(@contest).manage? diff --git a/db/migrate/20200418113600_add_live_scoreboard_field.rb b/db/migrate/20200418113600_add_live_scoreboard_field.rb new file mode 100644 index 00000000..adbc956c --- /dev/null +++ b/db/migrate/20200418113600_add_live_scoreboard_field.rb @@ -0,0 +1,5 @@ +class AddLiveScoreboardField < ActiveRecord::Migration + def change + add_column :contests, :live_scoreboard, :boolean, :default => true + end + end \ No newline at end of file diff --git a/db/migrate/20200418113601_add_offical_competitors.rb b/db/migrate/20200418113601_add_offical_competitors.rb new file mode 100644 index 00000000..bc50d207 --- /dev/null +++ b/db/migrate/20200418113601_add_offical_competitors.rb @@ -0,0 +1,5 @@ +class AddOfficalCompetitors < ActiveRecord::Migration + def change + add_column :contests, :show_unofficial_competitors, :boolean, :default => false + end + end \ No newline at end of file diff --git a/db/schema.rb b/db/schema.rb index 264ca391..d4326eb8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 20160131000430) do +ActiveRecord::Schema.define(version: 20200418113601) do # These are extensions that must be enabled in order to support this database enable_extension "plpgsql" @@ -114,9 +114,11 @@ t.integer "problem_set_id" t.datetime "finalized_at" t.string "startcode" - t.integer "observation", default: 1 - t.integer "registration", default: 0 - t.integer "affiliation", default: 0 + t.integer "observation", default: 1 + t.integer "registration", default: 0 + t.integer "affiliation", default: 0 + t.boolean "live_scoreboard", default: true + t.boolean "show_unofficial_competitors", default: false end create_table "entities", force: true do |t|