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 /.bundle
8 /.bundle
9
9
10 # Ignore the default SQLite database.
10 # Ignore the default SQLite database.
11 /db/*.sqlite3
11 /db/*.sqlite3
12
12
13 # Ignore all logfiles and tempfiles.
13 # Ignore all logfiles and tempfiles.
14 /log/*.log
14 /log/*.log
15 /tmp
15 /tmp
16
16
17 *~
17 *~
18
18
19 /vendor/plugins/rails_upgrade
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 # gem 'jbuilder'
28 # gem 'jbuilder'
29
29
30 # Use unicorn as the app server
30 # Use unicorn as the app server
31 # gem 'unicorn'
31 # gem 'unicorn'
32
32
33 # Deploy with Capistrano
33 # Deploy with Capistrano
34 # gem 'capistrano'
34 # gem 'capistrano'
35
35
36 # To use debugger
36 # To use debugger
37 # gem 'debugger'
37 # gem 'debugger'
38 #
38 #
39
39
40 + # jquery addition
40 gem 'jquery-rails'
41 gem 'jquery-rails'
41 gem 'jquery-ui-sass-rails'
42 gem 'jquery-ui-sass-rails'
42 gem 'jquery-timepicker-addon-rails'
43 gem 'jquery-timepicker-addon-rails'
44 + gem 'jquery-tablesorter'
43
45
44 #syntax highlighter
46 #syntax highlighter
45 gem 'rouge'
47 gem 'rouge'
46
48
47 gem "haml"
49 gem "haml"
48 gem "mail"
50 gem "mail"
49 gem "rdiscount"
51 gem "rdiscount"
50 gem "test-unit"
52 gem "test-unit"
51 gem 'will_paginate', '~> 3.0.0'
53 gem 'will_paginate', '~> 3.0.0'
52 gem 'dynamic_form'
54 gem 'dynamic_form'
53 gem 'in_place_editing'
55 gem 'in_place_editing'
54 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
56 gem 'verification', :git => 'git://github.com/sikachu/verification.git'
@@ -49,24 +49,26
49 dynamic_form (1.1.4)
49 dynamic_form (1.1.4)
50 erubis (2.7.0)
50 erubis (2.7.0)
51 execjs (2.2.1)
51 execjs (2.2.1)
52 haml (4.0.5)
52 haml (4.0.5)
53 tilt
53 tilt
54 hike (1.2.3)
54 hike (1.2.3)
55 i18n (0.6.11)
55 i18n (0.6.11)
56 in_place_editing (1.2.0)
56 in_place_editing (1.2.0)
57 journey (1.0.4)
57 journey (1.0.4)
58 jquery-rails (3.1.1)
58 jquery-rails (3.1.1)
59 railties (>= 3.0, < 5.0)
59 railties (>= 3.0, < 5.0)
60 thor (>= 0.14, < 2.0)
60 thor (>= 0.14, < 2.0)
61 + jquery-tablesorter (1.12.7)
62 + railties (>= 3.1, < 5)
61 jquery-timepicker-addon-rails (1.4.1)
63 jquery-timepicker-addon-rails (1.4.1)
62 railties (>= 3.1)
64 railties (>= 3.1)
63 jquery-ui-rails (4.0.3)
65 jquery-ui-rails (4.0.3)
64 jquery-rails
66 jquery-rails
65 railties (>= 3.1.0)
67 railties (>= 3.1.0)
66 jquery-ui-sass-rails (4.0.3.0)
68 jquery-ui-sass-rails (4.0.3.0)
67 jquery-rails
69 jquery-rails
68 jquery-ui-rails (= 4.0.3)
70 jquery-ui-rails (= 4.0.3)
69 railties (>= 3.1.0)
71 railties (>= 3.1.0)
70 json (1.8.1)
72 json (1.8.1)
71 mail (2.5.4)
73 mail (2.5.4)
72 mime-types (~> 1.16)
74 mime-types (~> 1.16)
@@ -143,24 +145,25
143 json (>= 1.8.0)
145 json (>= 1.8.0)
144 will_paginate (3.0.7)
146 will_paginate (3.0.7)
145
147
146 PLATFORMS
148 PLATFORMS
147 ruby
149 ruby
148
150
149 DEPENDENCIES
151 DEPENDENCIES
150 coffee-rails (~> 3.2.1)
152 coffee-rails (~> 3.2.1)
151 dynamic_form
153 dynamic_form
152 haml
154 haml
153 in_place_editing
155 in_place_editing
154 jquery-rails
156 jquery-rails
157 + jquery-tablesorter
155 jquery-timepicker-addon-rails
158 jquery-timepicker-addon-rails
156 jquery-ui-sass-rails
159 jquery-ui-sass-rails
157 mail
160 mail
158 mysql2
161 mysql2
159 prototype-rails
162 prototype-rails
160 rails (= 3.2.19)
163 rails (= 3.2.19)
161 rdiscount
164 rdiscount
162 rouge
165 rouge
163 rspec-rails (~> 2.0)
166 rspec-rails (~> 2.0)
164 sass-rails (~> 3.2.3)
167 sass-rails (~> 3.2.3)
165 test-unit
168 test-unit
166 uglifier (>= 1.0.3)
169 uglifier (>= 1.0.3)
@@ -1,6 +1,7
1 //= require jquery
1 //= require jquery
2 //= require jquery_ujs
2 //= require jquery_ujs
3 //= require jquery.ui.all
3 //= require jquery.ui.all
4 //= require jquery.ui.datepicker
4 //= require jquery.ui.datepicker
5 //= require jquery.ui.slider
5 //= require jquery.ui.slider
6 //= require jquery-ui-timepicker-addon
6 //= require jquery-ui-timepicker-addon
7 + //= require jquery-tablesorter
@@ -1,19 +1,20
1
1
2 @import jquery.ui.core
2 @import jquery.ui.core
3 @import jquery.ui.theme
3 @import jquery.ui.theme
4 @import jquery.ui.datepicker
4 @import jquery.ui.datepicker
5 @import jquery.ui.slider
5 @import jquery.ui.slider
6 @import jquery-ui-timepicker-addon
6 @import jquery-ui-timepicker-addon
7 -
7 + @import jquery-tablesorter/theme.metro-dark
8 + @import tablesorter-theme.cafe
8
9
9 body
10 body
10 background: white image-url("topbg.jpg") repeat-x top center
11 background: white image-url("topbg.jpg") repeat-x top center
11 font-size: 13px
12 font-size: 13px
12 font-family: Tahoma, "sans-serif"
13 font-family: Tahoma, "sans-serif"
13 margin: 10px
14 margin: 10px
14 padding: 10px
15 padding: 10px
15
16
16
17
17 input
18 input
18 font-family: Tahoma, "sans-serif"
19 font-family: Tahoma, "sans-serif"
19
20
@@ -18,25 +18,26
18 begin
18 begin
19 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
19 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
20 rescue
20 rescue
21 @since_time = DateTime.new(1000,1,1)
21 @since_time = DateTime.new(1000,1,1)
22 end
22 end
23 begin
23 begin
24 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
24 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
25 rescue
25 rescue
26 @until_time = DateTime.new(3000,1,1)
26 @until_time = DateTime.new(3000,1,1)
27 end
27 end
28
28
29 User.all.each do |user|
29 User.all.each do |user|
30 - @logins << { login: user.login,
30 + @logins << { id: user.id,
31 + login: user.login,
31 full_name: user.full_name,
32 full_name: user.full_name,
32 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
33 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
33 user.id,@since_time,@until_time)
34 user.id,@since_time,@until_time)
34 .count(:id),
35 .count(:id),
35 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 user.id,@since_time,@until_time)
37 user.id,@since_time,@until_time)
37 .minimum(:created_at),
38 .minimum(:created_at),
38 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 user.id,@since_time,@until_time)
40 user.id,@since_time,@until_time)
40 .maximum(:created_at)
41 .maximum(:created_at)
41 }
42 }
42 end
43 end
@@ -150,24 +150,26
150 @users.each do |u|
150 @users.each do |u|
151 ustat = Array.new
151 ustat = Array.new
152 ustat[0] = u
152 ustat[0] = u
153 @problems.each do |p|
153 @problems.each do |p|
154 max_points = 0
154 max_points = 0
155 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
155 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
156 max_points = sub.points if sub and sub.points and (sub.points > max_points)
156 max_points = sub.points if sub and sub.points and (sub.points > max_points)
157 end
157 end
158 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
158 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
159 end
159 end
160 @scorearray << ustat
160 @scorearray << ustat
161 end
161 end
162 +
163 + render template: 'user_admin/user_stat'
162 end
164 end
163
165
164 def import
166 def import
165 if params[:file]==''
167 if params[:file]==''
166 flash[:notice] = 'Error importing no file'
168 flash[:notice] = 'Error importing no file'
167 redirect_to :action => 'list' and return
169 redirect_to :action => 'list' and return
168 end
170 end
169 import_from_file(params[:file])
171 import_from_file(params[:file])
170 end
172 end
171
173
172 def random_all_passwords
174 def random_all_passwords
173 users = User.find(:all)
175 users = User.find(:all)
@@ -5,24 +5,25
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_filter :authenticate, :except => [:new,
7 before_filter :authenticate, :except => [:new,
8 :register,
8 :register,
9 :confirm,
9 :confirm,
10 :forget,
10 :forget,
11 :retrieve_password]
11 :retrieve_password]
12
12
13 before_filter :verify_online_registration, :only => [:new,
13 before_filter :verify_online_registration, :only => [:new,
14 :register,
14 :register,
15 :forget,
15 :forget,
16 :retrieve_password]
16 :retrieve_password]
17 + before_filter :authenticate, :profile_authorization, only: [:profile]
17
18
18 verify :method => :post, :only => [:chg_passwd],
19 verify :method => :post, :only => [:chg_passwd],
19 :redirect_to => { :action => :index }
20 :redirect_to => { :action => :index }
20
21
21 #in_place_edit_for :user, :alias_for_editing
22 #in_place_edit_for :user, :alias_for_editing
22 #in_place_edit_for :user, :email_for_editing
23 #in_place_edit_for :user, :email_for_editing
23
24
24 def index
25 def index
25 if !GraderConfiguration['system.user_setting_enabled']
26 if !GraderConfiguration['system.user_setting_enabled']
26 redirect_to :controller => 'main', :action => 'list'
27 redirect_to :controller => 'main', :action => 'list'
27 else
28 else
28 @user = User.find(session[:user_id])
29 @user = User.find(session[:user_id])
@@ -99,24 +100,29
99 else
100 else
100 user.password = user.password_confirmation = User.random_password
101 user.password = user.password_confirmation = User.random_password
101 user.save
102 user.save
102 send_new_password_email(user)
103 send_new_password_email(user)
103 flash[:notice] = 'New password has been mailed to you.'
104 flash[:notice] = 'New password has been mailed to you.'
104 end
105 end
105 else
106 else
106 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
107 end
108 end
108 redirect_to :action => 'forget'
109 redirect_to :action => 'forget'
109 end
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 protected
117 protected
112
118
113 def verify_online_registration
119 def verify_online_registration
114 if !GraderConfiguration['system.online_registration']
120 if !GraderConfiguration['system.online_registration']
115 redirect_to :controller => 'main', :action => 'login'
121 redirect_to :controller => 'main', :action => 'login'
116 end
122 end
117 end
123 end
118
124
119 def send_confirmation_email(user)
125 def send_confirmation_email(user)
120 contest_name = GraderConfiguration['contest.name']
126 contest_name = GraderConfiguration['contest.name']
121 activation_url = url_for(:action => 'confirm',
127 activation_url = url_for(:action => 'confirm',
122 :login => user.login,
128 :login => user.login,
@@ -143,14 +149,28
143 mail_body = t('registration.password_retrieval.email_body', {
149 mail_body = t('registration.password_retrieval.email_body', {
144 :full_name => user.full_name,
150 :full_name => user.full_name,
145 :contest_name => contest_name,
151 :contest_name => contest_name,
146 :login => user.login,
152 :login => user.login,
147 :password => user.password,
153 :password => user.password,
148 :admin_email => admin_email
154 :admin_email => admin_email
149 })
155 })
150
156
151 logger.info mail_body
157 logger.info mail_body
152
158
153 send_mail(user.email, mail_subject, mail_body)
159 send_mail(user.email, mail_subject, mail_body)
154 end
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 end
176 end
@@ -1,62 +1,79
1 :css
1 :css
2 .hof_user { color: orangered; font-style: italic; }
2 .hof_user { color: orangered; font-style: italic; }
3 .hof_language { color: green; font-style: italic; }
3 .hof_language { color: green; font-style: italic; }
4 .hof_value { color: deeppink;font-style: italic; }
4 .hof_value { color: deeppink;font-style: italic; }
5
5
6 %h2 Overall
6 %h2 Overall
7
7
8 - if @best
8 - if @best
9 %b Best Runtime:
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 = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
14 = link_to("#" + @best[:runtime][:sub_id].to_s, controller: 'graders', action: 'submission', id:@best[:runtime][:sub_id])
12 %br/
15 %br/
13
16
14 %b Best Memory Usage:
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 = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
22 = link_to("#" + @best[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id:@best[:memory][:sub_id])
17 %br/
23 %br/
18
24
19 - %b Shortest Code:
25 + %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
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 = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
30 = link_to("#" + @best[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:length][:sub_id])
22 %br/
31 %br/
23
32
24 - %b First solver:
33 + %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
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 = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
38 = link_to("#" + @best[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: @best[:first][:sub_id])
27 %br/
39 %br/
28
40
29
41
30 %p
42 %p
31 This counts only for submission with 100% score <br/>
43 This counts only for submission with 100% score <br/>
32 Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
44 Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)
33
45
34 %h2 By language
46 %h2 By language
35
47
36 %table.info
48 %table.info
37 %thead
49 %thead
38 %tr.info-head
50 %tr.info-head
39 %th Language
51 %th Language
40 %th Best runtime (ms)
52 %th Best runtime (ms)
41 %th Best memory (kbytes)
53 %th Best memory (kbytes)
42 %th Shortest Code (bytes)
54 %th Shortest Code (bytes)
43 %th First solver
55 %th First solver
44 %tbody
56 %tbody
45 - @by_lang.each do |lang,value|
57 - @by_lang.each do |lang,value|
46 %tr{class: cycle('info-even','info-odd')}
58 %tr{class: cycle('info-even','info-odd')}
47 %td= lang
59 %td= lang
48 %td
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 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
63 = "#{link_to("#" + value[:runtime][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:runtime][:sub_id])} )".html_safe
51 %td
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 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
67 = "#{link_to("#" + value[:memory][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:memory][:sub_id])} )".html_safe
54 %td
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 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
71 = "#{link_to("#" + value[:length][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:length][:sub_id])} )".html_safe
57 %td
72 %td
58 - = "#{value[:first][:user]} (#{value[:first][:value]} @"
73 + - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
59 - = "#{link_to("#" + value[:first][:sub_id].to_s, controller: 'graders' , action: 'submission', id: value[:first][:sub_id])} )".html_safe
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 - else
78 - else
62 %h3 No submissions
79 %h3 No submissions
@@ -1,31 +1,32
1 - content_for :header do
1 - content_for :header do
2 + = stylesheet_link_tag 'tablesorter-theme.cafe'
2 = javascript_include_tag 'new'
3 = javascript_include_tag 'new'
3
4
4 %script{:type=>"text/javascript"}
5 %script{:type=>"text/javascript"}
5 $(function () {
6 $(function () {
6 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
7 $('#until_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({widthFixed: true, widgets: ['zebra']});
8 });
10 });
9
11
10 %h1 Login status
12 %h1 Login status
11
13
12 =render partial: 'report_menu'
14 =render partial: 'report_menu'
13 =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
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 %thead
18 %thead
17 - %tr.info-head
19 + %tr
18 %th login
20 %th login
19 %th full name
21 %th full name
20 %th login count
22 %th login count
21 %th earliest
23 %th earliest
22 %th latest
24 %th latest
23 %tbody
25 %tbody
24 - @logins.each do |l|
26 - @logins.each do |l|
25 %tr{class: cycle('info-even','info-odd')}
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 %td= l[:full_name]
29 %td= l[:full_name]
28 %td= l[:count]
30 %td= l[:count]
29 %td= l[:min] ? l[:min].in_time_zone.strftime('%Y-%m-%d %H:%M') : ''
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') : ''
32 + %td= l[:max] ? time_ago_in_words(l[:max].in_time_zone) + ' ago' : ''
31 -
@@ -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 %h1 User grading results
12 %h1 User grading results
2 %h2 Show max scores in submission range
13 %h2 Show max scores in submission range
3
14
4 - if @problem and @problem.errors
15 - if @problem and @problem.errors
5 =error_messages_for 'problem'
16 =error_messages_for 'problem'
6
17
7 = render partial: 'submission_range'
18 = render partial: 'submission_range'
8
19
9 - - if @log
10 - %h3 Import log
11 - %pre.import-log
12 - = @log
13 -
14 %p= link_to '[Show only latest submissions]', controller: :user_admin, action: :user_stat
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 %thead
23 %thead
18 - %tr.info-head
24 + %tr
19 %th User
25 %th User
20 %th Name
26 %th Name
21 %th Activated?
27 %th Activated?
22 %th Logged in
28 %th Logged in
23 %th Contest(s)
29 %th Contest(s)
24 - @problems.each do |p|
30 - @problems.each do |p|
25 %th= p.name
31 %th= p.name
26 %th Total
32 %th Total
27 %th Passed
33 %th Passed
28 %tbody
34 %tbody
29 - @scorearray.each do |sc|
35 - @scorearray.each do |sc|
30 %tr{class: cycle('info-even','info-odd')}
36 %tr{class: cycle('info-even','info-odd')}
@@ -50,15 +50,15
50 # Enforce whitelist mode for mass assignment.
50 # Enforce whitelist mode for mass assignment.
51 # This will create an empty whitelist of attributes available for mass-assignment for all models
51 # This will create an empty whitelist of attributes available for mass-assignment for all models
52 # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
52 # in your app. As such, your models will need to explicitly whitelist or blacklist accessible
53 # parameters by using an attr_accessible or attr_protected declaration.
53 # parameters by using an attr_accessible or attr_protected declaration.
54 config.active_record.whitelist_attributes = false
54 config.active_record.whitelist_attributes = false
55
55
56 # Enable the asset pipeline
56 # Enable the asset pipeline
57 config.assets.enabled = true
57 config.assets.enabled = true
58
58
59 # Version of your assets, change this if you want to expire all your assets
59 # Version of your assets, change this if you want to expire all your assets
60 config.assets.version = '1.0'
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 end
63 end
64 end
64 end
deleted file
You need to be logged in to leave comments. Login now