Description:
merge feature from java, including * user profile page * combine user_stat with user_stat_max * add jquery plugin tablesorter that sorts table
Commit status:
[Not Reviewed]
References:
merge algo
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r433:a8fd17f1561a - - 16 files changed: 378 inserted, 74 deleted

@@ -0,0 +1,197
1 + /*************
2 + Metro Dark Theme
3 + *************/
4 + /* overall */
5 + .tablesorter-cafe {
6 + // font: 12px/18px 'Segoe UI Semilight', 'Open Sans', Verdana, Arial, Helvetica, sans-serif;
7 + color: #000;
8 + background-color: #777;
9 + margin: 10px 0 15px;
10 + text-align: left;
11 + border-collapse: collapse;
12 + border: #555 1px solid;
13 + }
14 +
15 + .tablesorter-cafe tr.dark-row th, .tablesorter-cafe tr.dark-row td {
16 + background-color: #222;
17 + color: #fff;
18 + text-align: left;
19 + font-size: 14px;
20 + }
21 +
22 + /* header/footer */
23 + .tablesorter-cafe caption,
24 + .tablesorter-cafe th,
25 + .tablesorter-cafe thead td,
26 + .tablesorter-cafe tfoot th,
27 + .tablesorter-cafe tfoot td {
28 + //font-weight: 300;
29 + //font-size: 15px;
30 + color: #fff;
31 + background-color: #777;
32 + padding: 2px;
33 + border: #555 1px solid;
34 + }
35 +
36 + .tablesorter-cafe .header,
37 + .tablesorter-cafe .tablesorter-header {
38 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAGFBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u5jNePWAAAACHRSTlMAMxIHKwEgMWD59H4AAABSSURBVAjXY2BgYFJgAAHzYhDJ6igSAKTYBAUTgJSioKAQAwNzoaCguAFDiCAQuDIkgigxBgiA8cJAVCpQt6AgSL+JoKAzA0gjUBsQqBcBCYhFAAE/CV4zeSzxAAAAAElFTkSuQmCC);
39 + background-position: center right;
40 + background-repeat: no-repeat;
41 + cursor: pointer;
42 + white-space: normal;
43 + }
44 + .tablesorter-cafe .tablesorter-header-inner {
45 + padding: 0 18px 0 4px;
46 + }
47 + .tablesorter-cafe thead .headerSortUp,
48 + .tablesorter-cafe thead .tablesorter-headerSortUp,
49 + .tablesorter-cafe thead .tablesorter-headerAsc {
50 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAAIVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u5meJAOAAAACnRSTlMAMwsqXt+gIBUGxGoDMAAAAFlJREFUCNctzC0SQAAUReEzGNQ3AlHRiSRZFCVZYgeswRL8hLdK7834wj3tAlGP6y7fYHpKS6w6WwbVG0I1NZVnZPG8/DYxOYlnhUYkA06R1s9ESsxR4NIdPhkPFDFYuEnMAAAAAElFTkSuQmCC);
51 + }
52 + .tablesorter-cafe thead .headerSortDown,
53 + .tablesorter-cafe thead .tablesorter-headerSortDown,
54 + .tablesorter-cafe thead .tablesorter-headerDesc {
55 + background-image: url(data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAQBAMAAADQT4M0AAAALVBMVEUAAADu7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7u7i0NViAAAADnRSTlMAMiweCQITTvDctZZqaTlM310AAABcSURBVAjXY2BgYEtgAAFHERDJqigUAKSYBQUNgFSioKAYAwOLIBA4MASBKFUGQxAlzAAF+94BwWuGKBC1lIFl3rt3Lx0YGCzevWsGSjK9e6cAUlT3HKyW9wADAwDRrBiDy6bKzwAAAABJRU5ErkJggg==);
56 + }
57 + .tablesorter-cafe thead .sorter-false {
58 + background-image: none;
59 + cursor: default;
60 + padding: 4px;
61 + }
62 +
63 + /* tbody */
64 + .tablesorter-cafe td {
65 + background-color: #fff;
66 + padding: 1px 4px;
67 + vertical-align: top;
68 + border-style: solid;
69 + border-color: #666;
70 + border-collapse: collapse;
71 + border-width: 0px 1px;
72 +
73 + }
74 +
75 + /* hovered row colors */
76 + .tablesorter-cafe tbody > tr:hover > td,
77 + .tablesorter-cafe tbody > tr.even:hover > td,
78 + .tablesorter-cafe tbody > tr.odd:hover > td {
79 + background: #bbb;
80 + color: #000;
81 + }
82 +
83 + /* table processing indicator */
84 + .tablesorter-cafe .tablesorter-processing {
85 + background-position: center center !important;
86 + background-repeat: no-repeat !important;
87 + /* background-image: url(../addons/pager/icons/loading.gif) !important; */
88 + background-image: url(data:image/gif;base64,R0lGODlhFAAUAKEAAO7u7lpaWgAAAAAAACH/C05FVFNDQVBFMi4wAwEAAAAh+QQBCgACACwAAAAAFAAUAAACQZRvoIDtu1wLQUAlqKTVxqwhXIiBnDg6Y4eyx4lKW5XK7wrLeK3vbq8J2W4T4e1nMhpWrZCTt3xKZ8kgsggdJmUFACH5BAEKAAIALAcAAAALAAcAAAIUVB6ii7jajgCAuUmtovxtXnmdUAAAIfkEAQoAAgAsDQACAAcACwAAAhRUIpmHy/3gUVQAQO9NetuugCFWAAAh+QQBCgACACwNAAcABwALAAACE5QVcZjKbVo6ck2AF95m5/6BSwEAIfkEAQoAAgAsBwANAAsABwAAAhOUH3kr6QaAcSrGWe1VQl+mMUIBACH5BAEKAAIALAIADQALAAcAAAIUlICmh7ncTAgqijkruDiv7n2YUAAAIfkEAQoAAgAsAAAHAAcACwAAAhQUIGmHyedehIoqFXLKfPOAaZdWAAAh+QQFCgACACwAAAIABwALAAACFJQFcJiXb15zLYRl7cla8OtlGGgUADs=) !important;
89 + }
90 +
91 + /* pager */
92 + .tablesorter-cafe .tablesorter-pager button {
93 + background-color: #444;
94 + color: #eee;
95 + border: #555 1px solid;
96 + cursor: pointer;
97 + }
98 + .tablesorter-cafe .tablesorter-pager button:hover {
99 + background-color: #555;
100 + }
101 +
102 + /* Zebra Widget - row alternating colors */
103 + .tablesorter-cafe tr.odd td {
104 + background-color: #eee;
105 + }
106 + .tablesorter-cafe tr.even td {
107 + background-color: #fff;
108 + }
109 +
110 + /* Column Widget - column sort colors */
111 + .tablesorter-cafe tr.odd td.primary {
112 + background-color: #bfbfbf;
113 + }
114 + .tablesorter-cafe td.primary,
115 + .tablesorter-cafe tr.even td.primary {
116 + background-color: #d9d9d9;
117 + }
118 + .tablesorter-cafe tr.odd td.secondary {
119 + background-color: #d9d9d9;
120 + }
121 + .tablesorter-cafe td.secondary,
122 + .tablesorter-cafe tr.even td.secondary {
123 + background-color: #e6e6e6;
124 + }
125 + .tablesorter-cafe tr.odd td.tertiary {
126 + background-color: #e6e6e6;
127 + }
128 + .tablesorter-cafe td.tertiary,
129 + .tablesorter-cafe tr.even td.tertiary {
130 + background-color: #f2f2f2;
131 + }
132 +
133 + /* filter widget */
134 + .tablesorter-cafe .tablesorter-filter-row td {
135 + background: #eee;
136 + line-height: normal;
137 + text-align: center; /* center the input */
138 + -webkit-transition: line-height 0.1s ease;
139 + -moz-transition: line-height 0.1s ease;
140 + -o-transition: line-height 0.1s ease;
141 + transition: line-height 0.1s ease;
142 + }
143 + /* optional disabled input styling */
144 + .tablesorter-cafe .tablesorter-filter-row .disabled {
145 + opacity: 0.5;
146 + filter: alpha(opacity=50);
147 + cursor: not-allowed;
148 + }
149 + /* hidden filter row */
150 + .tablesorter-cafe .tablesorter-filter-row.hideme td {
151 + /*** *********************************************** ***/
152 + /*** change this padding to modify the thickness ***/
153 + /*** of the closed filter row (height = padding x 2) ***/
154 + padding: 2px;
155 + /*** *********************************************** ***/
156 + margin: 0;
157 + line-height: 0;
158 + cursor: pointer;
159 + }
160 + .tablesorter-cafe .tablesorter-filter-row.hideme .tablesorter-filter {
161 + height: 1px;
162 + min-height: 0;
163 + border: 0;
164 + padding: 0;
165 + margin: 0;
166 + /* don't use visibility: hidden because it disables tabbing */
167 + opacity: 0;
168 + filter: alpha(opacity=0);
169 + }
170 + /* filters */
171 + .tablesorter-cafe .tablesorter-filter {
172 + width: 95%;
173 + height: auto;
174 + margin: 4px;
175 + padding: 4px;
176 + background-color: #fff;
177 + border: 1px solid #bbb;
178 + color: #333;
179 + -webkit-box-sizing: border-box;
180 + -moz-box-sizing: border-box;
181 + box-sizing: border-box;
182 + -webkit-transition: height 0.1s ease;
183 + -moz-transition: height 0.1s ease;
184 + -o-transition: height 0.1s ease;
185 + transition: height 0.1s ease;
186 + }
187 + /* rows hidden by filtering (needed for child rows) */
188 + .tablesorter .filtered {
189 + display: none;
190 + }
191 +
192 + /* ajax error row */
193 + .tablesorter .tablesorter-errorRow td {
194 + text-align: center;
195 + cursor: pointer;
196 + background-color: #e6bf99;
197 + }
@@ -0,0 +1,54
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 + = stylesheet_link_tag 'tablesorter-theme.cafe'
4 +
5 + %script{:type=>"text/javascript"}
6 + $(function () {
7 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widgets: ['zebra']});
10 + });
11 +
12 + %h1 User grading results
13 + %h2= params[:action] == 'user_stat' ? "Show scores from latest submission" : "Show max scores in submission range"
14 +
15 +
16 + - if @problem and @problem.errors
17 + =error_messages_for 'problem'
18 +
19 + = render partial: 'submission_range'
20 +
21 + - if params[:action] == 'user_stat'
22 + = "latest score"
23 + - else
24 + = link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
25 +
26 + %table.tablesorter-cafe#my_table
27 + %thead
28 + %tr
29 + %th User
30 + %th Name
31 + %th Activated?
32 + %th Logged in
33 + %th Contest(s)
34 + - @problems.each do |p|
35 + %th= p.name
36 + %th Total
37 + %th Passed
38 + %tbody
39 + - @scorearray.each do |sc|
40 + %tr{class: cycle('info-even','info-odd')}
41 + - total,num_passed = 0,0
42 + - sc.each_index do |i|
43 + - if i == 0
44 + %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
45 + %td= sc[i].full_name
46 + %td= sc[i].activated
47 + %td= sc[i].try(:contest_stat).try(:started_at)!=nil ? 'yes' : 'no'
48 + %td= sc[i].contests.collect {|c| c.name}.join(', ')
49 + - else
50 + %td= sc[i][0]
51 + - total += sc[i][0]
52 + - num_passed += 1 if sc[i][1]
53 + %td= total
54 + %td= num_passed
@@ -0,0 +1,40
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 +
4 + %script{:type=>"text/javascript"}
5 + $(function () {
6 + $('#submission_table').tablesorter({widgets: ['zebra','filter']});
7 + });
8 +
9 + %h1= @user.full_name + ' Profile'
10 +
11 + %h2 Basic info
12 + <b>Login:</b> #{@user.login} <br/>
13 + <b>Full name:</b> #{@user.full_name} <br />
14 +
15 +
16 + %h2 Problem Stat
17 +
18 + %h2 Submissions
19 +
20 + %table.tablesorter-cafe#submission_table
21 + %thead
22 + %tr
23 + %th ID
24 + %th Problem code
25 + %th Problem name
26 + %th Language
27 + %th Result
28 + %th Score
29 + %tbody
30 + - @submission.each do |s|
31 + %tr
32 + %td= link_to "#{s.id}", controller: "graders", action: "submission", id: s.id
33 + %td= s.problem.name
34 + %td= s.problem.full_name
35 + %td= s.language.pretty_name
36 + %td{style: 'font-family: Droid Sans Mono,Consolas, monospace, mono'}= s.grader_comment
37 + %td= s.points/s.problem.full_score * 100
38 +
39 +
40 +
@@ -8,12 +8,19
8 8 /.bundle
9 9
10 10 # Ignore the default SQLite database.
11 11 /db/*.sqlite3
12 12
13 13 # Ignore all logfiles and tempfiles.
14 14 /log/*.log
15 15 /tmp
16 16
17 17 *~
18 18
19 19 /vendor/plugins/rails_upgrade
20 +
21 + #ignore public assets???
22 + /public/assets
23 +
24 + #ignore .orig and .swp
25 + *.orig
26 + *.swp
@@ -28,27 +28,29
28 28 # gem 'jbuilder'
29 29
30 30 # Use unicorn as the app server
31 31 # gem 'unicorn'
32 32
33 33 # Deploy with Capistrano
34 34 # gem 'capistrano'
35 35
36 36 # To use debugger
37 37 # gem 'debugger'
38 38 #
39 39
40 + # jquery addition
40 41 gem 'jquery-rails'
41 42 gem 'jquery-ui-sass-rails'
42 43 gem 'jquery-timepicker-addon-rails'
44 + gem 'jquery-tablesorter'
43 45
44 46 #syntax highlighter
45 47 gem 'rouge'
46 48
47 49 gem "haml"
48 50 gem "mail"
49 51 gem "rdiscount"
50 52 gem "test-unit"
51 53 gem 'will_paginate', '~> 3.0.0'
52 54 gem 'dynamic_form'
53 55 gem 'in_place_editing'
54 56 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
@@ -49,24 +49,26
49 49 dynamic_form (1.1.4)
50 50 erubis (2.7.0)
51 51 execjs (2.2.1)
52 52 haml (4.0.5)
53 53 tilt
54 54 hike (1.2.3)
55 55 i18n (0.6.11)
56 56 in_place_editing (1.2.0)
57 57 journey (1.0.4)
58 58 jquery-rails (3.1.1)
59 59 railties (>= 3.0, < 5.0)
60 60 thor (>= 0.14, < 2.0)
61 + jquery-tablesorter (1.12.7)
62 + railties (>= 3.1, < 5)
61 63 jquery-timepicker-addon-rails (1.4.1)
62 64 railties (>= 3.1)
63 65 jquery-ui-rails (4.0.3)
64 66 jquery-rails
65 67 railties (>= 3.1.0)
66 68 jquery-ui-sass-rails (4.0.3.0)
67 69 jquery-rails
68 70 jquery-ui-rails (= 4.0.3)
69 71 railties (>= 3.1.0)
70 72 json (1.8.1)
71 73 mail (2.5.4)
72 74 mime-types (~> 1.16)
@@ -143,24 +145,25
143 145 json (>= 1.8.0)
144 146 will_paginate (3.0.7)
145 147
146 148 PLATFORMS
147 149 ruby
148 150
149 151 DEPENDENCIES
150 152 coffee-rails (~> 3.2.1)
151 153 dynamic_form
152 154 haml
153 155 in_place_editing
154 156 jquery-rails
157 + jquery-tablesorter
155 158 jquery-timepicker-addon-rails
156 159 jquery-ui-sass-rails
157 160 mail
158 161 mysql2
159 162 prototype-rails
160 163 rails (= 3.2.19)
161 164 rdiscount
162 165 rouge
163 166 rspec-rails (~> 2.0)
164 167 sass-rails (~> 3.2.3)
165 168 test-unit
166 169 uglifier (>= 1.0.3)
@@ -1,6 +1,7
1 1 //= require jquery
2 2 //= require jquery_ujs
3 3 //= require jquery.ui.all
4 4 //= require jquery.ui.datepicker
5 5 //= require jquery.ui.slider
6 6 //= require jquery-ui-timepicker-addon
7 + //= require jquery-tablesorter
@@ -1,19 +1,20
1 1
2 2 @import jquery.ui.core
3 3 @import jquery.ui.theme
4 4 @import jquery.ui.datepicker
5 5 @import jquery.ui.slider
6 6 @import jquery-ui-timepicker-addon
7 -
7 + @import jquery-tablesorter/theme.metro-dark
8 + @import tablesorter-theme.cafe
8 9
9 10 body
10 11 background: white image-url("topbg.jpg") repeat-x top center
11 12 font-size: 13px
12 13 font-family: Tahoma, "sans-serif"
13 14 margin: 10px
14 15 padding: 10px
15 16
16 17
17 18 input
18 19 font-family: Tahoma, "sans-serif"
19 20
@@ -18,25 +18,26
18 18 begin
19 19 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
20 20 rescue
21 21 @since_time = DateTime.new(1000,1,1)
22 22 end
23 23 begin
24 24 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
25 25 rescue
26 26 @until_time = DateTime.new(3000,1,1)
27 27 end
28 28
29 29 User.all.each do |user|
30 - @logins << { login: user.login,
30 + @logins << { id: user.id,
31 + login: user.login,
31 32 full_name: user.full_name,
32 33 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
33 34 user.id,@since_time,@until_time)
34 35 .count(:id),
35 36 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 37 user.id,@since_time,@until_time)
37 38 .minimum(:created_at),
38 39 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 40 user.id,@since_time,@until_time)
40 41 .maximum(:created_at)
41 42 }
42 43 end
@@ -150,24 +150,26
150 150 @users.each do |u|
151 151 ustat = Array.new
152 152 ustat[0] = u
153 153 @problems.each do |p|
154 154 max_points = 0
155 155 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
156 156 max_points = sub.points if sub and sub.points and (sub.points > max_points)
157 157 end
158 158 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
159 159 end
160 160 @scorearray << ustat
161 161 end
162 +
163 + render template: 'user_admin/user_stat'
162 164 end
163 165
164 166 def import
165 167 if params[:file]==''
166 168 flash[:notice] = 'Error importing no file'
167 169 redirect_to :action => 'list' and return
168 170 end
169 171 import_from_file(params[:file])
170 172 end
171 173
172 174 def random_all_passwords
173 175 users = User.find(:all)
@@ -5,24 +5,25
5 5 include MailHelperMethods
6 6
7 7 before_filter :authenticate, :except => [:new,
8 8 :register,
9 9 :confirm,
10 10 :forget,
11 11 :retrieve_password]
12 12
13 13 before_filter :verify_online_registration, :only => [:new,
14 14 :register,
15 15 :forget,
16 16 :retrieve_password]
17 + before_filter :authenticate, :profile_authorization, only: [:profile]
17 18
18 19 verify :method => :post, :only => [:chg_passwd],
19 20 :redirect_to => { :action => :index }
20 21
21 22 #in_place_edit_for :user, :alias_for_editing
22 23 #in_place_edit_for :user, :email_for_editing
23 24
24 25 def index
25 26 if !GraderConfiguration['system.user_setting_enabled']
26 27 redirect_to :controller => 'main', :action => 'list'
27 28 else
28 29 @user = User.find(session[:user_id])
@@ -99,24 +100,29
99 100 else
100 101 user.password = user.password_confirmation = User.random_password
101 102 user.save
102 103 send_new_password_email(user)
103 104 flash[:notice] = 'New password has been mailed to you.'
104 105 end
105 106 else
106 107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
107 108 end
108 109 redirect_to :action => 'forget'
109 110 end
110 111
112 + def profile
113 + @user = User.find(params[:id])
114 + @submission = Submission.where(user_id: params[:id]).all
115 + end
116 +
111 117 protected
112 118
113 119 def verify_online_registration
114 120 if !GraderConfiguration['system.online_registration']
115 121 redirect_to :controller => 'main', :action => 'login'
116 122 end
117 123 end
118 124
119 125 def send_confirmation_email(user)
120 126 contest_name = GraderConfiguration['contest.name']
121 127 activation_url = url_for(:action => 'confirm',
122 128 :login => user.login,
@@ -143,14 +149,28
143 149 mail_body = t('registration.password_retrieval.email_body', {
144 150 :full_name => user.full_name,
145 151 :contest_name => contest_name,
146 152 :login => user.login,
147 153 :password => user.password,
148 154 :admin_email => admin_email
149 155 })
150 156
151 157 logger.info mail_body
152 158
153 159 send_mail(user.email, mail_subject, mail_body)
154 160 end
161 +
162 + # allow viewing of regular user profile only when options allow so
163 + # only admins can view admins profile
164 + def profile_authorization
165 + #if view admins' profile, allow only admin
166 + return false unless(params[:id])
167 + user = User.find(params[:id])
168 + return false unless user
169 + return admin_authorization if user.admin?
170 + return true if GraderConfiguration["right.user_view_submission"]
171 +
172 + #finally, we allow only admin
173 + admin_authorization
174 + end
155 175
156 176 end
@@ -1,62 +1,79
1 1 :css
2 2 .hof_user { color: orangered; font-style: italic; }
3 3 .hof_language { color: green; font-style: italic; }
4 4 .hof_value { color: deeppink;font-style: italic; }
5 5
6 6 %h2 Overall
7 7
8 8 - if @best
9 9 %b Best Runtime:
10 - by <span class="hof_user">#{@best[:runtime][:user]}</span> using <span class="hof_language">#{@best[:runtime][:lang]}</span> with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span> at submission
10 + by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
11 + using <span class="hof_language">#{@best[:runtime][:lang]}</span>
12 + with <span class="hof_value">#{@best[:runtime][:value] * 1000} milliseconds</span>
13 + at submission
11 14 = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
12 15 %br/
13 16
14 17 %b Best Memory Usage:
15 - by <span class="hof_user">#{@best[:memory][:user]}</span> using <span class="hof_language">#{@best[:memory][:lang]}</span> with <span class="hof_value">#{@best[:memory][:value]} kbytes </span> at submission
18 + by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
19 + using <span class="hof_language">#{@best[:memory][:lang]}</span>
20 + with <span class="hof_value">#{@best[:memory][:value]} kbytes </span>
21 + at submission
16 22 = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
17 23 %br/
18 24
19 - %b Shortest Code:
20 - by <span class="hof_user">#{@best[:length][:user]}</span> using <span class="hof_language">#{@best[:length][:lang]}</span> with <span class="hof_value">#{@best[:length][:value]} bytes</span> at submission
25 + %b Shortest Code:
26 + by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
27 + using <span class="hof_language">#{@best[:length][:lang]}</span>
28 + with <span class="hof_value">#{@best[:length][:value]} bytes</span>
29 + at submission
21 30 = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
22 31 %br/
23 32
24 - %b First solver:
25 - <span class="hof_user">#{@best[:first][:user]}</span> is the first solver using <span class="hof_language">#{@best[:first][:lang]}</span> on <span class="hof_value">#{@best[:first][:value]}</span> at submission
33 + %b First solver:
34 + #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
35 + using <span class="hof_language">#{@best[:first][:lang]}</span>
36 + on <span class="hof_value">#{@best[:first][:value]}</span>
37 + at submission
26 38 = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
27 39 %br/
28 40
29 41
30 42 %p
31 43 This counts only for submission with 100% score <br/>
32 44 Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
33 45
34 46 %h2 By language
35 47
36 48 %table.info
37 49 %thead
38 50 %tr.info-head
39 51 %th Language
40 52 %th Best runtime (ms)
41 53 %th Best memory (kbytes)
42 54 %th Shortest Code (bytes)
43 55 %th First solver
44 56 %tbody
45 57 - @by_lang.each do |lang,value|
46 58 %tr{class: cycle('info-even','info-odd')}
47 59 %td= lang
48 60 %td
49 - = "#{value[:runtime][:user]} (#{(value[:runtime][:value] * 1000).to_i} @"
61 + = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
62 + = "(#{(value[:runtime][:value] * 1000).to_i} @"
50 63 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
51 64 %td
52 - = "#{value[:memory][:user]} (#{value[:memory][:value]} @"
65 + = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
66 + = "(#{value[:memory][:value]} @"
53 67 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
54 68 %td
55 - = "#{value[:length][:user]} (#{value[:length][:value]} @"
69 + = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
70 + = "(#{value[:length][:value]} @"
56 71 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
57 72 %td
58 - = "#{value[:first][:user]} (#{value[:first][:value]} @"
59 - = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
73 + - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
74 + = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
75 + = "(#{value[:first][:value]} @"
76 + = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
60 77
61 78 - else
62 79 %h3 No submissions
@@ -1,31 +1,32
1 1 - content_for :header do
2 + = stylesheet_link_tag 'tablesorter-theme.cafe'
2 3 = javascript_include_tag 'new'
3 4
4 5 %script{:type=>"text/javascript"}
5 6 $(function () {
6 7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 8 $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']});
8 10 });
9 11
10 12 %h1 Login status
11 13
12 14 =render partial: 'report_menu'
13 15 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
14 16
15 - %table.info
17 + %table.tablesorter-cafe#my_table
16 18 %thead
17 - %tr.info-head
19 + %tr
18 20 %th login
19 21 %th full name
20 22 %th login count
21 23 %th earliest
22 24 %th latest
23 25 %tbody
24 26 - @logins.each do |l|
25 27 %tr{class: cycle('info-even','info-odd')}
26 - %td= l[:login]
28 + %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
27 29 %td= l[:full_name]
28 30 %td= l[:count]
29 31 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
30 - %td= l[:max] ? l[:max].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
31 -
32 + %td= l[:max] ? time_ago_in_words(l[:max].in_time_zone) + ' ago' : ''
@@ -1,30 +1,36
1 + - content_for :header do
2 + = javascript_include_tag 'new'
3 + = stylesheet_link_tag 'tablesorter-theme.cafe'
4 +
5 + %script{:type=>"text/javascript"}
6 + $(function () {
7 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widgets: ['zebra']});
10 + });
11 +
1 12 %h1 User grading results
2 13 %h2 Show max scores in submission range
3 14
4 15 - if @problem and @problem.errors
5 16 =error_messages_for 'problem'
6 17
7 18 = render partial: 'submission_range'
8 19
9 - - if @log
10 - %h3 Import log
11 - %pre.import-log
12 - = @log
13 -
14 20 %p= link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
15 21
16 - %table.info
22 + %table.tablesorter-cafe#my_table{style: 'width:auto;'}
17 23 %thead
18 - %tr.info-head
24 + %tr
19 25 %th User
20 26 %th Name
21 27 %th Activated?
22 28 %th Logged in
23 29 %th Contest(s)
24 30 - @problems.each do |p|
25 31 %th= p.name
26 32 %th Total
27 33 %th Passed
28 34 %tbody
29 35 - @scorearray.each do |sc|
30 36 %tr{class: cycle('info-even','info-odd')}
@@ -50,15 +50,15
50 50 # Enforce whitelist mode for mass assignment.
51 51 # This will create an empty whitelist of attributes available for mass-assignment for all models
52 52 # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
53 53 # parameters by using an attr_accessible or attr_protected declaration.
54 54 config.active_record.whitelist_attributes = false
55 55
56 56 # Enable the asset pipeline
57 57 config.assets.enabled = true
58 58
59 59 # Version of your assets, change this if you want to expire all your assets
60 60 config.assets.version = '1.0'
61 61
62 - config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js','graders.css','problems.css','new.js']
62 + config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js','graders.css','problems.css']
63 63 end
64 64 end
deleted file
You need to be logged in to leave comments. Login now