Description:
add model solution
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r855:ef5cd5528b8d - - 11 files changed: 210 inserted, 125 deleted

@@ -0,0 +1,6
1 + class AddTypeToSubmission < ActiveRecord::Migration[7.0]
2 + def change
3 + add_column :submissions, :tag, :integer, default: 0
4 + add_column :problems, :difficulty, :integer
5 + end
6 + end
@@ -36,12 +36,23
36 36 unauthorized_redirect
37 37 return false
38 38 end
39 39 return true
40 40 end
41 41
42 + #admin always count as every roles
43 + def role_authorization(roles)
44 + return false unless check_valid_login
45 + user = User.find(session[:user_id])
46 + return true if user.admin?
47 + roles.each do |r|
48 + return true if user.has_role?(r)
49 + end
50 + unauthorized_redirect
51 + end
52 +
42 53 def authorization_by_roles(allowed_roles)
43 54 return false unless check_valid_login
44 55 unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
45 56 unauthorized_redirect
46 57 return false
47 58 end
@@ -68,13 +68,13
68 68 @submission.source = params[:editor_text]
69 69 @submission.source_filename = "live_edit.#{language.ext}"
70 70 @submission.language = language
71 71 end
72 72
73 73 @submission.submitted_at = Time.new.gmtime
74 - @submission.ip_address = request.remote_ip
74 + @submission.ip_address = cookies.encrypted[:uuid]
75 75
76 76 if @current_user.admin? == false && GraderConfiguration.time_limit_mode? && @current_user.contest_finished?
77 77 @submission.errors.add(:base,"The contest is over.")
78 78 prepare_list_information
79 79 render :action => 'list' and return
80 80 end
@@ -231,22 +231,27
231 231 return
232 232 end
233 233 end
234 234
235 235 return unless @problem
236 236
237 + #model submisssion
238 + @model_subs = Submission.where(problem: @problem,tag: Submission.tags[:model])
239 +
240 +
241 + #calculate best submission
237 242 @by_lang = {} #aggregrate by language
238 243
239 244 range =65
240 - @histogram = { data: Array.new(range,0), summary: {} }
245 + #@histogram = { data: Array.new(range,0), summary: {} }
241 246 @summary = {count: 0, solve: 0, attempt: 0}
242 247 user = Hash.new(0)
243 248 Submission.where(problem_id: @problem.id).find_each do |sub|
244 249 #histogram
245 250 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
246 - @histogram[:data][d.to_i] += 1 if d < range
251 + #@histogram[:data][d.to_i] += 1 if d < range
247 252
248 253 next unless sub.points
249 254 @summary[:count] += 1
250 255 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
251 256
252 257 lang = Language.find_by_id(sub.language_id)
@@ -308,15 +313,19
308 313 @best[:first] = prop[:first]
309 314 @best[:first][:lang] = lang
310 315 end
311 316 end
312 317 end
313 318
314 - @histogram[:summary][:max] = [@histogram[:data].max,1].max
319 + #@histogram[:summary][:max] = [@histogram[:data].max,1].max
315 320 @summary[:attempt] = user.count
316 321 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
322 +
323 +
324 + #for new graph
325 + @chart_dataset = @problem.get_jschart_history.to_json.html_safe
317 326 end
318 327
319 328 def stuck #report struggling user,problem
320 329 # init
321 330 user,problem = nil
322 331 solve = true
@@ -1,10 +1,11
1 1 class SubmissionsController < ApplicationController
2 + before_action :set_submission, only: [:show,:download,:compiler_msg,:rejudge,:set_tag, :edit]
2 3 before_action :check_valid_login
3 4 before_action :submission_authorization, only: [:show, :download, :edit]
4 - before_action :admin_authorization, only: [:rejudge]
5 + before_action only: [:rejudge, :set_tag] do role_authorization([:ta]) end
5 6
6 7 # GET /submissions
7 8 # GET /submissions.json
8 9 # Show problem selection and user's submission of that problem
9 10 def index
10 11 @user = @current_user
@@ -24,28 +25,24
24 25 end
25 26 end
26 27
27 28 # GET /submissions/1
28 29 # GET /submissions/1.json
29 30 def show
30 - @submission = Submission.find(params[:id])
31 -
32 31 #log the viewing
33 32 user = User.find(session[:user_id])
34 33 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35 34
36 35 @task = @submission.task
37 36 end
38 37
39 38 def download
40 - @submission = Submission.find(params[:id])
41 39 send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 40 end
43 41
44 42 def compiler_msg
45 - @submission = Submission.find(params[:id])
46 43 respond_to do |format|
47 44 format.js
48 45 end
49 46 end
50 47
51 48 #on-site new submission on specific problem
@@ -62,13 +59,12
62 59 end
63 60 render 'edit'
64 61 end
65 62
66 63 # GET /submissions/1/edit
67 64 def edit
68 - @submission = Submission.find(params[:id])
69 65 @source = @submission.source.to_s
70 66 @problem = @submission.problem
71 67 @lang_id = @submission.language.id
72 68 end
73 69
74 70
@@ -79,20 +75,24
79 75 format.js
80 76 end
81 77 end
82 78
83 79 # GET /submissions/:id/rejudge
84 80 def rejudge
85 - @submission = Submission.find(params[:id])
86 81 @task = @submission.task
87 82 @task.status_inqueue! if @task
88 83 respond_to do |format|
89 84 format.js
90 85 end
91 86 end
92 87
88 + def set_tag
89 + @submission.update(tag: params[:tag])
90 + redirect_to @submission
91 + end
92 +
93 93 protected
94 94
95 95 def submission_authorization
96 96 #admin always has privileged
97 97 return true if @current_user.admin?
98 98 return true if @current_user.has_role?('ta') && (['show','download'].include? action_name)
@@ -103,9 +103,13
103 103 end
104 104
105 105 #default to NO
106 106 unauthorized_redirect
107 107 return false
108 108 end
109 +
110 + def set_submission
111 + @submission = Submission.find(params[:id])
112 + end
109 113
110 114
111 115 end
@@ -21,12 +21,34
21 21
22 22 scope :available, -> { where(available: true) }
23 23
24 24 DEFAULT_TIME_LIMIT = 1
25 25 DEFAULT_MEMORY_LIMIT = 32
26 26
27 + def get_jschart_history
28 + start = 4.month.ago.beginning_of_day
29 + start_date = start.to_date
30 + count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count
31 + i = 0
32 + label = []
33 + value = []
34 + while (start_date + i < Time.zone.now.to_date)
35 + if (start_date+i).day == 1
36 + #label << (start_date+i).strftime("%d %b %Y")
37 + #label << (start_date+i).strftime("%d")
38 + else
39 + #label << ' '
40 + #label << (start_date+i).strftime("%d")
41 + end
42 + label << (start_date+i).strftime("%d-%b")
43 + value << (count[start_date+i] || 0)
44 + i+=1
45 + end
46 + return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']}
47 + end
48 +
27 49 def self.available_problems
28 50 available.order(date_added: :desc).order(:name)
29 51 #Problem.available.all(:order => "date_added DESC, name ASC")
30 52 end
31 53
32 54 def self.create_from_import_form_params(params, old_problem=nil)
@@ -1,8 +1,10
1 1 class Submission < ActiveRecord::Base
2 2
3 + enum tag: {default: 0, model: 1}, _prefix: true
4 +
3 5 belongs_to :language
4 6 belongs_to :problem
5 7 belongs_to :user
6 8
7 9 before_validation :assign_problem
8 10 before_validation :assign_language
@@ -21,18 +23,18
21 23 where("user_id = ? AND problem_id = ?",user_id,problem_id).last
22 24 end
23 25
24 26 def self.find_all_last_by_problem(problem_id)
25 27 # need to put in SQL command, maybe there's a better way
26 28 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
27 - "WHERE id = " +
28 - "(SELECT MAX(id) FROM submissions AS subs " +
29 - "WHERE subs.user_id = submissions.user_id AND " +
30 - "problem_id = " + problem_id.to_s + " " +
31 - "GROUP BY user_id) " +
32 - "ORDER BY user_id")
29 + "WHERE id = " +
30 + "(SELECT MAX(id) FROM submissions AS subs " +
31 + "WHERE subs.user_id = submissions.user_id AND " +
32 + "problem_id = " + problem_id.to_s + " " +
33 + "GROUP BY user_id) " +
34 + "ORDER BY user_id")
33 35 end
34 36
35 37 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
36 38 records = Submission.where(problem_id: problem_id,user_id: user_id)
37 39 records = records.where('id >= ?',since_id) if since_id and since_id > 0
38 40 records = records.where('id <= ?',until_id) if until_id and until_id > 0
@@ -72,18 +74,18
72 74 if source==nil
73 75 return nil
74 76 end
75 77 i = 0
76 78 source.each_line do |s|
77 79 if s =~ option
78 - words = s.split
79 - return words[1]
80 + words = s.split
81 + return words[1]
80 82 end
81 83 i = i + 1
82 84 if i==10
83 - return nil
85 + return nil
84 86 end
85 87 end
86 88 return nil
87 89 end
88 90
89 91 def self.find_language_in_source(source, source_filename="")
@@ -21,116 +21,134
21 21 word-wrap: break-word;
22 22 z-index: 9999;
23 23 overflow: auto;
24 24 }
25 25
26 26
27 - .container
27 + .container-fluid
28 + .row
29 + .col-md-8
30 + .card
31 + .card-body
32 + %h2.card-title Submission History
33 + %canvas#chart{height: '50px'}
34 +
35 + .col-md-4
36 + .card
37 + .card-body
38 + %h2.card-title General Info
39 + .row
40 + .col-sm-6
41 + Subs
42 + .col-sm-6
43 + = @summary[:count]
44 + .row
45 + .col-sm-6
46 + Solved/Attempted User
47 + .col-sm-6
48 + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
28 49 .row
29 50 .col-md-4
30 - %h2 Overall Stat
31 - %table.table.table-hover
32 - %thead
33 - %tr
34 - %th
35 - %th
36 - %tbody
37 - %tr
38 - %td.info_param Submissions
39 - %td= @summary[:count]
40 - %tr
41 - %td.info_param Solved/Attempted User
42 - %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
43 - - if @best
44 - %tr
45 - %td.info_param Best Runtime
46 - %td
47 - by #{link_to @best[:runtime][:user], stat_user_path(@best[:runtime][:user_id])}
48 - %br
49 - using <span class="text-success">#{@best[:runtime][:lang]}</span>
50 - %br
51 - with <span class="text-success">#{@best[:runtime][:value] * 1000} milliseconds</span>
52 - %br
53 - at submission
54 - = link_to "#" + @best[:runtime][:sub_id].to_s, submission_path(@best[:runtime][:sub_id])
55 -
56 - %tr
57 - %td.info_param
58 - Best Memory Usage
59 - %sup{ id: "xmem_remark",
60 - style: "position:relative; color: blue;",
61 - data: {toggle: 'tooltip', placement: 'top', animation: 'false', delay: 20},
62 - title: "This counts only for submission with 100% score. Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)"}
63 - [?]
64 - %td
65 - by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
66 - %br
67 - using <span class="text-success">#{@best[:memory][:lang]}</span>
68 - %br
69 - with <span class="text-success">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
70 - %br
71 - at submission
72 - = link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
73 -
74 - %tr
75 - %td.info_param Shortest Code
76 - %td
77 - by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
78 - %br
79 - using <span class="text-success">#{@best[:length][:lang]}</span>
80 - %br
81 - with <span class="text-success">#{@best[:length][:value]} bytes</span>
82 - %br
83 - at submission
84 - = link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
85 -
86 - %tr
87 - %td.info_param First solver
88 - %td
89 - - if @best[:first][:user] != '(NULL)'
90 - #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
91 - %br
92 - using <span class="text-success">#{@best[:first][:lang]}</span>
93 - %br
94 - on <span class="text-success">#{@best[:first][:value]}</span>
95 - %br
96 - at submission
97 - = link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
98 - - else
99 - no first solver
100 - .col-md-8
101 - - if @best
102 - %h2 By Language
51 + .card
52 + .card-body
53 + %h2.card-title Model submission
103 54 %table.table.table-hover
104 55 %thead
105 56 %tr
106 - %th Language
107 - %th Best runtime (ms)
108 - %th Best memory (kbytes)
109 - %th Shortest Code (bytes)
110 - %th First solver
57 + %th #Sub
58 + %th Author
111 59 %tbody
112 - - @by_lang.each do |lang,value|
60 + - @model_subs.each do |sub|
113 61 %tr
114 - %td= lang
62 + %td= link_to "##{sub.id}", submission_path(sub)
63 + %td= sub.user.full_name
64 + .col-md-8
65 + - if @best
66 + .card
67 + .card-body
68 + %h2.card-title Top Submissions
69 + %table.table.table-hover
70 + %thead
71 + %tr
72 + %th Language
73 + %th Best runtime (ms)
74 + %th Best memory (kbytes)
75 + %th Shortest Code (bytes)
76 + %th First solver
77 + %tbody
78 + %tr.bg-warning
115 79 %td
116 - = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
80 + Overall
81 + %td
82 + by #{link_to @best[:runtime][:user], stat_user_path(@best[:runtime][:user_id])}
83 + %br
84 + using <span class="text-success">#{@best[:runtime][:lang]}</span>
85 + %br
86 + with <span class="text-success">#{@best[:runtime][:value] * 1000} milliseconds</span>
87 + %br= link_to "#" + @best[:runtime][:sub_id].to_s, submission_path(@best[:runtime][:sub_id])
88 + %td
89 + by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
117 90 %br
118 - = "#{(value[:runtime][:value] * 1000).to_i} @"
119 - = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
91 + using <span class="text-success">#{@best[:memory][:lang]}</span>
92 + %br
93 + with <span class="text-success">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
94 + %br= link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
95 + %td
96 + by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
97 + %br
98 + using <span class="text-success">#{@best[:length][:lang]}</span>
99 + %br
100 + with <span class="text-success">#{@best[:length][:value]} bytes</span>
101 + %br= link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
120 102 %td
121 - = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
122 - %br
123 - = "#{number_with_delimiter(value[:memory][:value])} @"
124 - = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
125 - %td
126 - = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
127 - %br
128 - = "#{value[:length][:value]} @"
129 - = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
130 - %td
131 - - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
132 - = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
103 + - if @best[:first][:user] != '(NULL)'
104 + #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
105 + %br
106 + using <span class="text-success">#{@best[:first][:lang]}</span>
107 + %br
108 + on <span class="text-success">#{@best[:first][:value]}</span>
109 + %br= link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
110 + - else
111 + no first solver
112 + - @by_lang.each do |lang,value|
113 + %tr
114 + %td= lang
115 + %td
116 + = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
117 + %br
118 + = "#{(value[:runtime][:value] * 1000).to_i} @"
119 + = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
120 + %td
121 + = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
122 + %br
123 + = "#{number_with_delimiter(value[:memory][:value])} @"
124 + = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
125 + %td
126 + = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
133 127 %br
134 - = "#{value[:first][:value]} @"
135 - = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
128 + = "#{value[:length][:value]} @"
129 + = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
130 + %td
131 + - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
132 + = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
133 + %br
134 + = "#{value[:first][:value]} @"
135 + = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
136 136
137 + %script{src:"https://cdn.jsdelivr.net/npm/chart.js"}
138 + :javascript
139 + data = #{@chart_dataset}
140 + config = {
141 + type: 'bar',
142 + data: data,
143 + options: {
144 + plugins: {
145 + legend: {
146 + display: false
147 + },
148 + },
149 + }
150 + }
151 + Chart.defaults.font.size = 15
152 + //Chart.defaults.font.family = 'Sarabun Light'
153 + chart = new Chart($('#chart'),config)
154 +
@@ -20,10 +20,10
20 20
21 21 - unless params[:id]
22 22 /=render partial: 'all_time_hof'
23 23 Please select a problem.
24 24 - else
25 25 %h1 [#{Problem.find(params[:id]).name}] #{Problem.find(params[:id]).full_name}
26 - %h2 Submission History
27 - =render partial: 'application/bar_graph', locals: { histogram: @histogram }
26 + -# %h2 Submission History
27 + -# =render partial: 'application/bar_graph', locals: { histogram: @histogram }
28 28 =render partial: 'task_hof'
29 29
@@ -86,24 +86,36
86 86 %tr
87 87 %td.text-right
88 88 %strong Compiler result
89 89 %td
90 90 %button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
91 91 view
92 - - if session[:admin]
93 - %tr
94 - %td.text-right
95 - %strong IP
96 - %td #{@submission.ip_address}
97 92 %tr
98 93 %td.text-right
99 94 %strong Grading Task Status
100 95 %td
101 96 = @task.status_str if @task
102 97 - if session[:admin]
103 98 = link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
99 + - if session[:admin]
100 + %tr
101 + %td.text-right
102 + %strong IP
103 + %td #{@submission.ip_address}
104 + %tr
105 + %td.text-right
106 + %strong Model solution
107 + %td
108 + - if @submission.tag_model?
109 + YES
110 + - if session[:admin]
111 + = link_to "remove model status", set_tag_submission_path(@submission, tag: :default), class: 'btn btn-warning btn-xs'
112 + - else
113 + No
114 + - if session[:admin]
115 + = link_to "set as model solution", set_tag_submission_path(@submission, tag: :model), class: 'btn btn-success btn-xs'
104 116
105 117
106 118 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
107 119 .modal-dialog.modal-lg{role:'document'}
108 120 .modal-content
109 121 .modal-header
@@ -91,12 +91,13
91 91
92 92 resources :submissions do
93 93 member do
94 94 get 'download'
95 95 get 'compiler_msg'
96 96 get 'rejudge'
97 + get 'set_tag'
97 98 end
98 99 collection do
99 100 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
100 101 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
101 102 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
102 103 end
You need to be logged in to leave comments. Login now