diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb
--- a/app/controllers/application_controller.rb
+++ b/app/controllers/application_controller.rb
@@ -39,6 +39,17 @@
return true
end
+ #admin always count as every roles
+ def role_authorization(roles)
+ return false unless check_valid_login
+ user = User.find(session[:user_id])
+ return true if user.admin?
+ roles.each do |r|
+ return true if user.has_role?(r)
+ end
+ unauthorized_redirect
+ end
+
def authorization_by_roles(allowed_roles)
return false unless check_valid_login
unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
diff --git a/app/controllers/main_controller.rb b/app/controllers/main_controller.rb
--- a/app/controllers/main_controller.rb
+++ b/app/controllers/main_controller.rb
@@ -71,7 +71,7 @@
end
@submission.submitted_at = Time.new.gmtime
- @submission.ip_address = request.remote_ip
+ @submission.ip_address = cookies.encrypted[:uuid]
if @current_user.admin? == false && GraderConfiguration.time_limit_mode? && @current_user.contest_finished?
@submission.errors.add(:base,"The contest is over.")
diff --git a/app/controllers/report_controller.rb b/app/controllers/report_controller.rb
--- a/app/controllers/report_controller.rb
+++ b/app/controllers/report_controller.rb
@@ -234,16 +234,21 @@
return unless @problem
+ #model submisssion
+ @model_subs = Submission.where(problem: @problem,tag: Submission.tags[:model])
+
+
+ #calculate best submission
@by_lang = {} #aggregrate by language
range =65
- @histogram = { data: Array.new(range,0), summary: {} }
+ #@histogram = { data: Array.new(range,0), summary: {} }
@summary = {count: 0, solve: 0, attempt: 0}
user = Hash.new(0)
Submission.where(problem_id: @problem.id).find_each do |sub|
#histogram
d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
- @histogram[:data][d.to_i] += 1 if d < range
+ #@histogram[:data][d.to_i] += 1 if d < range
next unless sub.points
@summary[:count] += 1
@@ -311,9 +316,13 @@
end
end
- @histogram[:summary][:max] = [@histogram[:data].max,1].max
+ #@histogram[:summary][:max] = [@histogram[:data].max,1].max
@summary[:attempt] = user.count
user.each_value { |v| @summary[:solve] += 1 if v == 1 }
+
+
+ #for new graph
+ @chart_dataset = @problem.get_jschart_history.to_json.html_safe
end
def stuck #report struggling user,problem
diff --git a/app/controllers/submissions_controller.rb b/app/controllers/submissions_controller.rb
--- a/app/controllers/submissions_controller.rb
+++ b/app/controllers/submissions_controller.rb
@@ -1,7 +1,8 @@
class SubmissionsController < ApplicationController
+ before_action :set_submission, only: [:show,:download,:compiler_msg,:rejudge,:set_tag, :edit]
before_action :check_valid_login
before_action :submission_authorization, only: [:show, :download, :edit]
- before_action :admin_authorization, only: [:rejudge]
+ before_action only: [:rejudge, :set_tag] do role_authorization([:ta]) end
# GET /submissions
# GET /submissions.json
@@ -27,8 +28,6 @@
# GET /submissions/1
# GET /submissions/1.json
def show
- @submission = Submission.find(params[:id])
-
#log the viewing
user = User.find(session[:user_id])
SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
@@ -37,12 +36,10 @@
end
def download
- @submission = Submission.find(params[:id])
send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
end
def compiler_msg
- @submission = Submission.find(params[:id])
respond_to do |format|
format.js
end
@@ -65,7 +62,6 @@
# GET /submissions/1/edit
def edit
- @submission = Submission.find(params[:id])
@source = @submission.source.to_s
@problem = @submission.problem
@lang_id = @submission.language.id
@@ -82,7 +78,6 @@
# GET /submissions/:id/rejudge
def rejudge
- @submission = Submission.find(params[:id])
@task = @submission.task
@task.status_inqueue! if @task
respond_to do |format|
@@ -90,6 +85,11 @@
end
end
+ def set_tag
+ @submission.update(tag: params[:tag])
+ redirect_to @submission
+ end
+
protected
def submission_authorization
@@ -106,6 +106,10 @@
unauthorized_redirect
return false
end
+
+ def set_submission
+ @submission = Submission.find(params[:id])
+ end
end
diff --git a/app/models/problem.rb b/app/models/problem.rb
--- a/app/models/problem.rb
+++ b/app/models/problem.rb
@@ -24,6 +24,28 @@
DEFAULT_TIME_LIMIT = 1
DEFAULT_MEMORY_LIMIT = 32
+ def get_jschart_history
+ start = 4.month.ago.beginning_of_day
+ start_date = start.to_date
+ count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count
+ i = 0
+ label = []
+ value = []
+ while (start_date + i < Time.zone.now.to_date)
+ if (start_date+i).day == 1
+ #label << (start_date+i).strftime("%d %b %Y")
+ #label << (start_date+i).strftime("%d")
+ else
+ #label << ' '
+ #label << (start_date+i).strftime("%d")
+ end
+ label << (start_date+i).strftime("%d-%b")
+ value << (count[start_date+i] || 0)
+ i+=1
+ end
+ return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']}
+ end
+
def self.available_problems
available.order(date_added: :desc).order(:name)
#Problem.available.all(:order => "date_added DESC, name ASC")
diff --git a/app/models/submission.rb b/app/models/submission.rb
--- a/app/models/submission.rb
+++ b/app/models/submission.rb
@@ -1,5 +1,7 @@
class Submission < ActiveRecord::Base
+ enum tag: {default: 0, model: 1}, _prefix: true
+
belongs_to :language
belongs_to :problem
belongs_to :user
@@ -24,12 +26,12 @@
def self.find_all_last_by_problem(problem_id)
# need to put in SQL command, maybe there's a better way
Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
- "WHERE id = " +
- "(SELECT MAX(id) FROM submissions AS subs " +
- "WHERE subs.user_id = submissions.user_id AND " +
- "problem_id = " + problem_id.to_s + " " +
- "GROUP BY user_id) " +
- "ORDER BY user_id")
+ "WHERE id = " +
+ "(SELECT MAX(id) FROM submissions AS subs " +
+ "WHERE subs.user_id = submissions.user_id AND " +
+ "problem_id = " + problem_id.to_s + " " +
+ "GROUP BY user_id) " +
+ "ORDER BY user_id")
end
def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
@@ -75,12 +77,12 @@
i = 0
source.each_line do |s|
if s =~ option
- words = s.split
- return words[1]
+ words = s.split
+ return words[1]
end
i = i + 1
if i==10
- return nil
+ return nil
end
end
return nil
diff --git a/app/views/report/_task_hof.html.haml b/app/views/report/_task_hof.html.haml
--- a/app/views/report/_task_hof.html.haml
+++ b/app/views/report/_task_hof.html.haml
@@ -24,113 +24,131 @@
}
-.container
+.container-fluid
+ .row
+ .col-md-8
+ .card
+ .card-body
+ %h2.card-title Submission History
+ %canvas#chart{height: '50px'}
+
+ .col-md-4
+ .card
+ .card-body
+ %h2.card-title General Info
+ .row
+ .col-sm-6
+ Subs
+ .col-sm-6
+ = @summary[:count]
+ .row
+ .col-sm-6
+ Solved/Attempted User
+ .col-sm-6
+ #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
.row
.col-md-4
- %h2 Overall Stat
- %table.table.table-hover
- %thead
- %tr
- %th
- %th
- %tbody
- %tr
- %td.info_param Submissions
- %td= @summary[:count]
- %tr
- %td.info_param Solved/Attempted User
- %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
- - if @best
- %tr
- %td.info_param Best Runtime
- %td
- by #{link_to @best[:runtime][:user], stat_user_path(@best[:runtime][:user_id])}
- %br
- using #{@best[:runtime][:lang]}
- %br
- with #{@best[:runtime][:value] * 1000} milliseconds
- %br
- at submission
- = link_to "#" + @best[:runtime][:sub_id].to_s, submission_path(@best[:runtime][:sub_id])
-
- %tr
- %td.info_param
- Best Memory Usage
- %sup{ id: "xmem_remark",
- style: "position:relative; color: blue;",
- data: {toggle: 'tooltip', placement: 'top', animation: 'false', delay: 20},
- title: "This counts only for submission with 100% score. Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)"}
- [?]
- %td
- by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
- %br
- using #{@best[:memory][:lang]}
- %br
- with #{number_with_delimiter(@best[:memory][:value])} kbytes
- %br
- at submission
- = link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
-
- %tr
- %td.info_param Shortest Code
- %td
- by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
- %br
- using #{@best[:length][:lang]}
- %br
- with #{@best[:length][:value]} bytes
- %br
- at submission
- = link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
-
- %tr
- %td.info_param First solver
- %td
- - if @best[:first][:user] != '(NULL)'
- #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
- %br
- using #{@best[:first][:lang]}
- %br
- on #{@best[:first][:value]}
- %br
- at submission
- = link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
- - else
- no first solver
- .col-md-8
- - if @best
- %h2 By Language
+ .card
+ .card-body
+ %h2.card-title Model submission
%table.table.table-hover
%thead
%tr
- %th Language
- %th Best runtime (ms)
- %th Best memory (kbytes)
- %th Shortest Code (bytes)
- %th First solver
+ %th #Sub
+ %th Author
%tbody
- - @by_lang.each do |lang,value|
+ - @model_subs.each do |sub|
%tr
- %td= lang
+ %td= link_to "##{sub.id}", submission_path(sub)
+ %td= sub.user.full_name
+ .col-md-8
+ - if @best
+ .card
+ .card-body
+ %h2.card-title Top Submissions
+ %table.table.table-hover
+ %thead
+ %tr
+ %th Language
+ %th Best runtime (ms)
+ %th Best memory (kbytes)
+ %th Shortest Code (bytes)
+ %th First solver
+ %tbody
+ %tr.bg-warning
%td
- = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
+ Overall
+ %td
+ by #{link_to @best[:runtime][:user], stat_user_path(@best[:runtime][:user_id])}
+ %br
+ using #{@best[:runtime][:lang]}
+ %br
+ with #{@best[:runtime][:value] * 1000} milliseconds
+ %br= link_to "#" + @best[:runtime][:sub_id].to_s, submission_path(@best[:runtime][:sub_id])
+ %td
+ by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
%br
- = "#{(value[:runtime][:value] * 1000).to_i} @"
- = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
+ using #{@best[:memory][:lang]}
+ %br
+ with #{number_with_delimiter(@best[:memory][:value])} kbytes
+ %br= link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
+ %td
+ by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
+ %br
+ using #{@best[:length][:lang]}
+ %br
+ with #{@best[:length][:value]} bytes
+ %br= link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
%td
- = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
- %br
- = "#{number_with_delimiter(value[:memory][:value])} @"
- = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
- %td
- = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
- %br
- = "#{value[:length][:value]} @"
- = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
- %td
- - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
- = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
+ - if @best[:first][:user] != '(NULL)'
+ #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
+ %br
+ using #{@best[:first][:lang]}
+ %br
+ on #{@best[:first][:value]}
+ %br= link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
+ - else
+ no first solver
+ - @by_lang.each do |lang,value|
+ %tr
+ %td= lang
+ %td
+ = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
+ %br
+ = "#{(value[:runtime][:value] * 1000).to_i} @"
+ = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
+ %td
+ = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
+ %br
+ = "#{number_with_delimiter(value[:memory][:value])} @"
+ = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
+ %td
+ = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
%br
- = "#{value[:first][:value]} @"
- = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
+ = "#{value[:length][:value]} @"
+ = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
+ %td
+ - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
+ = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
+ %br
+ = "#{value[:first][:value]} @"
+ = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
+%script{src:"https://cdn.jsdelivr.net/npm/chart.js"}
+:javascript
+ data = #{@chart_dataset}
+ config = {
+ type: 'bar',
+ data: data,
+ options: {
+ plugins: {
+ legend: {
+ display: false
+ },
+ },
+ }
+ }
+ Chart.defaults.font.size = 15
+ //Chart.defaults.font.family = 'Sarabun Light'
+ chart = new Chart($('#chart'),config)
+
diff --git a/app/views/report/problem_hof.html.haml b/app/views/report/problem_hof.html.haml
--- a/app/views/report/problem_hof.html.haml
+++ b/app/views/report/problem_hof.html.haml
@@ -23,7 +23,7 @@
Please select a problem.
- else
%h1 [#{Problem.find(params[:id]).name}] #{Problem.find(params[:id]).full_name}
- %h2 Submission History
- =render partial: 'application/bar_graph', locals: { histogram: @histogram }
+ -# %h2 Submission History
+ -# =render partial: 'application/bar_graph', locals: { histogram: @histogram }
=render partial: 'task_hof'
diff --git a/app/views/submissions/show.html.haml b/app/views/submissions/show.html.haml
--- a/app/views/submissions/show.html.haml
+++ b/app/views/submissions/show.html.haml
@@ -89,11 +89,6 @@
%td
%button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
view
- - if session[:admin]
- %tr
- %td.text-right
- %strong IP
- %td #{@submission.ip_address}
%tr
%td.text-right
%strong Grading Task Status
@@ -101,6 +96,23 @@
= @task.status_str if @task
- if session[:admin]
= link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
+ - if session[:admin]
+ %tr
+ %td.text-right
+ %strong IP
+ %td #{@submission.ip_address}
+ %tr
+ %td.text-right
+ %strong Model solution
+ %td
+ - if @submission.tag_model?
+ YES
+ - if session[:admin]
+ = link_to "remove model status", set_tag_submission_path(@submission, tag: :default), class: 'btn btn-warning btn-xs'
+ - else
+ No
+ - if session[:admin]
+ = link_to "set as model solution", set_tag_submission_path(@submission, tag: :model), class: 'btn btn-success btn-xs'
.modal.fade#compiler{tabindex: -1,role: 'dialog'}
diff --git a/config/routes.rb b/config/routes.rb
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -94,6 +94,7 @@
get 'download'
get 'compiler_msg'
get 'rejudge'
+ get 'set_tag'
end
collection do
get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
diff --git a/db/migrate/20220204080936_add_type_to_submission.rb b/db/migrate/20220204080936_add_type_to_submission.rb
new file mode 100644
--- /dev/null
+++ b/db/migrate/20220204080936_add_type_to_submission.rb
@@ -0,0 +1,6 @@
+class AddTypeToSubmission < ActiveRecord::Migration[7.0]
+ def change
+ add_column :submissions, :tag, :integer, default: 0
+ add_column :problems, :difficulty, :integer
+ end
+end