Description:
- add problem toggle test js reponse (it was forgotten)
- change score report to bootstrap-sortable
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r570:0b74eb4e28fa - - 8 files changed: 77 inserted, 25 deleted
@@ -0,0 +1,2 | |||
|
1 | + = render partial: 'toggle_button', | |
|
2 | + locals: {button_id: "#problem-test-#{@problem.id}",button_on: @problem.test_allowed?} |
@@ -1,75 +1,79 | |||
|
1 | 1 | source 'https://rubygems.org' |
|
2 | 2 | |
|
3 | 3 | gem 'rails', '3.2.21' |
|
4 | 4 | |
|
5 | 5 | gem 'select2-rails' |
|
6 | 6 | |
|
7 | 7 | # Bundle edge Rails instead: |
|
8 | 8 | # gem 'rails', :git => 'git://github.com/rails/rails.git' |
|
9 | 9 | |
|
10 | 10 | gem 'mysql2' |
|
11 | 11 | |
|
12 | 12 | # Gems used only for assets and not required |
|
13 | 13 | # in production environments by default. |
|
14 | 14 | group :assets do |
|
15 | 15 | gem 'sass-rails', '~> 3.2.6' |
|
16 | 16 | gem 'coffee-rails', '~> 3.2.2' |
|
17 | 17 | |
|
18 | 18 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes |
|
19 | 19 | # gem 'therubyracer', :platforms => :ruby |
|
20 | 20 | |
|
21 | 21 | gem 'uglifier' |
|
22 | 22 | end |
|
23 | 23 | |
|
24 | 24 | gem 'prototype-rails' |
|
25 | 25 | |
|
26 | 26 | # To use ActiveModel has_secure_password |
|
27 | 27 | # gem 'bcrypt-ruby', '~> 3.0.0' |
|
28 | 28 | |
|
29 | 29 | # To use Jbuilder templates for JSON |
|
30 | 30 | # gem 'jbuilder' |
|
31 | 31 | |
|
32 | 32 | # Use unicorn as the app server |
|
33 | 33 | # gem 'unicorn' |
|
34 | 34 | |
|
35 | 35 | # Deploy with Capistrano |
|
36 | 36 | # gem 'capistrano' |
|
37 | 37 | |
|
38 | 38 | # To use debugger |
|
39 | 39 | # gem 'debugger' |
|
40 | 40 | # |
|
41 | 41 | |
|
42 | 42 | #in-place editor |
|
43 | 43 | gem 'best_in_place', '~> 3.0.1' |
|
44 | 44 | |
|
45 | 45 | # jquery addition |
|
46 | 46 | gem 'jquery-rails' |
|
47 | 47 | gem 'jquery-ui-sass-rails' |
|
48 | 48 | gem 'jquery-timepicker-addon-rails' |
|
49 | 49 | gem 'jquery-tablesorter' |
|
50 | 50 | |
|
51 | 51 | #syntax highlighter |
|
52 | 52 | gem 'rouge' |
|
53 | 53 | |
|
54 | 54 | #add bootstrap |
|
55 | 55 | gem 'bootstrap-sass', '~> 3.2.0' |
|
56 | 56 | gem 'bootstrap-switch-rails' |
|
57 | 57 | gem 'bootstrap-toggle-rails' |
|
58 | 58 | gem 'autoprefixer-rails' |
|
59 | 59 | |
|
60 | + #bootstrap sortable | |
|
61 | + gem 'momentjs-rails' | |
|
62 | + gem 'rails_bootstrap_sortable' | |
|
63 | + | |
|
64 | + #ace editor | |
|
60 | 65 | gem 'ace-rails-ap' |
|
61 | 66 | |
|
62 | - | |
|
63 | 67 | gem 'haml' |
|
64 | 68 | gem 'haml-rails' |
|
65 | 69 | gem 'mail' |
|
66 | 70 | gem 'rdiscount' |
|
67 | 71 | gem 'test-unit' |
|
68 | 72 | gem 'will_paginate', '~> 3.0.7' |
|
69 | 73 | gem 'dynamic_form' |
|
70 | 74 | gem 'in_place_editing' |
|
71 | 75 | gem 'verification', :git => 'https://github.com/sikachu/verification.git' |
|
72 | 76 | |
|
73 | 77 | group :test, :development do |
|
74 | 78 | gem 'rspec-rails', '~> 2.99.0' |
|
75 | 79 | end |
@@ -1,197 +1,203 | |||
|
1 | 1 | GIT |
|
2 | 2 | remote: https://github.com/sikachu/verification.git |
|
3 | 3 | revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d |
|
4 | 4 | specs: |
|
5 | 5 | verification (1.0.3) |
|
6 | 6 | actionpack (>= 3.0.0, < 5.0) |
|
7 | 7 | activesupport (>= 3.0.0, < 5.0) |
|
8 | 8 | |
|
9 | 9 | GEM |
|
10 | 10 | remote: https://rubygems.org/ |
|
11 | 11 | specs: |
|
12 | 12 | ace-rails-ap (4.0.2) |
|
13 | 13 | actionmailer (3.2.21) |
|
14 | 14 | actionpack (= 3.2.21) |
|
15 | 15 | mail (~> 2.5.4) |
|
16 | 16 | actionpack (3.2.21) |
|
17 | 17 | activemodel (= 3.2.21) |
|
18 | 18 | activesupport (= 3.2.21) |
|
19 | 19 | builder (~> 3.0.0) |
|
20 | 20 | erubis (~> 2.7.0) |
|
21 | 21 | journey (~> 1.0.4) |
|
22 | 22 | rack (~> 1.4.5) |
|
23 | 23 | rack-cache (~> 1.2) |
|
24 | 24 | rack-test (~> 0.6.1) |
|
25 | 25 | sprockets (~> 2.2.1) |
|
26 | 26 | activemodel (3.2.21) |
|
27 | 27 | activesupport (= 3.2.21) |
|
28 | 28 | builder (~> 3.0.0) |
|
29 | 29 | activerecord (3.2.21) |
|
30 | 30 | activemodel (= 3.2.21) |
|
31 | 31 | activesupport (= 3.2.21) |
|
32 | 32 | arel (~> 3.0.2) |
|
33 | 33 | tzinfo (~> 0.3.29) |
|
34 | 34 | activeresource (3.2.21) |
|
35 | 35 | activemodel (= 3.2.21) |
|
36 | 36 | activesupport (= 3.2.21) |
|
37 | 37 | activesupport (3.2.21) |
|
38 | 38 | i18n (~> 0.6, >= 0.6.4) |
|
39 | 39 | multi_json (~> 1.0) |
|
40 | 40 | arel (3.0.3) |
|
41 | 41 | autoprefixer-rails (6.0.3) |
|
42 | 42 | execjs |
|
43 | 43 | json |
|
44 | 44 | best_in_place (3.0.3) |
|
45 | 45 | actionpack (>= 3.2) |
|
46 | 46 | railties (>= 3.2) |
|
47 | 47 | bootstrap-sass (3.2.0.2) |
|
48 | 48 | sass (~> 3.2) |
|
49 | 49 | bootstrap-switch-rails (3.3.3) |
|
50 | 50 | bootstrap-toggle-rails (2.2.1.0) |
|
51 | 51 | builder (3.0.4) |
|
52 | 52 | coffee-rails (3.2.2) |
|
53 | 53 | coffee-script (>= 2.2.0) |
|
54 | 54 | railties (~> 3.2.0) |
|
55 | 55 | coffee-script (2.3.0) |
|
56 | 56 | coffee-script-source |
|
57 | 57 | execjs |
|
58 | 58 | coffee-script-source (1.9.0) |
|
59 | 59 | diff-lcs (1.2.5) |
|
60 | 60 | dynamic_form (1.1.4) |
|
61 | 61 | erubis (2.7.0) |
|
62 | 62 | execjs (2.3.0) |
|
63 | 63 | haml (4.0.6) |
|
64 | 64 | tilt |
|
65 | 65 | haml-rails (0.4) |
|
66 | 66 | actionpack (>= 3.1, < 4.1) |
|
67 | 67 | activesupport (>= 3.1, < 4.1) |
|
68 | 68 | haml (>= 3.1, < 4.1) |
|
69 | 69 | railties (>= 3.1, < 4.1) |
|
70 | 70 | hike (1.2.3) |
|
71 | 71 | i18n (0.7.0) |
|
72 | 72 | in_place_editing (1.2.0) |
|
73 | 73 | journey (1.0.4) |
|
74 | 74 | jquery-rails (3.1.2) |
|
75 | 75 | railties (>= 3.0, < 5.0) |
|
76 | 76 | thor (>= 0.14, < 2.0) |
|
77 | 77 | jquery-tablesorter (1.13.4) |
|
78 | 78 | railties (>= 3.1, < 5) |
|
79 | 79 | jquery-timepicker-addon-rails (1.4.1) |
|
80 | 80 | railties (>= 3.1) |
|
81 | 81 | jquery-ui-rails (4.0.3) |
|
82 | 82 | jquery-rails |
|
83 | 83 | railties (>= 3.1.0) |
|
84 | 84 | jquery-ui-sass-rails (4.0.3.0) |
|
85 | 85 | jquery-rails |
|
86 | 86 | jquery-ui-rails (= 4.0.3) |
|
87 | 87 | railties (>= 3.1.0) |
|
88 | 88 | json (1.8.2) |
|
89 | 89 | mail (2.5.4) |
|
90 | 90 | mime-types (~> 1.16) |
|
91 | 91 | treetop (~> 1.4.8) |
|
92 | 92 | mime-types (1.25.1) |
|
93 | + momentjs-rails (2.11.1) | |
|
94 | + railties (>= 3.1) | |
|
93 | 95 | multi_json (1.10.1) |
|
94 | 96 | mysql2 (0.3.20) |
|
95 | 97 | polyglot (0.3.5) |
|
96 | 98 | power_assert (0.2.2) |
|
97 | 99 | prototype-rails (3.2.1) |
|
98 | 100 | rails (~> 3.2) |
|
99 | 101 | rack (1.4.5) |
|
100 | 102 | rack-cache (1.2) |
|
101 | 103 | rack (>= 0.4) |
|
102 | 104 | rack-ssl (1.3.4) |
|
103 | 105 | rack |
|
104 | 106 | rack-test (0.6.3) |
|
105 | 107 | rack (>= 1.0) |
|
106 | 108 | rails (3.2.21) |
|
107 | 109 | actionmailer (= 3.2.21) |
|
108 | 110 | actionpack (= 3.2.21) |
|
109 | 111 | activerecord (= 3.2.21) |
|
110 | 112 | activeresource (= 3.2.21) |
|
111 | 113 | activesupport (= 3.2.21) |
|
112 | 114 | bundler (~> 1.0) |
|
113 | 115 | railties (= 3.2.21) |
|
116 | + rails_bootstrap_sortable (2.0.0) | |
|
117 | + momentjs-rails (~> 2, >= 2.8.3) | |
|
114 | 118 | railties (3.2.21) |
|
115 | 119 | actionpack (= 3.2.21) |
|
116 | 120 | activesupport (= 3.2.21) |
|
117 | 121 | rack-ssl (~> 1.3.2) |
|
118 | 122 | rake (>= 0.8.7) |
|
119 | 123 | rdoc (~> 3.4) |
|
120 | 124 | thor (>= 0.14.6, < 2.0) |
|
121 | 125 | rake (10.4.2) |
|
122 | 126 | rdiscount (2.1.8) |
|
123 | 127 | rdoc (3.12.2) |
|
124 | 128 | json (~> 1.4) |
|
125 | 129 | rouge (1.8.0) |
|
126 | 130 | rspec-collection_matchers (1.1.2) |
|
127 | 131 | rspec-expectations (>= 2.99.0.beta1) |
|
128 | 132 | rspec-core (2.99.2) |
|
129 | 133 | rspec-expectations (2.99.2) |
|
130 | 134 | diff-lcs (>= 1.1.3, < 2.0) |
|
131 | 135 | rspec-mocks (2.99.3) |
|
132 | 136 | rspec-rails (2.99.0) |
|
133 | 137 | actionpack (>= 3.0) |
|
134 | 138 | activemodel (>= 3.0) |
|
135 | 139 | activesupport (>= 3.0) |
|
136 | 140 | railties (>= 3.0) |
|
137 | 141 | rspec-collection_matchers |
|
138 | 142 | rspec-core (~> 2.99.0) |
|
139 | 143 | rspec-expectations (~> 2.99.0) |
|
140 | 144 | rspec-mocks (~> 2.99.0) |
|
141 | 145 | sass (3.4.11) |
|
142 | 146 | sass-rails (3.2.6) |
|
143 | 147 | railties (~> 3.2.0) |
|
144 | 148 | sass (>= 3.1.10) |
|
145 | 149 | tilt (~> 1.3) |
|
146 | 150 | select2-rails (4.0.1) |
|
147 | 151 | thor (~> 0.14) |
|
148 | 152 | sprockets (2.2.3) |
|
149 | 153 | hike (~> 1.2) |
|
150 | 154 | multi_json (~> 1.0) |
|
151 | 155 | rack (~> 1.0) |
|
152 | 156 | tilt (~> 1.1, != 1.3.0) |
|
153 | 157 | test-unit (3.0.9) |
|
154 | 158 | power_assert |
|
155 | 159 | thor (0.19.1) |
|
156 | 160 | tilt (1.4.1) |
|
157 | 161 | treetop (1.4.15) |
|
158 | 162 | polyglot |
|
159 | 163 | polyglot (>= 0.3.1) |
|
160 | 164 | tzinfo (0.3.43) |
|
161 | 165 | uglifier (2.7.0) |
|
162 | 166 | execjs (>= 0.3.0) |
|
163 | 167 | json (>= 1.8.0) |
|
164 | 168 | will_paginate (3.0.7) |
|
165 | 169 | |
|
166 | 170 | PLATFORMS |
|
167 | 171 | ruby |
|
168 | 172 | |
|
169 | 173 | DEPENDENCIES |
|
170 | 174 | ace-rails-ap |
|
171 | 175 | autoprefixer-rails |
|
172 | 176 | best_in_place (~> 3.0.1) |
|
173 | 177 | bootstrap-sass (~> 3.2.0) |
|
174 | 178 | bootstrap-switch-rails |
|
175 | 179 | bootstrap-toggle-rails |
|
176 | 180 | coffee-rails (~> 3.2.2) |
|
177 | 181 | dynamic_form |
|
178 | 182 | haml |
|
179 | 183 | haml-rails |
|
180 | 184 | in_place_editing |
|
181 | 185 | jquery-rails |
|
182 | 186 | jquery-tablesorter |
|
183 | 187 | jquery-timepicker-addon-rails |
|
184 | 188 | jquery-ui-sass-rails |
|
185 | 189 | |
|
190 | + momentjs-rails | |
|
186 | 191 | mysql2 |
|
187 | 192 | prototype-rails |
|
188 | 193 | rails (= 3.2.21) |
|
194 | + rails_bootstrap_sortable | |
|
189 | 195 | rdiscount |
|
190 | 196 | rouge |
|
191 | 197 | rspec-rails (~> 2.99.0) |
|
192 | 198 | sass-rails (~> 3.2.6) |
|
193 | 199 | select2-rails |
|
194 | 200 | test-unit |
|
195 | 201 | uglifier |
|
196 | 202 | verification! |
|
197 | 203 | will_paginate (~> 3.0.7) |
@@ -1,35 +1,35 | |||
|
1 | 1 | // This is a manifest file that'll be compiled into application.js, which will include all the files |
|
2 | 2 | // listed below. |
|
3 | 3 | // |
|
4 | 4 | // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts, |
|
5 | 5 | // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path. |
|
6 | 6 | // |
|
7 | 7 | // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the |
|
8 | 8 | // the compiled file. |
|
9 | 9 | // |
|
10 | 10 | // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD |
|
11 | 11 | // GO AFTER THE REQUIRES BELOW. |
|
12 | 12 | // |
|
13 | 13 | //= require jquery |
|
14 | 14 | //= require jquery_ujs |
|
15 | 15 | //= require jquery.ui.all |
|
16 | 16 | //= require bootstrap-sprockets |
|
17 | - //x= require bootstrap-switch | |
|
18 |
- //= require bootstrap- |
|
|
17 | + //= require moment | |
|
18 | + //= require bootstrap-sortable | |
|
19 | 19 | //= require select2 |
|
20 | 20 | //= require custom |
|
21 | 21 | //= require ace-rails-ap |
|
22 | 22 | //= require ace/mode-c_cpp |
|
23 | 23 | //= require ace/mode-ruby |
|
24 | 24 | //= require ace/mode-pascal |
|
25 | 25 | //= require ace/mode-javascript |
|
26 | 26 | //= require ace/mode-java |
|
27 | 27 | //= require ace/theme-merbivore |
|
28 | 28 | |
|
29 | 29 | |
|
30 | 30 | // since this is after blank line, it is not downloaded |
|
31 | 31 | //x= require prototype |
|
32 | 32 | //x= require prototype_ujs |
|
33 | 33 | //x= require effects |
|
34 | 34 | //x= require dragdrop |
|
35 | 35 | //x= require controls |
@@ -1,47 +1,47 | |||
|
1 | 1 | $(document).on 'change', '.btn-file :file', -> |
|
2 | 2 | input = $(this) |
|
3 | 3 | numFiles = if input.get(0).files then input.get(0).files.length else 1 |
|
4 | 4 | label = input.val().replace(/\\/g, '/').replace(/.*\//, '') |
|
5 | 5 | input.trigger 'fileselect', [ |
|
6 | 6 | numFiles |
|
7 | 7 | label |
|
8 | 8 | ] |
|
9 | 9 | return |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | # document ready |
|
13 | 13 | |
|
14 | 14 | $ -> |
|
15 | 15 | $(".select2").select2() |
|
16 | 16 | #$(".bootstrap-switch").bootstrapSwitch() |
|
17 | 17 | $(".bootstrap-toggle").bootstrapToggle() |
|
18 | 18 | $('.btn-file :file').on 'fileselect', (event, numFiles, label) -> |
|
19 | 19 | input = $(this).parents('.input-group').find(':text') |
|
20 | 20 | log = if numFiles > 1 then numFiles + ' files selected' else label |
|
21 | 21 | if input.length |
|
22 | 22 | input.val log |
|
23 | 23 | else |
|
24 | 24 | if log |
|
25 | 25 | alert log |
|
26 | 26 | return |
|
27 | 27 | $(".go-button").on 'click', (event) -> |
|
28 | 28 | link = $(this).attr("data-source") |
|
29 | 29 | url = $(link).val() |
|
30 | 30 | if url |
|
31 | 31 | window.location.href = url |
|
32 | 32 | return |
|
33 | 33 | $('.ajax-toggle').on 'click', (event) -> |
|
34 | 34 | target = $(event.target) |
|
35 | 35 | target.removeClass 'btn-default' |
|
36 | 36 | target.removeClass 'btn-success' |
|
37 | 37 | target.addClass 'btn-warning' |
|
38 | 38 | target.text '...' |
|
39 | 39 | return |
|
40 | - | |
|
40 | + | |
|
41 | 41 | #ace editor |
|
42 | 42 | e = ace.edit("editor") |
|
43 | 43 | e.setTheme('ace/theme/merbivore') |
|
44 | 44 | e.getSession().setTabSize(2) |
|
45 | 45 | e.getSession().setUseSoftTabs(true) |
|
46 | 46 | |
|
47 | 47 | return |
@@ -1,420 +1,433 | |||
|
1 | 1 | /* |
|
2 | 2 | * This is a manifest file that'll be compiled into application.css, which will include all the files |
|
3 | 3 | * listed below. |
|
4 | 4 | * |
|
5 | 5 | * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets, |
|
6 | 6 | * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path. |
|
7 | 7 | * |
|
8 | 8 | * You're free to add application-wide styles to this file and they'll appear at the bottom of the |
|
9 | 9 | * compiled file so the styles you add here take precedence over styles defined in any styles |
|
10 | 10 | * defined in the other CSS/SCSS files in this directory. It is generally better to create a new |
|
11 | 11 | * file per style scope. |
|
12 | 12 | * |
|
13 | 13 | // bootstrap says that we should not do this, but @import each file instead |
|
14 | 14 | # *= require_tree . |
|
15 | 15 | # *= require_self |
|
16 | 16 | */ |
|
17 | 17 | |
|
18 | 18 | @import jquery.ui.all |
|
19 | 19 | @import jquery.ui.core |
|
20 | 20 | @import jquery.ui.core |
|
21 | 21 | @import jquery.ui.theme |
|
22 | 22 | @import jquery.ui.datepicker |
|
23 | 23 | @import jquery.ui.slider |
|
24 | 24 | @import jquery-ui-timepicker-addon |
|
25 | 25 | @import jquery-tablesorter/theme.metro-dark |
|
26 | 26 | @import tablesorter-theme.cafe |
|
27 | 27 | |
|
28 | 28 | //bootstrap |
|
29 | 29 | @import bootstrap-sprockets |
|
30 | 30 | @import bootstrap |
|
31 | 31 | @import select2 |
|
32 | 32 | @import select2-bootstrap |
|
33 | 33 | //@import bootstrap3-switch |
|
34 | 34 | @import bootstrap-toggle |
|
35 | + @import bootstrap-sortable | |
|
35 | 36 | |
|
36 | 37 | //bootstrap navbar color (from) |
|
37 | 38 | $bgDefault : #19197b |
|
38 | 39 | $bgHighlight : #06064b |
|
39 | 40 | $colDefault : #8e8eb4 |
|
40 | 41 | $colHighlight : #ffffff |
|
41 | 42 | $dropDown : false |
|
42 | 43 | .navbar-default |
|
43 | 44 | background-color: $bgDefault |
|
44 | 45 | border-color: $bgHighlight |
|
45 | 46 | .navbar-brand |
|
46 | 47 | color: $colDefault |
|
47 | 48 | &:hover, &:focus |
|
48 | 49 | color: $colHighlight |
|
49 | 50 | .navbar-text |
|
50 | 51 | color: $colDefault |
|
51 | 52 | .navbar-nav |
|
52 | 53 | > li |
|
53 | 54 | > a |
|
54 | 55 | color: $colDefault |
|
55 | 56 | &:hover, &:focus |
|
56 | 57 | color: $colHighlight |
|
57 | 58 | @if $dropDown |
|
58 | 59 | > .dropdown-menu |
|
59 | 60 | background-color: $bgDefault |
|
60 | 61 | > li |
|
61 | 62 | > a |
|
62 | 63 | color: $colDefault |
|
63 | 64 | &:hover, &:focus |
|
64 | 65 | color: $colHighlight |
|
65 | 66 | background-color: $bgHighlight |
|
66 | 67 | > .divider |
|
67 | 68 | background-color: $bgHighlight |
|
68 | 69 | @if $dropDown |
|
69 | 70 | .open .dropdown-menu > .active |
|
70 | 71 | > a, > a:hover, > a:focus |
|
71 | 72 | color: $colHighlight |
|
72 | 73 | background-color: $bgHighlight |
|
73 | 74 | > .active |
|
74 | 75 | > a, > a:hover, > a:focus |
|
75 | 76 | color: $colHighlight |
|
76 | 77 | background-color: $bgHighlight |
|
77 | 78 | > .open |
|
78 | 79 | > a, > a:hover, > a:focus |
|
79 | 80 | color: $colHighlight |
|
80 | 81 | background-color: $bgHighlight |
|
81 | 82 | .navbar-toggle |
|
82 | 83 | border-color: $bgHighlight |
|
83 | 84 | &:hover, &:focus |
|
84 | 85 | background-color: $bgHighlight |
|
85 | 86 | .icon-bar |
|
86 | 87 | background-color: $colDefault |
|
87 | 88 | .navbar-collapse, |
|
88 | 89 | .navbar-form |
|
89 | 90 | border-color: $colDefault |
|
90 | 91 | .navbar-link |
|
91 | 92 | color: $colDefault |
|
92 | 93 | &:hover |
|
93 | 94 | color: $colHighlight |
|
94 | 95 | @media (max-width: 767px) |
|
95 | 96 | .navbar-default .navbar-nav .open .dropdown-menu |
|
96 | 97 | > li > a |
|
97 | 98 | color: $colDefault |
|
98 | 99 | &:hover, &:focus |
|
99 | 100 | color: $colHighlight |
|
100 | 101 | > .active |
|
101 | 102 | > a, > a:hover, > a:focus |
|
102 | 103 | color: $colHighlight |
|
103 | 104 | background-color: $bgHighlight |
|
104 | 105 | |
|
105 | 106 | .secondnavbar |
|
106 | 107 | top: 50px |
|
107 | 108 | |
|
109 | + | |
|
110 | + // --------------- bootstrap file upload ---------------------- | |
|
108 | 111 | .btn-file |
|
109 | 112 | position: relative |
|
110 | 113 | overflow: hidden |
|
111 | 114 | |
|
112 | 115 | .btn-file input[type=file] |
|
113 | 116 | position: absolute |
|
114 | 117 | top: 0 |
|
115 | 118 | right: 0 |
|
116 | 119 | min-width: 100% |
|
117 | 120 | min-height: 100% |
|
118 | 121 | font-size: 100px |
|
119 | 122 | text-align: right |
|
120 | 123 | filter: alpha(opacity=0) |
|
121 | 124 | opacity: 0 |
|
122 | 125 | outline: none |
|
123 | 126 | background: white |
|
124 | 127 | cursor: inherit |
|
125 | 128 | display: block |
|
126 | 129 | |
|
127 | 130 | body |
|
128 | 131 | background: white image-url("topbg.jpg") repeat-x top center |
|
129 | 132 | //font-size: 13px |
|
130 | 133 | //font-family: Tahoma, "sans-serif" |
|
131 | 134 | margin: 10px |
|
132 | 135 | padding: 10px |
|
133 |
- padding-top: |
|
|
136 | + padding-top: 60px | |
|
134 | 137 | |
|
138 | + // ------------------ bootstrap sortable -------------------- | |
|
139 | + table.sortable th | |
|
140 | + padding-right: 20px !important | |
|
141 | + span.sign | |
|
142 | + right: -15px !important | |
|
143 | + &.text-right | |
|
144 | + padding-left: 20px !important | |
|
145 | + padding-right: 8px !important | |
|
146 | + &:after, span.sign | |
|
147 | + left: -15px !important | |
|
135 | 148 | |
|
136 | 149 | input |
|
137 | 150 | font-family: Tahoma, "sans-serif" |
|
138 | 151 | |
|
139 | 152 | |
|
140 | 153 | h1 |
|
141 | 154 | font-size: 24px |
|
142 | 155 | color: #334488 |
|
143 | 156 | line-height: 2em |
|
144 | 157 | |
|
145 | 158 | |
|
146 | 159 | h2 |
|
147 | 160 | font-size: 18px |
|
148 | 161 | color: #5566bb |
|
149 | 162 | line-height: 1.5em |
|
150 | 163 | |
|
151 | 164 | |
|
152 | 165 | hr |
|
153 | 166 | border-top: 1px solid #dddddd |
|
154 | 167 | border-bottom: 1px solid #eeeeee |
|
155 | 168 | |
|
156 | 169 | |
|
157 | 170 | //#a |
|
158 | 171 | // color: #6666cc |
|
159 | 172 | // text-decoration: none |
|
160 | 173 | // |
|
161 | 174 | // &:link, &:visited |
|
162 | 175 | // color: #6666cc |
|
163 | 176 | // text-decoration: none |
|
164 | 177 | // |
|
165 | 178 | // &:hover, &:focus |
|
166 | 179 | // color: #111166 |
|
167 | 180 | // text-decoration: none |
|
168 | 181 | |
|
169 | 182 | |
|
170 | 183 | div |
|
171 | 184 | &.userbar |
|
172 | 185 | line-height: 1.5em |
|
173 | 186 | text-align: right |
|
174 | 187 | font-size: 12px |
|
175 | 188 | |
|
176 | 189 | &.title |
|
177 | 190 | padding: 10px 0px |
|
178 | 191 | line-height: 1.5em |
|
179 | 192 | font-size: 13px |
|
180 | 193 | |
|
181 | 194 | span.contest-over-msg |
|
182 | 195 | font-size: 15px |
|
183 | 196 | color: red |
|
184 | 197 | |
|
185 | 198 | table |
|
186 | 199 | width: 100% |
|
187 | 200 | font-weight: bold |
|
188 | 201 | |
|
189 | 202 | td |
|
190 | 203 | &.left-col |
|
191 | 204 | text-align: left |
|
192 | 205 | vertical-align: top |
|
193 | 206 | color: #444444 |
|
194 | 207 | |
|
195 | 208 | &.right-col |
|
196 | 209 | text-align: right |
|
197 | 210 | vertical-align: top |
|
198 | 211 | font-size: 18px |
|
199 | 212 | color: #116699 |
|
200 | 213 | |
|
201 | 214 | |
|
202 | 215 | table.info |
|
203 | 216 | margin: 10px 0 |
|
204 | 217 | border: 1px solid #666666 |
|
205 | 218 | border-collapse: collapse |
|
206 | 219 | font-size: 12px |
|
207 | 220 | |
|
208 | 221 | th |
|
209 | 222 | border: 1px solid #666666 |
|
210 | 223 | line-height: 1.5em |
|
211 | 224 | padding: 0 0.5em |
|
212 | 225 | |
|
213 | 226 | td |
|
214 | 227 | border-left: 1px solid #666666 |
|
215 | 228 | border-right: 1px solid #666666 |
|
216 | 229 | line-height: 1.5em |
|
217 | 230 | padding: 0 0.5em |
|
218 | 231 | |
|
219 | 232 | |
|
220 | 233 | tr |
|
221 | 234 | &.info-head |
|
222 | 235 | background: #777777 |
|
223 | 236 | color: white |
|
224 | 237 | |
|
225 | 238 | &.info-odd |
|
226 | 239 | background: #eeeeee |
|
227 | 240 | |
|
228 | 241 | &.info-even |
|
229 | 242 | background: #fcfcfc |
|
230 | 243 | |
|
231 | 244 | =basicbox |
|
232 | 245 | background: #eeeeff |
|
233 | 246 | border: 1px dotted #99aaee |
|
234 | 247 | padding: 5px |
|
235 | 248 | margin: 10px 0px |
|
236 | 249 | color: black |
|
237 | 250 | font-size: 13px |
|
238 | 251 | |
|
239 | 252 | .infobox |
|
240 | 253 | +basicbox |
|
241 | 254 | |
|
242 | 255 | .submitbox |
|
243 | 256 | +basicbox |
|
244 | 257 | |
|
245 | 258 | .errorExplanation |
|
246 | 259 | border: 1px dotted gray |
|
247 | 260 | color: #bb2222 |
|
248 | 261 | padding: 5px 15px 5px 15px |
|
249 | 262 | margin-bottom: 5px |
|
250 | 263 | background-color: white |
|
251 | 264 | font-weight: normal |
|
252 | 265 | |
|
253 | 266 | h2 |
|
254 | 267 | color: #cc1111 |
|
255 | 268 | font-weight: bold |
|
256 | 269 | |
|
257 | 270 | |
|
258 | 271 | table.uinfo |
|
259 | 272 | border-collapse: collapse |
|
260 | 273 | border: 1px solid black |
|
261 | 274 | font-size: 13px |
|
262 | 275 | |
|
263 | 276 | |
|
264 | 277 | td.uinfo |
|
265 | 278 | vertical-align: top |
|
266 | 279 | border: 1px solid black |
|
267 | 280 | padding: 5px |
|
268 | 281 | |
|
269 | 282 | |
|
270 | 283 | th.uinfo |
|
271 | 284 | background: lightgreen |
|
272 | 285 | vertical-align: top |
|
273 | 286 | text-align: right |
|
274 | 287 | border: 1px solid black |
|
275 | 288 | padding: 5px |
|
276 | 289 | |
|
277 | 290 | |
|
278 | 291 | div |
|
279 | 292 | &.compilermsgbody |
|
280 | 293 | font-family: monospace |
|
281 | 294 | |
|
282 | 295 | &.task-menu |
|
283 | 296 | text-align: center |
|
284 | 297 | font-size: 13px |
|
285 | 298 | line-height: 1.75em |
|
286 | 299 | font-weight: bold |
|
287 | 300 | border-top: 1px dashed gray |
|
288 | 301 | border-bottom: 1px dashed gray |
|
289 | 302 | margin-top: 2px |
|
290 | 303 | margin-bottom: 4px |
|
291 | 304 | |
|
292 | 305 | |
|
293 | 306 | table.taskdesc |
|
294 | 307 | border: 2px solid #dddddd |
|
295 | 308 | border-collapse: collapse |
|
296 | 309 | margin: 10px auto |
|
297 | 310 | width: 90% |
|
298 | 311 | font-size: 13px |
|
299 | 312 | |
|
300 | 313 | p |
|
301 | 314 | font-size: 13px |
|
302 | 315 | |
|
303 | 316 | tr.name |
|
304 | 317 | border: 2px solid #dddddd |
|
305 | 318 | background: #dddddd |
|
306 | 319 | color: #333333 |
|
307 | 320 | font-weight: bold |
|
308 | 321 | font-size: 14px |
|
309 | 322 | line-height: 1.5em |
|
310 | 323 | text-align: center |
|
311 | 324 | |
|
312 | 325 | td |
|
313 | 326 | &.desc-odd |
|
314 | 327 | padding: 5px |
|
315 | 328 | padding-left: 20px |
|
316 | 329 | background: #fefeee |
|
317 | 330 | |
|
318 | 331 | &.desc-even |
|
319 | 332 | padding: 5px |
|
320 | 333 | padding-left: 20px |
|
321 | 334 | background: #feeefe |
|
322 | 335 | |
|
323 | 336 | |
|
324 | 337 | .announcementbox |
|
325 | 338 | margin: 10px 0px |
|
326 | 339 | background: #bbddee |
|
327 | 340 | padding: 1px |
|
328 | 341 | |
|
329 | 342 | span.title |
|
330 | 343 | font-weight: bold |
|
331 | 344 | color: #224455 |
|
332 | 345 | padding-left: 10px |
|
333 | 346 | line-height: 1.6em |
|
334 | 347 | |
|
335 | 348 | .announcement |
|
336 | 349 | margin: 2px |
|
337 | 350 | background: white |
|
338 | 351 | padding: 1px |
|
339 | 352 | padding-left: 10px |
|
340 | 353 | padding-right: 10px |
|
341 | 354 | padding-top: 5px |
|
342 | 355 | padding-bottom: 5px |
|
343 | 356 | |
|
344 | 357 | |
|
345 | 358 | .announcement p |
|
346 | 359 | font-size: 12px |
|
347 | 360 | margin: 2px |
|
348 | 361 | |
|
349 | 362 | |
|
350 | 363 | .pub-info |
|
351 | 364 | text-align: right |
|
352 | 365 | font-style: italic |
|
353 | 366 | font-size: 9px |
|
354 | 367 | |
|
355 | 368 | p |
|
356 | 369 | text-align: right |
|
357 | 370 | font-style: italic |
|
358 | 371 | font-size: 9px |
|
359 | 372 | |
|
360 | 373 | |
|
361 | 374 | .announcement |
|
362 | 375 | .toggles |
|
363 | 376 | font-weight: normal |
|
364 | 377 | float: right |
|
365 | 378 | font-size: 80% |
|
366 | 379 | |
|
367 | 380 | .announcement-title |
|
368 | 381 | font-weight: bold |
|
369 | 382 | |
|
370 | 383 | |
|
371 | 384 | div |
|
372 | 385 | &.message |
|
373 | 386 | margin: 10px 0 0 |
|
374 | 387 | |
|
375 | 388 | div |
|
376 | 389 | &.message |
|
377 | 390 | margin: 0 0 0 30px |
|
378 | 391 | |
|
379 | 392 | &.body |
|
380 | 393 | border: 2px solid #dddddd |
|
381 | 394 | background: #fff8f8 |
|
382 | 395 | padding-left: 5px |
|
383 | 396 | |
|
384 | 397 | &.reply-body |
|
385 | 398 | border: 2px solid #bbbbbb |
|
386 | 399 | background: #fffff8 |
|
387 | 400 | padding-left: 5px |
|
388 | 401 | |
|
389 | 402 | &.stat |
|
390 | 403 | font-size: 10px |
|
391 | 404 | line-height: 1.75em |
|
392 | 405 | padding: 0 5px |
|
393 | 406 | color: #333333 |
|
394 | 407 | background: #dddddd |
|
395 | 408 | font-weight: bold |
|
396 | 409 | |
|
397 | 410 | &.message div.stat |
|
398 | 411 | font-size: 10px |
|
399 | 412 | line-height: 1.75em |
|
400 | 413 | padding: 0 5px |
|
401 | 414 | color: #444444 |
|
402 | 415 | background: #bbbbbb |
|
403 | 416 | font-weight: bold |
|
404 | 417 | |
|
405 | 418 | &.contest-title |
|
406 | 419 | color: white |
|
407 | 420 | text-align: center |
|
408 | 421 | line-height: 2em |
|
409 | 422 | |
|
410 | 423 | &.registration-desc, &.test-desc |
|
411 | 424 | border: 1px dotted gray |
|
412 | 425 | background: #f5f5f5 |
|
413 | 426 | padding: 5px |
|
414 | 427 | margin: 10px 0 |
|
415 | 428 | font-size: 12px |
|
416 | 429 | line-height: 1.5em |
|
417 | 430 | |
|
418 | 431 | h2.contest-title |
|
419 | 432 | margin-top: 5px |
|
420 | 433 | margin-bottom: 5px |
@@ -1,379 +1,404 | |||
|
1 | 1 | class ReportController < ApplicationController |
|
2 | 2 | |
|
3 | 3 | before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize] |
|
4 | 4 | |
|
5 | 5 | before_filter(only: [:problem_hof]) { |c| |
|
6 | 6 | return false unless authenticate |
|
7 | 7 | |
|
8 | 8 | if GraderConfiguration["right.user_view_submission"] |
|
9 | 9 | return true; |
|
10 | 10 | end |
|
11 | 11 | |
|
12 | 12 | admin_authorization |
|
13 | 13 | } |
|
14 | 14 | |
|
15 | + def score | |
|
16 | + if params[:commit] == 'download csv' | |
|
17 | + @problems = Problem.all | |
|
18 | + else | |
|
19 | + @problems = Problem.find_available_problems | |
|
20 | + end | |
|
21 | + @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true) | |
|
22 | + @scorearray = Array.new | |
|
23 | + @users.each do |u| | |
|
24 | + ustat = Array.new | |
|
25 | + ustat[0] = u | |
|
26 | + @problems.each do |p| | |
|
27 | + sub = Submission.find_last_by_user_and_problem(u.id,p.id) | |
|
28 | + if (sub!=nil) and (sub.points!=nil) and p and p.full_score | |
|
29 | + ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)] | |
|
30 | + else | |
|
31 | + ustat << [0,false] | |
|
32 | + end | |
|
33 | + end | |
|
34 | + @scorearray << ustat | |
|
35 | + end | |
|
36 | + if params[:commit] == 'download csv' then | |
|
37 | + csv = gen_csv_from_scorearray(@scorearray,@problems) | |
|
38 | + send_data csv, filename: 'last_score.csv' | |
|
39 | + else | |
|
40 | + render template: 'user_admin/user_stat' | |
|
41 | + end | |
|
42 | + | |
|
43 | + end | |
|
44 | + | |
|
15 | 45 | def login_stat |
|
16 | 46 | @logins = Array.new |
|
17 | 47 | |
|
18 | 48 | date_and_time = '%Y-%m-%d %H:%M' |
|
19 | 49 | begin |
|
20 | 50 | md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
21 | 51 | @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
22 | 52 | rescue |
|
23 | 53 | @since_time = DateTime.new(1000,1,1) |
|
24 | 54 | end |
|
25 | 55 | begin |
|
26 | 56 | md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
27 | 57 | @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
28 | 58 | rescue |
|
29 | 59 | @until_time = DateTime.new(3000,1,1) |
|
30 | 60 | end |
|
31 | 61 | |
|
32 | 62 | User.all.each do |user| |
|
33 | 63 | @logins << { id: user.id, |
|
34 | 64 | login: user.login, |
|
35 | 65 | full_name: user.full_name, |
|
36 | 66 | count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?", |
|
37 | 67 | user.id,@since_time,@until_time) |
|
38 | 68 | .count(:id), |
|
39 | 69 | min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?", |
|
40 | 70 | user.id,@since_time,@until_time) |
|
41 | 71 | .minimum(:created_at), |
|
42 | 72 | max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?", |
|
43 | 73 | user.id,@since_time,@until_time) |
|
44 | 74 | .maximum(:created_at), |
|
45 | 75 | ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?", |
|
46 | 76 | user.id,@since_time,@until_time) |
|
47 | 77 | .select(:ip_address).uniq |
|
48 | 78 | |
|
49 | 79 | } |
|
50 | 80 | end |
|
51 | 81 | end |
|
52 | 82 | |
|
53 | 83 | def submission_stat |
|
54 | 84 | |
|
55 | 85 | date_and_time = '%Y-%m-%d %H:%M' |
|
56 | 86 | begin |
|
57 | 87 | @since_time = DateTime.strptime(params[:since_datetime],date_and_time) |
|
58 | 88 | rescue |
|
59 | 89 | @since_time = DateTime.new(1000,1,1) |
|
60 | 90 | end |
|
61 | 91 | begin |
|
62 | 92 | @until_time = DateTime.strptime(params[:until_datetime],date_and_time) |
|
63 | 93 | rescue |
|
64 | 94 | @until_time = DateTime.new(3000,1,1) |
|
65 | 95 | end |
|
66 | 96 | |
|
67 | 97 | @submissions = {} |
|
68 | 98 | |
|
69 | 99 | User.find_each do |user| |
|
70 | 100 | @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } } |
|
71 | 101 | end |
|
72 | 102 | |
|
73 | 103 | Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s| |
|
74 | 104 | if @submissions[s.user_id] |
|
75 | 105 | if not @submissions[s.user_id][:sub].has_key?(s.problem_id) |
|
76 | - a = nil | |
|
77 | - begin | |
|
78 | - a = Problem.find(s.problem_id) | |
|
79 | - rescue | |
|
80 | - a = nil | |
|
81 | - end | |
|
106 | + a = Problem.find_by_id(s.problem_id) | |
|
82 | 107 | @submissions[s.user_id][:sub][s.problem_id] = |
|
83 | 108 | { prob_name: (a ? a.full_name : '(NULL)'), |
|
84 | 109 | sub_ids: [s.id] } |
|
85 | 110 | else |
|
86 | 111 | @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id |
|
87 | 112 | end |
|
88 | 113 | @submissions[s.user_id][:count] += 1 |
|
89 | 114 | end |
|
90 | 115 | end |
|
91 | 116 | end |
|
92 | 117 | |
|
93 | 118 | def problem_hof |
|
94 | 119 | # gen problem list |
|
95 | 120 | @user = User.find(session[:user_id]) |
|
96 | 121 | @problems = @user.available_problems |
|
97 | 122 | |
|
98 | 123 | # get selected problems or the default |
|
99 | 124 | if params[:id] |
|
100 | 125 | begin |
|
101 | 126 | @problem = Problem.available.find(params[:id]) |
|
102 | 127 | rescue |
|
103 | 128 | redirect_to action: :problem_hof |
|
104 | 129 | flash[:notice] = 'Error: submissions for that problem are not viewable.' |
|
105 | 130 | return |
|
106 | 131 | end |
|
107 | 132 | end |
|
108 | 133 | |
|
109 | 134 | return unless @problem |
|
110 | 135 | |
|
111 | 136 | @by_lang = {} #aggregrate by language |
|
112 | 137 | |
|
113 | 138 | range =65 |
|
114 | 139 | @histogram = { data: Array.new(range,0), summary: {} } |
|
115 | 140 | @summary = {count: 0, solve: 0, attempt: 0} |
|
116 | 141 | user = Hash.new(0) |
|
117 | 142 | Submission.where(problem_id: @problem.id).find_each do |sub| |
|
118 | 143 | #histogram |
|
119 | 144 | d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
|
120 | 145 | @histogram[:data][d.to_i] += 1 if d < range |
|
121 | 146 | |
|
122 | 147 | next unless sub.points |
|
123 | 148 | @summary[:count] += 1 |
|
124 | 149 | user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max |
|
125 | 150 | |
|
126 | 151 | lang = Language.find_by_id(sub.language_id) |
|
127 | 152 | next unless lang |
|
128 | 153 | next unless sub.points >= @problem.full_score |
|
129 | 154 | |
|
130 | 155 | #initialize |
|
131 | 156 | unless @by_lang.has_key?(lang.pretty_name) |
|
132 | 157 | @by_lang[lang.pretty_name] = { |
|
133 | 158 | runtime: { avail: false, value: 2**30-1 }, |
|
134 | 159 | memory: { avail: false, value: 2**30-1 }, |
|
135 | 160 | length: { avail: false, value: 2**30-1 }, |
|
136 | 161 | first: { avail: false, value: DateTime.new(3000,1,1) } |
|
137 | 162 | } |
|
138 | 163 | end |
|
139 | 164 | |
|
140 | 165 | if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value] |
|
141 | 166 | @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id } |
|
142 | 167 | end |
|
143 | 168 | |
|
144 | 169 | if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value] |
|
145 | 170 | @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id } |
|
146 | 171 | end |
|
147 | 172 | |
|
148 | 173 | if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and |
|
149 | 174 | !sub.user.admin? |
|
150 | 175 | @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id } |
|
151 | 176 | end |
|
152 | 177 | |
|
153 | 178 | if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length |
|
154 | 179 | @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id } |
|
155 | 180 | end |
|
156 | 181 | end |
|
157 | 182 | |
|
158 | 183 | #process user_id |
|
159 | 184 | @by_lang.each do |lang,prop| |
|
160 | 185 | prop.each do |k,v| |
|
161 | 186 | v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)" |
|
162 | 187 | end |
|
163 | 188 | end |
|
164 | 189 | |
|
165 | 190 | #sum into best |
|
166 | 191 | if @by_lang and @by_lang.first |
|
167 | 192 | @best = @by_lang.first[1].clone |
|
168 | 193 | @by_lang.each do |lang,prop| |
|
169 | 194 | if @best[:runtime][:value] >= prop[:runtime][:value] |
|
170 | 195 | @best[:runtime] = prop[:runtime] |
|
171 | 196 | @best[:runtime][:lang] = lang |
|
172 | 197 | end |
|
173 | 198 | if @best[:memory][:value] >= prop[:memory][:value] |
|
174 | 199 | @best[:memory] = prop[:memory] |
|
175 | 200 | @best[:memory][:lang] = lang |
|
176 | 201 | end |
|
177 | 202 | if @best[:length][:value] >= prop[:length][:value] |
|
178 | 203 | @best[:length] = prop[:length] |
|
179 | 204 | @best[:length][:lang] = lang |
|
180 | 205 | end |
|
181 | 206 | if @best[:first][:value] >= prop[:first][:value] |
|
182 | 207 | @best[:first] = prop[:first] |
|
183 | 208 | @best[:first][:lang] = lang |
|
184 | 209 | end |
|
185 | 210 | end |
|
186 | 211 | end |
|
187 | 212 | |
|
188 | 213 | @histogram[:summary][:max] = [@histogram[:data].max,1].max |
|
189 | 214 | @summary[:attempt] = user.count |
|
190 | 215 | user.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
191 | 216 | end |
|
192 | 217 | |
|
193 | 218 | def stuck #report struggling user,problem |
|
194 | 219 | # init |
|
195 | 220 | user,problem = nil |
|
196 | 221 | solve = true |
|
197 | 222 | tries = 0 |
|
198 | 223 | @struggle = Array.new |
|
199 | 224 | record = {} |
|
200 | 225 | Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub| |
|
201 | 226 | next unless sub.problem and sub.user |
|
202 | 227 | if user != sub.user_id or problem != sub.problem_id |
|
203 | 228 | @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve |
|
204 | 229 | record = {user: sub.user, problem: sub.problem} |
|
205 | 230 | user,problem = sub.user_id, sub.problem_id |
|
206 | 231 | solve = false |
|
207 | 232 | tries = 0 |
|
208 | 233 | end |
|
209 | 234 | if sub.points >= sub.problem.full_score |
|
210 | 235 | solve = true |
|
211 | 236 | else |
|
212 | 237 | tries += 1 |
|
213 | 238 | end |
|
214 | 239 | end |
|
215 | 240 | @struggle.sort!{|a,b| b[:tries] <=> a[:tries] } |
|
216 | 241 | @struggle = @struggle[0..50] |
|
217 | 242 | end |
|
218 | 243 | |
|
219 | 244 | |
|
220 | 245 | def multiple_login |
|
221 | 246 | #user with multiple IP |
|
222 | 247 | raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login) |
|
223 | 248 | last,count = 0,0 |
|
224 | 249 | first = 0 |
|
225 | 250 | @users = [] |
|
226 | 251 | raw.each do |r| |
|
227 | 252 | if last != r.user.login |
|
228 | 253 | count = 1 |
|
229 | 254 | last = r.user.login |
|
230 | 255 | first = r |
|
231 | 256 | else |
|
232 | 257 | @users << first if count == 1 |
|
233 | 258 | @users << r |
|
234 | 259 | count += 1 |
|
235 | 260 | end |
|
236 | 261 | end |
|
237 | 262 | |
|
238 | 263 | #IP with multiple user |
|
239 | 264 | raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address) |
|
240 | 265 | last,count = 0,0 |
|
241 | 266 | first = 0 |
|
242 | 267 | @ip = [] |
|
243 | 268 | raw.each do |r| |
|
244 | 269 | if last != r.ip_address |
|
245 | 270 | count = 1 |
|
246 | 271 | last = r.ip_address |
|
247 | 272 | first = r |
|
248 | 273 | else |
|
249 | 274 | @ip << first if count == 1 |
|
250 | 275 | @ip << r |
|
251 | 276 | count += 1 |
|
252 | 277 | end |
|
253 | 278 | end |
|
254 | 279 | end |
|
255 | 280 | |
|
256 | 281 | def cheat_report |
|
257 | 282 | date_and_time = '%Y-%m-%d %H:%M' |
|
258 | 283 | begin |
|
259 | 284 | md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
260 | 285 | @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
261 | 286 | rescue |
|
262 | 287 | @since_time = Time.zone.now.ago( 90.minutes) |
|
263 | 288 | end |
|
264 | 289 | begin |
|
265 | 290 | md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
266 | 291 | @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
267 | 292 | rescue |
|
268 | 293 | @until_time = Time.zone.now |
|
269 | 294 | end |
|
270 | 295 | |
|
271 | 296 | #multi login |
|
272 | 297 | @ml = Login.joins(:user).where("logins.created_at >= ? and logins.created_at <= ?",@since_time,@until_time).select('users.login,count(distinct ip_address) as count,users.full_name').group("users.id").having("count > 1") |
|
273 | 298 | |
|
274 | 299 | st = <<-SQL |
|
275 | 300 | SELECT l2.* |
|
276 | 301 | FROM logins l2 INNER JOIN |
|
277 | 302 | (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name |
|
278 | 303 | FROM logins l |
|
279 | 304 | INNER JOIN users u ON l.user_id = u.id |
|
280 | 305 | WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}' |
|
281 | 306 | GROUP BY u.id |
|
282 | 307 | HAVING count > 1 |
|
283 | 308 | ) ml ON l2.user_id = ml.id |
|
284 | 309 | WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}' |
|
285 | 310 | UNION |
|
286 | 311 | SELECT l2.* |
|
287 | 312 | FROM logins l2 INNER JOIN |
|
288 | 313 | (SELECT l.ip_address,COUNT(DISTINCT u.id) as count |
|
289 | 314 | FROM logins l |
|
290 | 315 | INNER JOIN users u ON l.user_id = u.id |
|
291 | 316 | WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}' |
|
292 | 317 | GROUP BY l.ip_address |
|
293 | 318 | HAVING count > 1 |
|
294 | 319 | ) ml on ml.ip_address = l2.ip_address |
|
295 | 320 | INNER JOIN users u ON l2.user_id = u.id |
|
296 | 321 | WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}' |
|
297 | 322 | ORDER BY ip_address,created_at |
|
298 | 323 | SQL |
|
299 | 324 | @mld = Login.find_by_sql(st) |
|
300 | 325 | |
|
301 | 326 | st = <<-SQL |
|
302 | 327 | SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id |
|
303 | 328 | FROM submissions s INNER JOIN |
|
304 | 329 | (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name |
|
305 | 330 | FROM logins l |
|
306 | 331 | INNER JOIN users u ON l.user_id = u.id |
|
307 | 332 | WHERE l.created_at >= ? and l.created_at <= ? |
|
308 | 333 | GROUP BY u.id |
|
309 | 334 | HAVING count > 1 |
|
310 | 335 | ) ml ON s.user_id = ml.id |
|
311 | 336 | WHERE s.submitted_at >= ? and s.submitted_at <= ? |
|
312 | 337 | UNION |
|
313 | 338 | SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id |
|
314 | 339 | FROM submissions s INNER JOIN |
|
315 | 340 | (SELECT l.ip_address,COUNT(DISTINCT u.id) as count |
|
316 | 341 | FROM logins l |
|
317 | 342 | INNER JOIN users u ON l.user_id = u.id |
|
318 | 343 | WHERE l.created_at >= ? and l.created_at <= ? |
|
319 | 344 | GROUP BY l.ip_address |
|
320 | 345 | HAVING count > 1 |
|
321 | 346 | ) ml on ml.ip_address = s.ip_address |
|
322 | 347 | WHERE s.submitted_at >= ? and s.submitted_at <= ? |
|
323 | 348 | ORDER BY ip_address,submitted_at |
|
324 | 349 | SQL |
|
325 | 350 | @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time, |
|
326 | 351 | @since_time,@until_time, |
|
327 | 352 | @since_time,@until_time, |
|
328 | 353 | @since_time,@until_time]) |
|
329 | 354 | |
|
330 | 355 | end |
|
331 | 356 | |
|
332 | 357 | def cheat_scruntinize |
|
333 | 358 | #convert date & time |
|
334 | 359 | date_and_time = '%Y-%m-%d %H:%M' |
|
335 | 360 | begin |
|
336 | 361 | md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
337 | 362 | @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
338 | 363 | rescue |
|
339 | 364 | @since_time = Time.zone.now.ago( 90.minutes) |
|
340 | 365 | end |
|
341 | 366 | begin |
|
342 | 367 | md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/) |
|
343 | 368 | @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i) |
|
344 | 369 | rescue |
|
345 | 370 | @until_time = Time.zone.now |
|
346 | 371 | end |
|
347 | 372 | |
|
348 | 373 | #convert sid |
|
349 | 374 | @sid = params[:SID].split(/[,\s]/) if params[:SID] |
|
350 | 375 | unless @sid and @sid.size > 0 |
|
351 | 376 | return |
|
352 | 377 | redirect_to actoin: :cheat_scruntinize |
|
353 | 378 | flash[:notice] = 'Please enter at least 1 student id' |
|
354 | 379 | end |
|
355 | 380 | mark = Array.new(@sid.size,'?') |
|
356 | 381 | condition = "(u.login = " + mark.join(' OR u.login = ') + ')' |
|
357 | 382 | |
|
358 | 383 | @st = <<-SQL |
|
359 | 384 | SELECT l.created_at as submitted_at ,-1 as id,u.login,u.full_name,l.ip_address,"" as problem_id,"" as points,l.user_id |
|
360 | 385 | FROM logins l INNER JOIN users u on l.user_id = u.id |
|
361 | 386 | WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition} |
|
362 | 387 | UNION |
|
363 | 388 | SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id |
|
364 | 389 | FROM submissions s INNER JOIN users u ON s.user_id = u.id |
|
365 | 390 | WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition} |
|
366 | 391 | ORDER BY submitted_at |
|
367 | 392 | SQL |
|
368 | 393 | |
|
369 | 394 | p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid |
|
370 | 395 | @logs = Submission.joins(:problem).find_by_sql(p) |
|
371 | 396 | |
|
372 | 397 | |
|
373 | 398 | |
|
374 | 399 | |
|
375 | 400 | |
|
376 | 401 | end |
|
377 | 402 | |
|
378 | 403 | |
|
379 | 404 | end |
@@ -1,59 +1,61 | |||
|
1 | - - content_for :header do | |
|
2 |
- |
|
|
3 |
- |
|
|
1 | + /- content_for :header do | |
|
2 | + / = javascript_include_tag 'local_jquery' | |
|
3 | + / = stylesheet_link_tag 'tablesorter-theme.cafe' | |
|
4 | 4 | |
|
5 | 5 | %script{:type=>"text/javascript"} |
|
6 | 6 | $(function () { |
|
7 | 7 | $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); |
|
8 | 8 | $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} ); |
|
9 | - $('#my_table').tablesorter({widgets: ['zebra']}); | |
|
9 | + /$('#my_table').tablesorter({widgets: ['zebra']}); | |
|
10 | 10 | }); |
|
11 | 11 | |
|
12 | 12 | %h1 User grading results |
|
13 | 13 | %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range" |
|
14 | 14 | |
|
15 | 15 | |
|
16 | 16 | - if @problem and @problem.errors |
|
17 | 17 | =error_messages_for 'problem' |
|
18 | 18 | |
|
19 | 19 | = render partial: 'submission_range' |
|
20 | 20 | |
|
21 | 21 | - if params[:action] == 'user_stat' |
|
22 | 22 | %h3 Latest score |
|
23 | 23 | = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat, commit: 'download csv' |
|
24 | 24 | - else |
|
25 | 25 | %h3 Max score |
|
26 | 26 | = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat |
|
27 | 27 | = link_to '[download csv with all problems]', controller: :user_admin, action: :user_stat_max, commit: 'download csv' |
|
28 | 28 | |
|
29 | - %table.tablesorter-cafe#my_table | |
|
29 | + %table.table.sortable.table-striped.table-bordered | |
|
30 | 30 | %thead |
|
31 | 31 | %tr |
|
32 |
- %th |
|
|
32 | + %th Login | |
|
33 | 33 | %th Name |
|
34 | 34 | %th Activated? |
|
35 |
- %th Logged |
|
|
35 | + %th Logged_in | |
|
36 | 36 | %th Contest(s) |
|
37 | 37 | %th Remark |
|
38 | 38 | - @problems.each do |p| |
|
39 | - %th= p.name | |
|
40 | - %th Total | |
|
41 | - %th Passed | |
|
39 | + %th.text-right= p.name | |
|
40 | + %th.text-right Total | |
|
41 | + %th.text-right Passed | |
|
42 | 42 | %tbody |
|
43 | 43 | - @scorearray.each do |sc| |
|
44 | - %tr{class: cycle('info-even','info-odd')} | |
|
44 | + %tr | |
|
45 | 45 | - total,num_passed = 0,0 |
|
46 | 46 | - sc.each_index do |i| |
|
47 | 47 | - if i == 0 |
|
48 | 48 | %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i] |
|
49 | 49 | %td= sc[i].full_name |
|
50 | 50 | %td= sc[i].activated |
|
51 | 51 | %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no' |
|
52 | 52 | %td= sc[i].contests.collect {|c| c.name}.join(', ') |
|
53 | 53 | %td= sc[i].remark |
|
54 | 54 | - else |
|
55 | - %td= sc[i][0] | |
|
55 | + %td.text-right= sc[i][0] | |
|
56 | 56 | - total += sc[i][0] |
|
57 | 57 | - num_passed += 1 if sc[i][1] |
|
58 | - %td= total | |
|
59 | - %td= num_passed | |
|
58 | + %td.text-right= total | |
|
59 | + %td.text-right= num_passed | |
|
60 | + :javascript | |
|
61 | + $.bootstrapSortable(true,'reversed') |
You need to be logged in to leave comments.
Login now