Description:
wip
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r880:31e27f513ce9 - - 9 files changed: 191 inserted, 160 deleted
@@ -148,6 +148,9 | |||||
|
148 |
|
148 | ||
|
149 | @summary = { attempt: user.count, solve: 0 } |
|
149 | @summary = { attempt: user.count, solve: 0 } |
|
150 | user.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
150 | user.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
|
151 | + | ||
|
|
152 | + #for new graph | ||
|
|
153 | + @chart_dataset = @problem.get_jschart_history.to_json.html_safe | ||
|
151 | end |
|
154 | end |
|
152 |
|
155 | ||
|
153 | def manage |
|
156 | def manage |
@@ -248,7 +248,7 | |||||
|
248 | #@histogram = { data: Array.new(range,0), summary: {} } |
|
248 | #@histogram = { data: Array.new(range,0), summary: {} } |
|
249 | @summary = {count: 0, solve: 0, attempt: 0} |
|
249 | @summary = {count: 0, solve: 0, attempt: 0} |
|
250 | user = Hash.new(0) |
|
250 | user = Hash.new(0) |
|
251 |
- Submission.where(problem_id: @problem.id). |
|
251 | + Submission.where(problem_id: @problem.id).includes(:language).each do |sub| |
|
252 | #histogram |
|
252 | #histogram |
|
253 | d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
|
253 | d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
|
254 | #@histogram[:data][d.to_i] += 1 if d < range |
|
254 | #@histogram[:data][d.to_i] += 1 if d < range |
@@ -257,7 +257,8 | |||||
|
257 | @summary[:count] += 1 |
|
257 | @summary[:count] += 1 |
|
258 | user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max |
|
258 | user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max |
|
259 |
|
259 | ||
|
260 | - lang = Language.find_by_id(sub.language_id) |
|
260 | + #lang = Language.find_by_id(sub.language_id) |
|
|
261 | + lang = sub.language | ||
|
261 | next unless lang |
|
262 | next unless lang |
|
262 | next unless sub.points >= @problem.full_score |
|
263 | next unless sub.points >= @problem.full_score |
|
263 |
|
264 |
@@ -130,27 +130,21 | |||||
|
130 |
|
130 | ||
|
131 | def stat |
|
131 | def stat |
|
132 | @user = User.find(params[:id]) |
|
132 | @user = User.find(params[:id]) |
|
133 | - @submission = Submission.joins(:problem).where(user_id: params[:id]) |
|
133 | + @submission = Submission.joins(:problem).includes(:problem).includes(:language).where(user_id: params[:id]) |
|
134 | @submission = @submission.where('problems.available = true') unless current_user.admin? |
|
134 | @submission = @submission.where('problems.available = true') unless current_user.admin? |
|
135 |
|
135 | ||
|
136 | - range = 120 |
|
||
|
137 | - @histogram = { data: Array.new(range,0), summary: {} } |
|
||
|
138 | @summary = {count: 0, solve: 0, attempt: 0} |
|
136 | @summary = {count: 0, solve: 0, attempt: 0} |
|
139 | problem = Hash.new(0) |
|
137 | problem = Hash.new(0) |
|
140 |
|
138 | ||
|
141 | @submission.find_each do |sub| |
|
139 | @submission.find_each do |sub| |
|
142 | - #histogram |
|
||
|
143 | - d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
|
||
|
144 | - @histogram[:data][d.to_i] += 1 if d < range |
|
||
|
145 | - |
|
||
|
146 | @summary[:count] += 1 |
|
140 | @summary[:count] += 1 |
|
147 | next unless sub.problem |
|
141 | next unless sub.problem |
|
148 | problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max |
|
142 | problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max |
|
149 | end |
|
143 | end |
|
150 |
|
144 | ||
|
151 | - @histogram[:summary][:max] = [@histogram[:data].max,1].max |
|
||
|
152 | @summary[:attempt] = problem.count |
|
145 | @summary[:attempt] = problem.count |
|
153 | problem.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
146 | problem.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
|
147 | + @chart_dataset = @user.get_jschart_user_sub_history.to_json.html_safe | ||
|
154 | end |
|
148 | end |
|
155 |
|
149 | ||
|
156 | def toggle_activate |
|
150 | def toggle_activate |
@@ -314,6 +314,21 | |||||
|
314 | User.update_all(:last_ip => nil) |
|
314 | User.update_all(:last_ip => nil) |
|
315 | end |
|
315 | end |
|
316 |
|
316 | ||
|
|
317 | + def get_jschart_user_sub_history | ||
|
|
318 | + start = 4.month.ago.beginning_of_day | ||
|
|
319 | + start_date = start.to_date | ||
|
|
320 | + count = Submission.where(user: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count | ||
|
|
321 | + i = 0 | ||
|
|
322 | + label = [] | ||
|
|
323 | + value = [] | ||
|
|
324 | + while (start_date + i < Time.zone.now.to_date) | ||
|
|
325 | + label << (start_date+i).strftime("%d-%b") | ||
|
|
326 | + value << (count[start_date+i] || 0) | ||
|
|
327 | + i+=1 | ||
|
|
328 | + end | ||
|
|
329 | + return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']} | ||
|
|
330 | + end | ||
|
|
331 | + | ||
|
317 | #create multiple user, one per lines of input |
|
332 | #create multiple user, one per lines of input |
|
318 | def self.create_from_list(lines) |
|
333 | def self.create_from_list(lines) |
|
319 | error_logins = [] |
|
334 | error_logins = [] |
@@ -3,21 +3,21 | |||||
|
3 | - else |
|
3 | - else |
|
4 | - if local_assigns[:show_id] |
|
4 | - if local_assigns[:show_id] |
|
5 | .row |
|
5 | .row |
|
6 |
- .col-3. |
|
6 | + .col-3.fw-bold |
|
7 |
- Sub ID |
|
7 | + Sub ID |
|
8 |
- |
|
8 | + .col-9.text-secondary-x= submission.id |
|
9 | - unless submission.graded_at |
|
9 | - unless submission.graded_at |
|
10 | .row |
|
10 | .row |
|
11 |
- .col-3. |
|
11 | + .col-3.fw-bold= t 'main.submitted_at' |
|
12 |
- |
|
12 | + .col-9.text-secondary-x= format_full_time_ago(submission.submitted_at.localtime) |
|
13 | - else |
|
13 | - else |
|
14 | .row |
|
14 | .row |
|
15 |
- .col-3. |
|
15 | + .col-3.fw-bold= t 'main.graded_at' |
|
16 |
- |
|
16 | + .col-9.text-secondary-x= format_full_time_ago(submission.graded_at.localtime) |
|
17 | - if GraderConfiguration['ui.show_score'] |
|
17 | - if GraderConfiguration['ui.show_score'] |
|
18 | .row |
|
18 | .row |
|
19 |
- .col-3. |
|
19 | + .col-3.fw-bold=t 'main.score' |
|
20 | - %strong.col-9 |
|
20 | + .col-9.text-secondary-x |
|
21 | = (submission.points*100/submission.problem.full_score).to_i |
|
21 | = (submission.points*100/submission.problem.full_score).to_i |
|
22 | %tt.grader-comment |
|
22 | %tt.grader-comment |
|
23 | = " [#{submission.grader_comment}]" |
|
23 | = " [#{submission.grader_comment}]" |
@@ -2,51 +2,29 | |||||
|
2 | = stylesheet_link_tag 'problems' |
|
2 | = stylesheet_link_tag 'problems' |
|
3 | = javascript_include_tag 'local_jquery' |
|
3 | = javascript_include_tag 'local_jquery' |
|
4 |
|
4 | ||
|
5 | - :javascript |
|
||
|
6 | - $(document).ready( function() { |
|
||
|
7 | - function shiftclick(start,stop,value) { |
|
||
|
8 | - $('tr input').each( function(id,input) { |
|
||
|
9 | - var $input=$(input); |
|
||
|
10 | - var iid=parseInt($input.attr('id').split('-')[2]); |
|
||
|
11 | - if(iid>=start&&iid<=stop){ |
|
||
|
12 | - $input.prop('checked',value) |
|
||
|
13 | - } |
|
||
|
14 | - }); |
|
||
|
15 | - } |
|
||
|
16 | - |
|
||
|
17 | - $('tr input').click( function(e) { |
|
||
|
18 | - if (e.shiftKey) { |
|
||
|
19 | - stop = parseInt($(this).attr('id').split('-')[2]); |
|
||
|
20 | - var orig_stop = stop |
|
||
|
21 | - if (typeof start !== 'undefined') { |
|
||
|
22 | - if (start > stop) { |
|
||
|
23 | - var tmp = start; |
|
||
|
24 | - start = stop; |
|
||
|
25 | - stop = tmp; |
|
||
|
26 | - } |
|
||
|
27 | - shiftclick(start,stop,$(this).is(':checked') ) |
|
||
|
28 | - } |
|
||
|
29 | - start = orig_stop |
|
||
|
30 | - } else { |
|
||
|
31 | - start = parseInt($(this).attr('id').split('-')[2]); |
|
||
|
32 | - } |
|
||
|
33 | - }); |
|
||
|
34 | - }); |
|
||
|
35 |
|
5 | ||
|
36 |
|
6 | ||
|
37 | %h1 Manage problems |
|
7 | %h1 Manage problems |
|
38 |
|
8 | ||
|
39 | %p= link_to '[Back to problem list]', problems_path |
|
9 | %p= link_to '[Back to problem list]', problems_path |
|
40 |
|
10 | ||
|
41 | - = form_tag :action=>'do_manage' do |
|
11 | + = form_with url: do_manage_problems_path do |f| |
|
42 | - .panel.panel-primary |
|
12 | + .card.border-primary.mb-2 |
|
43 | - .panel-heading |
|
13 | + .card-header.text-bg-primary.border-primary |
|
44 | Action |
|
14 | Action |
|
45 |
- . |
|
15 | + .card-body |
|
46 | .submit-box |
|
16 | .submit-box |
|
47 | What do you want to do to the selected problem? |
|
17 | What do you want to do to the selected problem? |
|
48 | %br/ |
|
18 | %br/ |
|
49 | (You can shift-click to select a range of problems) |
|
19 | (You can shift-click to select a range of problems) |
|
|
20 | + .row | ||
|
|
21 | + .col-md-auto | ||
|
|
22 | + = f.check_box :change_date_added, class: 'form-check-input' | ||
|
|
23 | + .col-md-auto | ||
|
|
24 | + .form-check-label | ||
|
|
25 | + Change "Date added" to | ||
|
|
26 | + .col-md-auto | ||
|
|
27 | + | ||
|
50 | %ul.form-inline |
|
28 | %ul.form-inline |
|
51 | %li |
|
29 | %li |
|
52 | Change "Date added" to |
|
30 | Change "Date added" to |
@@ -107,13 +85,45 | |||||
|
107 | = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])" |
|
85 | = "(#{contest.name} [#{link_to 'x', :action => 'remove_contest', :id => problem.id, :contest_id => contest.id }])" |
|
108 |
|
86 | ||
|
109 | :javascript |
|
87 | :javascript |
|
110 | - $('.input-group.date').datetimepicker({ |
|
88 | + |
|
111 | - format: 'DD/MMM/YYYY', |
|
89 | + $(document).on('import-map-loaded', function() { |
|
112 | - showTodayButton: true, |
|
90 | + function shiftclick(start,stop,value) { |
|
113 | - locale: 'en', |
|
91 | + $('tr input').each( function(id,input) { |
|
114 | - widgetPositioning: {horizontal: 'auto', vertical: 'bottom'}, |
|
92 | + var $input=$(input); |
|
|
93 | + var iid=parseInt($input.attr('id').split('-')[2]); | ||
|
|
94 | + if(iid>=start&&iid<=stop){ | ||
|
|
95 | + $input.prop('checked',value) | ||
|
|
96 | + } | ||
|
|
97 | + }); | ||
|
|
98 | + } | ||
|
115 |
|
99 | ||
|
|
100 | + $('tr input').click( function(e) { | ||
|
|
101 | + if (e.shiftKey) { | ||
|
|
102 | + stop = parseInt($(this).attr('id').split('-')[2]); | ||
|
|
103 | + var orig_stop = stop | ||
|
|
104 | + if (typeof start !== 'undefined') { | ||
|
|
105 | + if (start > stop) { | ||
|
|
106 | + var tmp = start; | ||
|
|
107 | + start = stop; | ||
|
|
108 | + stop = tmp; | ||
|
|
109 | + } | ||
|
|
110 | + shiftclick(start,stop,$(this).is(':checked') ) | ||
|
|
111 | + } | ||
|
|
112 | + start = orig_stop | ||
|
|
113 | + } else { | ||
|
|
114 | + start = parseInt($(this).attr('id').split('-')[2]); | ||
|
|
115 | + } | ||
|
|
116 | + }); | ||
|
|
117 | + | ||
|
|
118 | + $('.input-group.date').datetimepicker({ | ||
|
|
119 | + format: 'DD/MMM/YYYY', | ||
|
|
120 | + showTodayButton: true, | ||
|
|
121 | + locale: 'en', | ||
|
|
122 | + widgetPositioning: {horizontal: 'auto', vertical: 'bottom'}, | ||
|
|
123 | + | ||
|
|
124 | + }); | ||
|
|
125 | + | ||
|
|
126 | + $('.datatable').DataTable({ | ||
|
|
127 | + paging: false | ||
|
|
128 | + }); | ||
|
116 | }); |
|
129 | }); |
|
117 | - $('.datatable').DataTable({ |
|
||
|
118 | - paging: false |
|
||
|
119 | - }); |
|
@@ -4,28 +4,34 | |||||
|
4 | } |
|
4 | } |
|
5 |
|
5 | ||
|
6 | %h1 Problem stat: #{@problem.name} |
|
6 | %h1 Problem stat: #{@problem.name} |
|
7 | - %h2 Overview |
|
7 | + |
|
|
8 | + .row.mb-3 | ||
|
|
9 | + .col-md-8 | ||
|
|
10 | + .card | ||
|
|
11 | + .card-body | ||
|
|
12 | + %h2.card-title Submission History | ||
|
|
13 | + %canvas#chart{height: '50px'} | ||
|
8 |
|
14 | ||
|
9 | - .row |
|
15 | + .col-md-4 |
|
10 | - .col-md-2 |
|
16 | + .card |
|
11 | - %strong Name: |
|
17 | + .card-body |
|
12 | - .col-md-10 |
|
18 | + %h2.card-title General Info |
|
13 | - = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 |
|
19 | + .row |
|
14 | - = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem |
|
20 | + .col-sm-6 |
|
15 | - .row |
|
21 | + Name |
|
16 | - .col-md-2.strong |
|
22 | + .col-sm-6 |
|
17 | - %strong Submissions: |
|
23 | + = @problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 |
|
18 | - .col-md-10 |
|
24 | + = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem |
|
19 | - = @submissions.count |
|
25 | + .row |
|
20 | - .row |
|
26 | + .col-sm-6 |
|
21 | - .col-md-2.strong |
|
27 | + Subs |
|
22 | - %strong Solved/Attemped User |
|
28 | + .col-sm-6 |
|
23 | - .col-md-10 |
|
29 | + = @submissions.count |
|
24 | - #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) |
|
30 | + .row |
|
25 | - |
|
31 | + .col-sm-6 |
|
26 | - |
|
32 | + Solved/Attempted User |
|
27 | - %h2 Submissions Count |
|
33 | + .col-sm-6 |
|
28 | - = render partial: 'application/bar_graph', locals: { histogram: @histogram } |
|
34 | + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) |
|
29 |
|
35 | ||
|
30 | %h2 Submissions |
|
36 | %h2 Submissions |
|
31 | - if @submissions and @submissions.count > 0 |
|
37 | - if @submissions and @submissions.count > 0 |
@@ -58,6 +64,27 | |||||
|
58 | No submission |
|
64 | No submission |
|
59 |
|
65 | ||
|
60 | :javascript |
|
66 | :javascript |
|
61 | - $("#main_table").DataTable({ |
|
67 | + $(document).on('import-map-loaded',(e) => { |
|
62 | - paging: false |
|
68 | + //init datatable |
|
|
69 | + $("#main_table").DataTable({ | ||
|
|
70 | + paging: false | ||
|
|
71 | + }); | ||
|
|
72 | + | ||
|
|
73 | + //history graph | ||
|
|
74 | + data = #{@chart_dataset} | ||
|
|
75 | + config = { | ||
|
|
76 | + type: 'bar', | ||
|
|
77 | + data: data, | ||
|
|
78 | + options: { | ||
|
|
79 | + plugins: { | ||
|
|
80 | + legend: { | ||
|
|
81 | + display: false | ||
|
|
82 | + }, | ||
|
|
83 | + }, | ||
|
|
84 | + } | ||
|
|
85 | + } | ||
|
|
86 | + Chart.defaults.font.size = 15 | ||
|
|
87 | + //Chart.defaults.font.family = 'Sarabun Light' | ||
|
|
88 | + chart = new Chart($('#chart'),config) | ||
|
63 | }); |
|
89 | }); |
|
|
90 | + |
@@ -1,42 +1,46 | |||||
|
1 | - - content_for :header do |
|
||
|
2 | - = javascript_include_tag 'local_jquery' |
|
||
|
3 | - |
|
||
|
4 | - :javascript |
|
||
|
5 | - $(function () { |
|
||
|
6 | - $('#submission_table').tablesorter({widgets: ['zebra']}); |
|
||
|
7 | - }); |
|
||
|
8 |
|
|
1 | |
|
9 | :css |
|
2 | :css |
|
10 | .fix-width { |
|
3 | .fix-width { |
|
11 | font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier; |
|
4 | font-family: Droid Sans Mono,Consolas, monospace, mono, Courier New, Courier; |
|
12 | } |
|
5 | } |
|
13 |
|
6 | ||
|
14 | - %h1= @user.full_name |
|
7 | + %h1 User stats |
|
|
8 | + %h5.text-secondary= @user.login | ||
|
|
9 | + | ||
|
|
10 | + .row.my-3 | ||
|
|
11 | + .col-md-8 | ||
|
|
12 | + .card | ||
|
|
13 | + .card-body | ||
|
|
14 | + %h2.card-title Sub Info | ||
|
|
15 | + %canvas#chart{height: '50px'} | ||
|
15 |
|
16 | ||
|
16 | - <b>Login:</b> #{@user.login} <br/> |
|
17 | + .col-md-4 |
|
17 | - <b>Full name:</b> #{@user.full_name} <br /> |
|
18 | + .card |
|
|
19 | + .card-body | ||
|
|
20 | + %h2.card-title General Info | ||
|
|
21 | + .row | ||
|
|
22 | + .col-sm-6.fw-bold | ||
|
|
23 | + Login | ||
|
|
24 | + .col-sm-6 | ||
|
|
25 | + = @user.login | ||
|
|
26 | + .row | ||
|
|
27 | + .col-sm-6.fw-bold | ||
|
|
28 | + Full name | ||
|
|
29 | + .col-sm-6 | ||
|
|
30 | + = @user.full_name | ||
|
|
31 | + .row | ||
|
|
32 | + .col-sm-6.fw-bold | ||
|
|
33 | + Subs | ||
|
|
34 | + .col-sm-6 | ||
|
|
35 | + = @summary[:count] | ||
|
|
36 | + .row | ||
|
|
37 | + .col-sm-6.fw-bold | ||
|
|
38 | + Solved/Attempted Problem | ||
|
|
39 | + .col-sm-6 | ||
|
|
40 | + #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) | ||
|
18 |
|
41 | ||
|
19 |
|
42 | ||
|
20 | - %h2 Problem Stat |
|
43 | + %table#main_table.table.table-striped |
|
21 | - %table.info |
|
||
|
22 | - %thead |
|
||
|
23 | - %tr.info-head |
|
||
|
24 | - %th Stat |
|
||
|
25 | - %th Value |
|
||
|
26 | - %tbody |
|
||
|
27 | - %tr{class: cycle('info-even','info-odd')} |
|
||
|
28 | - %td.info_param Submissions |
|
||
|
29 | - %td= @summary[:count] |
|
||
|
30 | - %tr{class: cycle('info-even','info-odd')} |
|
||
|
31 | - %td.info_param Solved/Attempted Problem |
|
||
|
32 | - %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%) |
|
||
|
33 | - |
|
||
|
34 | - %h2 Submission History |
|
||
|
35 | - |
|
||
|
36 | - =render partial: 'application/bar_graph', locals: {histogram: @histogram, param: {bar_width: 7}} |
|
||
|
37 | - |
|
||
|
38 | - |
|
||
|
39 | - %table#submission_table.table.table-striped |
|
||
|
40 | %thead |
|
44 | %thead |
|
41 | %tr |
|
45 | %tr |
|
42 | %th ID |
|
46 | %th ID |
@@ -65,6 +69,27 | |||||
|
65 |
|
69 | ||
|
66 |
|
70 | ||
|
67 | :javascript |
|
71 | :javascript |
|
68 | - $("#submission_table").DataTable({ |
|
72 | + $(document).on('import-map-loaded',(e) => { |
|
69 | - paging: false |
|
73 | + //init datatable |
|
|
74 | + $("#main_table").DataTable({ | ||
|
|
75 | + paging: false | ||
|
|
76 | + }); | ||
|
|
77 | + | ||
|
|
78 | + //history graph | ||
|
|
79 | + data = #{@chart_dataset} | ||
|
|
80 | + config = { | ||
|
|
81 | + type: 'bar', | ||
|
|
82 | + data: data, | ||
|
|
83 | + options: { | ||
|
|
84 | + plugins: { | ||
|
|
85 | + legend: { | ||
|
|
86 | + display: false | ||
|
|
87 | + }, | ||
|
|
88 | + }, | ||
|
|
89 | + } | ||
|
|
90 | + } | ||
|
|
91 | + Chart.defaults.font.size = 15 | ||
|
|
92 | + //Chart.defaults.font.family = 'Sarabun Light' | ||
|
|
93 | + chart = new Chart($('#chart'),config) | ||
|
70 | }); |
|
94 | }); |
|
|
95 | + |
deleted file |
You need to be logged in to leave comments.
Login now