Description:
- add problem toggle test js reponse (it was forgotten) - change score report to bootstrap-sortable
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

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 mail
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-toggle
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: 40px
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 - = javascript_include_tag 'local_jquery'
3 - = stylesheet_link_tag 'tablesorter-theme.cafe'
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 User
32 + %th Login
33 33 %th Name
34 34 %th Activated?
35 - %th Logged in
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