Description:
consolidate
Commit status:
[Not Reviewed]
References:
merge algo
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r489:915396c14fc6 - - 23 files changed: 123 inserted, 159 deleted

@@ -1,63 +1,63
1 1 source 'https://rubygems.org'
2 2
3 - gem 'rails', '3.2.19'
3 + gem 'rails', '3.2.21'
4 4
5 5 # Bundle edge Rails instead:
6 6 # gem 'rails', :git => 'git://github.com/rails/rails.git'
7 7
8 8 gem 'mysql2'
9 9
10 10 # Gems used only for assets and not required
11 11 # in production environments by default.
12 12 group :assets do
13 - gem 'sass-rails', '~> 3.2.3'
14 - gem 'coffee-rails', '~> 3.2.1'
13 + gem 'sass-rails', '~> 3.2.6'
14 + gem 'coffee-rails', '~> 3.2.2'
15 15
16 16 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
17 17 # gem 'therubyracer', :platforms => :ruby
18 18
19 - gem 'uglifier', '>= 1.0.3'
19 + gem 'uglifier'
20 20 end
21 21
22 22 gem 'prototype-rails'
23 23
24 24 # To use ActiveModel has_secure_password
25 25 # gem 'bcrypt-ruby', '~> 3.0.0'
26 26
27 27 # To use Jbuilder templates for JSON
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 40 #in-place editor
41 41 gem 'best_in_place', '~> 3.0.1'
42 42
43 43 # jquery addition
44 44 gem 'jquery-rails'
45 45 gem 'jquery-ui-sass-rails'
46 46 gem 'jquery-timepicker-addon-rails'
47 47 gem 'jquery-tablesorter'
48 48
49 49 #syntax highlighter
50 50 gem 'rouge'
51 51
52 - gem "haml"
53 - gem "mail"
54 - gem "rdiscount"
55 - gem "test-unit"
56 - gem 'will_paginate', '~> 3.0.0'
52 + gem 'haml'
53 + gem 'mail'
54 + gem 'rdiscount'
55 + gem 'test-unit'
56 + gem 'will_paginate', '~> 3.0.7'
57 57 gem 'dynamic_form'
58 58 gem 'in_place_editing'
59 - gem 'verification', :git => 'git://github.com/sikachu/verification.git'
59 + gem 'verification', :git => 'https://github.com/sikachu/verification.git'
60 60
61 61 group :test, :development do
62 - gem "rspec-rails", "~> 2.0"
62 + gem 'rspec-rails', '~> 2.99.0'
63 63 end
@@ -1,175 +1,175
1 1 GIT
2 - remote: git://github.com/sikachu/verification.git
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 - actionmailer (3.2.19)
13 - actionpack (= 3.2.19)
12 + actionmailer (3.2.21)
13 + actionpack (= 3.2.21)
14 14 mail (~> 2.5.4)
15 - actionpack (3.2.19)
16 - activemodel (= 3.2.19)
17 - activesupport (= 3.2.19)
15 + actionpack (3.2.21)
16 + activemodel (= 3.2.21)
17 + activesupport (= 3.2.21)
18 18 builder (~> 3.0.0)
19 19 erubis (~> 2.7.0)
20 20 journey (~> 1.0.4)
21 21 rack (~> 1.4.5)
22 22 rack-cache (~> 1.2)
23 23 rack-test (~> 0.6.1)
24 24 sprockets (~> 2.2.1)
25 - activemodel (3.2.19)
26 - activesupport (= 3.2.19)
25 + activemodel (3.2.21)
26 + activesupport (= 3.2.21)
27 27 builder (~> 3.0.0)
28 - activerecord (3.2.19)
29 - activemodel (= 3.2.19)
30 - activesupport (= 3.2.19)
28 + activerecord (3.2.21)
29 + activemodel (= 3.2.21)
30 + activesupport (= 3.2.21)
31 31 arel (~> 3.0.2)
32 32 tzinfo (~> 0.3.29)
33 - activeresource (3.2.19)
34 - activemodel (= 3.2.19)
35 - activesupport (= 3.2.19)
36 - activesupport (3.2.19)
33 + activeresource (3.2.21)
34 + activemodel (= 3.2.21)
35 + activesupport (= 3.2.21)
36 + activesupport (3.2.21)
37 37 i18n (~> 0.6, >= 0.6.4)
38 38 multi_json (~> 1.0)
39 39 arel (3.0.3)
40 - best_in_place (3.0.2)
40 + best_in_place (3.0.3)
41 41 actionpack (>= 3.2)
42 42 railties (>= 3.2)
43 43 builder (3.0.4)
44 44 coffee-rails (3.2.2)
45 45 coffee-script (>= 2.2.0)
46 46 railties (~> 3.2.0)
47 47 coffee-script (2.3.0)
48 48 coffee-script-source
49 49 execjs
50 - coffee-script-source (1.7.1)
50 + coffee-script-source (1.9.0)
51 51 diff-lcs (1.2.5)
52 52 dynamic_form (1.1.4)
53 53 erubis (2.7.0)
54 - execjs (2.2.1)
55 - haml (4.0.5)
54 + execjs (2.3.0)
55 + haml (4.0.6)
56 56 tilt
57 57 hike (1.2.3)
58 - i18n (0.6.11)
58 + i18n (0.7.0)
59 59 in_place_editing (1.2.0)
60 60 journey (1.0.4)
61 - jquery-rails (3.1.1)
61 + jquery-rails (3.1.2)
62 62 railties (>= 3.0, < 5.0)
63 63 thor (>= 0.14, < 2.0)
64 - jquery-tablesorter (1.12.7)
64 + jquery-tablesorter (1.13.4)
65 65 railties (>= 3.1, < 5)
66 66 jquery-timepicker-addon-rails (1.4.1)
67 67 railties (>= 3.1)
68 68 jquery-ui-rails (4.0.3)
69 69 jquery-rails
70 70 railties (>= 3.1.0)
71 71 jquery-ui-sass-rails (4.0.3.0)
72 72 jquery-rails
73 73 jquery-ui-rails (= 4.0.3)
74 74 railties (>= 3.1.0)
75 - json (1.8.1)
75 + json (1.8.2)
76 76 mail (2.5.4)
77 77 mime-types (~> 1.16)
78 78 treetop (~> 1.4.8)
79 79 mime-types (1.25.1)
80 80 multi_json (1.10.1)
81 - mysql2 (0.3.16)
81 + mysql2 (0.3.17)
82 82 polyglot (0.3.5)
83 - power_assert (0.1.3)
83 + power_assert (0.2.2)
84 84 prototype-rails (3.2.1)
85 85 rails (~> 3.2)
86 86 rack (1.4.5)
87 87 rack-cache (1.2)
88 88 rack (>= 0.4)
89 89 rack-ssl (1.3.4)
90 90 rack
91 - rack-test (0.6.2)
91 + rack-test (0.6.3)
92 92 rack (>= 1.0)
93 - rails (3.2.19)
94 - actionmailer (= 3.2.19)
95 - actionpack (= 3.2.19)
96 - activerecord (= 3.2.19)
97 - activeresource (= 3.2.19)
98 - activesupport (= 3.2.19)
93 + rails (3.2.21)
94 + actionmailer (= 3.2.21)
95 + actionpack (= 3.2.21)
96 + activerecord (= 3.2.21)
97 + activeresource (= 3.2.21)
98 + activesupport (= 3.2.21)
99 99 bundler (~> 1.0)
100 - railties (= 3.2.19)
101 - railties (3.2.19)
102 - actionpack (= 3.2.19)
103 - activesupport (= 3.2.19)
100 + railties (= 3.2.21)
101 + railties (3.2.21)
102 + actionpack (= 3.2.21)
103 + activesupport (= 3.2.21)
104 104 rack-ssl (~> 1.3.2)
105 105 rake (>= 0.8.7)
106 106 rdoc (~> 3.4)
107 107 thor (>= 0.14.6, < 2.0)
108 - rake (10.3.2)
109 - rdiscount (2.1.7.1)
108 + rake (10.4.2)
109 + rdiscount (2.1.8)
110 110 rdoc (3.12.2)
111 111 json (~> 1.4)
112 - rouge (1.6.2)
113 - rspec-collection_matchers (1.0.0)
112 + rouge (1.8.0)
113 + rspec-collection_matchers (1.1.2)
114 114 rspec-expectations (>= 2.99.0.beta1)
115 115 rspec-core (2.99.2)
116 116 rspec-expectations (2.99.2)
117 117 diff-lcs (>= 1.1.3, < 2.0)
118 - rspec-mocks (2.99.2)
118 + rspec-mocks (2.99.3)
119 119 rspec-rails (2.99.0)
120 120 actionpack (>= 3.0)
121 121 activemodel (>= 3.0)
122 122 activesupport (>= 3.0)
123 123 railties (>= 3.0)
124 124 rspec-collection_matchers
125 125 rspec-core (~> 2.99.0)
126 126 rspec-expectations (~> 2.99.0)
127 127 rspec-mocks (~> 2.99.0)
128 - sass (3.4.1)
128 + sass (3.4.11)
129 129 sass-rails (3.2.6)
130 130 railties (~> 3.2.0)
131 131 sass (>= 3.1.10)
132 132 tilt (~> 1.3)
133 - sprockets (2.2.2)
133 + sprockets (2.2.3)
134 134 hike (~> 1.2)
135 135 multi_json (~> 1.0)
136 136 rack (~> 1.0)
137 137 tilt (~> 1.1, != 1.3.0)
138 - test-unit (3.0.1)
138 + test-unit (3.0.9)
139 139 power_assert
140 140 thor (0.19.1)
141 141 tilt (1.4.1)
142 142 treetop (1.4.15)
143 143 polyglot
144 144 polyglot (>= 0.3.1)
145 - tzinfo (0.3.41)
146 - uglifier (2.5.3)
145 + tzinfo (0.3.43)
146 + uglifier (2.7.0)
147 147 execjs (>= 0.3.0)
148 148 json (>= 1.8.0)
149 149 will_paginate (3.0.7)
150 150
151 151 PLATFORMS
152 152 ruby
153 153
154 154 DEPENDENCIES
155 155 best_in_place (~> 3.0.1)
156 - coffee-rails (~> 3.2.1)
156 + coffee-rails (~> 3.2.2)
157 157 dynamic_form
158 158 haml
159 159 in_place_editing
160 160 jquery-rails
161 161 jquery-tablesorter
162 162 jquery-timepicker-addon-rails
163 163 jquery-ui-sass-rails
164 164 mail
165 165 mysql2
166 166 prototype-rails
167 - rails (= 3.2.19)
167 + rails (= 3.2.21)
168 168 rdiscount
169 169 rouge
170 - rspec-rails (~> 2.0)
171 - sass-rails (~> 3.2.3)
170 + rspec-rails (~> 2.99.0)
171 + sass-rails (~> 3.2.6)
172 172 test-unit
173 - uglifier (>= 1.0.3)
173 + uglifier
174 174 verification!
175 - will_paginate (~> 3.0.0)
175 + will_paginate (~> 3.0.7)
@@ -1,50 +1,50
1 1 class ContestManagementController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 def index
6 6 @num_contests = Contest.count()
7 7 end
8 8
9 9 def user_stat
10 10 if not GraderConfiguration.indv_contest_mode?
11 11 redirect_to :action => 'index' and return
12 12 end
13 13
14 14 @users = User.find(:all)
15 15 @start_times = {}
16 16 UserContestStat.find(:all).each do |stat|
17 17 @start_times[stat.user_id] = stat.started_at
18 18 end
19 19 end
20 20
21 21 def clear_stat
22 22 user = User.find(params[:id])
23 23 if user.contest_stat!=nil
24 24 user.contest_stat.destroy
25 25 end
26 26 redirect_to :action => 'user_stat'
27 27 end
28 28
29 29 def clear_all_stat
30 30 if not GraderConfiguration.indv_contest_mode?
31 31 redirect_to :action => 'index' and return
32 32 end
33 33
34 34 UserContestStat.delete_all()
35 35 flash[:notice] = 'All start time statistic cleared.'
36 36 redirect_to :action => 'index'
37 37 end
38 38
39 39 def change_contest_mode
40 - if ['standard', 'contest', 'indv-contest'].include? params[:id]
40 + if ['standard', 'contest', 'indv-contest', 'analysis'].include? params[:id]
41 41 config = GraderConfiguration.find_by_key('system.mode')
42 42 config.value = params[:id]
43 43 config.save
44 44 else
45 45 flash[:notice] = 'Wrong contest mode value'
46 46 end
47 47 redirect_to :action => 'index'
48 48 end
49 49
50 50 end
@@ -1,293 +1,293
1 1 class MainController < ApplicationController
2 2
3 3 before_filter :authenticate, :except => [:index, :login]
4 4 before_filter :check_viewability, :except => [:index, :login]
5 5
6 6 append_before_filter :confirm_and_update_start_time,
7 7 :except => [:index,
8 8 :login,
9 9 :confirm_contest_start]
10 10
11 11 # to prevent log in box to be shown when user logged out of the
12 12 # system only in some tab
13 13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 14 :only => [:announcements]
15 15
16 16 # COMMENTED OUT: filter in each action instead
17 17 # before_filter :verify_time_limit, :only => [:submit]
18 18
19 19 verify :method => :post, :only => [:submit],
20 20 :redirect_to => { :action => :index }
21 21
22 22 # COMMENT OUT: only need when having high load
23 23 # caches_action :index, :login
24 24
25 25 # NOTE: This method is not actually needed, 'config/routes.rb' has
26 26 # assigned action login as a default action.
27 27 def index
28 28 redirect_to :action => 'login'
29 29 end
30 30
31 31 def login
32 32 saved_notice = flash[:notice]
33 33 reset_session
34 34 flash.now[:notice] = saved_notice
35 35
36 36 # EXPERIMENT:
37 37 # Hide login if in single user mode and the url does not
38 38 # explicitly specify /login
39 39 #
40 40 # logger.info "PATH: #{request.path}"
41 41 # if GraderConfiguration['system.single_user_mode'] and
42 42 # request.path!='/main/login'
43 43 # @hidelogin = true
44 44 # end
45 45
46 46 @announcements = Announcement.find_for_frontpage
47 47 render :action => 'login', :layout => 'empty'
48 48 end
49 49
50 50 def list
51 51 prepare_list_information
52 52 end
53 53
54 54 def help
55 55 @user = User.find(session[:user_id])
56 56 end
57 57
58 58 def submit
59 59 user = User.find(session[:user_id])
60 60
61 61 @submission = Submission.new
62 62 @submission.problem_id = params[:submission][:problem_id]
63 63 @submission.user = user
64 64 @submission.language_id = 0
65 65 if (params['file']) and (params['file']!='')
66 66 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
67 67 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
68 68 @submission.source_filename = params['file'].original_filename
69 69 end
70 70 @submission.submitted_at = Time.new.gmtime
71 71 @submission.ip_address = request.remote_ip
72 72
73 73 if GraderConfiguration.time_limit_mode? and user.contest_finished?
74 - @submission.errors.add_to_base "The contest is over."
74 + @submission.errors.add(:base,"The contest is over.")
75 75 prepare_list_information
76 76 render :action => 'list' and return
77 77 end
78 78
79 79 if @submission.valid?
80 80 if @submission.save == false
81 81 flash[:notice] = 'Error saving your submission'
82 82 elsif Task.create(:submission_id => @submission.id,
83 83 :status => Task::STATUS_INQUEUE) == false
84 84 flash[:notice] = 'Error adding your submission to task queue'
85 85 end
86 86 else
87 87 prepare_list_information
88 88 render :action => 'list' and return
89 89 end
90 90 redirect_to :action => 'list'
91 91 end
92 92
93 93 def source
94 94 submission = Submission.find(params[:id])
95 95 if ((submission.user_id == session[:user_id]) and
96 96 (submission.problem != nil) and
97 97 (submission.problem.available))
98 98 send_data(submission.source,
99 99 {:filename => submission.download_filename,
100 100 :type => 'text/plain'})
101 101 else
102 102 flash[:notice] = 'Error viewing source'
103 103 redirect_to :action => 'list'
104 104 end
105 105 end
106 106
107 107 def compiler_msg
108 108 @submission = Submission.find(params[:id])
109 109 if @submission.user_id == session[:user_id]
110 110 render :action => 'compiler_msg', :layout => 'empty'
111 111 else
112 112 flash[:notice] = 'Error viewing source'
113 113 redirect_to :action => 'list'
114 114 end
115 115 end
116 116
117 117 def submission
118 118 @user = User.find(session[:user_id])
119 119 @problems = @user.available_problems
120 120 if params[:id]==nil
121 121 @problem = nil
122 122 @submissions = nil
123 123 else
124 124 @problem = Problem.find_by_name(params[:id])
125 125 if not @problem.available
126 126 redirect_to :action => 'list'
127 127 flash[:notice] = 'Error: submissions for that problem are not viewable.'
128 128 return
129 129 end
130 130 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
131 131 end
132 132 end
133 133
134 134 def result
135 135 if !GraderConfiguration.show_grading_result
136 136 redirect_to :action => 'list' and return
137 137 end
138 138 @user = User.find(session[:user_id])
139 139 @submission = Submission.find(params[:id])
140 140 if @submission.user!=@user
141 141 flash[:notice] = 'You are not allowed to view result of other users.'
142 142 redirect_to :action => 'list' and return
143 143 end
144 144 prepare_grading_result(@submission)
145 145 end
146 146
147 147 def load_output
148 148 if !GraderConfiguration.show_grading_result or params[:num]==nil
149 149 redirect_to :action => 'list' and return
150 150 end
151 151 @user = User.find(session[:user_id])
152 152 @submission = Submission.find(params[:id])
153 153 if @submission.user!=@user
154 154 flash[:notice] = 'You are not allowed to view result of other users.'
155 155 redirect_to :action => 'list' and return
156 156 end
157 157 case_num = params[:num].to_i
158 158 out_filename = output_filename(@user.login,
159 159 @submission.problem.name,
160 160 @submission.id,
161 161 case_num)
162 162 if !FileTest.exists?(out_filename)
163 163 flash[:notice] = 'Output not found.'
164 164 redirect_to :action => 'list' and return
165 165 end
166 166
167 167 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
168 168 response.headers['Content-Type'] = "application/force-download"
169 169 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
170 170 response.headers["X-Sendfile"] = out_filename
171 171 response.headers['Content-length'] = File.size(out_filename)
172 172 render :nothing => true
173 173 else
174 174 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
175 175 end
176 176 end
177 177
178 178 def error
179 179 @user = User.find(session[:user_id])
180 180 end
181 181
182 182 # announcement refreshing and hiding methods
183 183
184 184 def announcements
185 185 if params.has_key? 'recent'
186 186 prepare_announcements(params[:recent])
187 187 else
188 188 prepare_announcements
189 189 end
190 190 render(:partial => 'announcement',
191 191 :collection => @announcements,
192 192 :locals => {:announcement_effect => true})
193 193 end
194 194
195 195 def confirm_contest_start
196 196 user = User.find(session[:user_id])
197 - if request.method == :post
197 + if request.method == 'POST'
198 198 user.update_start_time
199 199 redirect_to :action => 'list'
200 200 else
201 201 @contests = user.contests
202 202 @user = user
203 203 end
204 204 end
205 205
206 206 protected
207 207
208 208 def prepare_announcements(recent=nil)
209 209 if GraderConfiguration.show_tasks_to?(@user)
210 210 @announcements = Announcement.find_published(true)
211 211 else
212 212 @announcements = Announcement.find_published
213 213 end
214 214 if recent!=nil
215 215 recent_id = recent.to_i
216 216 @announcements = @announcements.find_all { |a| a.id > recent_id }
217 217 end
218 218 end
219 219
220 220 def prepare_list_information
221 221 @user = User.find(session[:user_id])
222 222 if not GraderConfiguration.multicontests?
223 223 @problems = @user.available_problems
224 224 else
225 225 @contest_problems = @user.available_problems_group_by_contests
226 226 @problems = @user.available_problems
227 227 end
228 228 @prob_submissions = {}
229 229 @problems.each do |p|
230 230 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
231 231 if sub!=nil
232 232 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
233 233 else
234 234 @prob_submissions[p.id] = { :count => 0, :submission => nil }
235 235 end
236 236 end
237 237 prepare_announcements
238 238 end
239 239
240 240 def check_viewability
241 241 @user = User.find(session[:user_id])
242 242 if (!GraderConfiguration.show_tasks_to?(@user)) and
243 243 ((action_name=='submission') or (action_name=='submit'))
244 244 redirect_to :action => 'list' and return
245 245 end
246 246 end
247 247
248 248 def prepare_grading_result(submission)
249 249 if GraderConfiguration.task_grading_info.has_key? submission.problem.name
250 250 grading_info = GraderConfiguration.task_grading_info[submission.problem.name]
251 251 else
252 252 # guess task info from problem.full_score
253 253 cases = submission.problem.full_score / 10
254 254 grading_info = {
255 255 'testruns' => cases,
256 256 'testcases' => cases
257 257 }
258 258 end
259 259 @test_runs = []
260 260 if grading_info['testruns'].is_a? Integer
261 261 trun_count = grading_info['testruns']
262 262 trun_count.times do |i|
263 263 @test_runs << [ read_grading_result(@user.login,
264 264 submission.problem.name,
265 265 submission.id,
266 266 i+1) ]
267 267 end
268 268 else
269 269 grading_info['testruns'].keys.sort.each do |num|
270 270 run = []
271 271 testrun = grading_info['testruns'][num]
272 272 testrun.each do |c|
273 273 run << read_grading_result(@user.login,
274 274 submission.problem.name,
275 275 submission.id,
276 276 c)
277 277 end
278 278 @test_runs << run
279 279 end
280 280 end
281 281 end
282 282
283 283 def grading_result_dir(user_name, problem_name, submission_id, case_num)
284 284 return "#{GRADING_RESULT_DIR}/#{user_name}/#{problem_name}/#{submission_id}/test-result/#{case_num}"
285 285 end
286 286
287 287 def output_filename(user_name, problem_name, submission_id, case_num)
288 288 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
289 289 return "#{dir}/output.txt"
290 290 end
291 291
292 292 def read_grading_result(user_name, problem_name, submission_id, case_num)
293 293 dir = grading_result_dir(user_name,problem_name, submission_id, case_num)
@@ -1,85 +1,86
1 1 class MessagesController < ApplicationController
2 2
3 3 before_filter :authenticate
4 4
5 5 verify :method => :post, :only => ['create'],
6 6 :redirect_to => { :action => 'list' }
7 7
8 8 before_filter :admin_authorization, :only => ['console','show',
9 9 'reply','hide','list_all']
10 10
11 11 def list
12 12 @user = User.find(session[:user_id])
13 13 @messages = Message.find_all_sent_by_user(@user)
14 14 end
15 15
16 16 def console
17 17 @user = User.find(session[:user_id])
18 18 @messages = Message.find_all_system_unreplied_messages
19 19 end
20 20
21 21 def show
22 22 @message = Message.find(params[:id])
23 23 end
24 24
25 25 def list_all
26 26 @user = User.find(session[:user_id])
27 27 @messages = Message.where(receiver_id: nil).order(:created_at)
28 28 end
29 29
30 30 def create
31 31 user = User.find(session[:user_id])
32 32 @message = Message.new(params[:message])
33 33 @message.sender = user
34 - if !@message.save
35 - render :action => 'list' and return
34 + if @message.body == '' or !@message.save
35 + flash[:notice] = 'An error occurred'
36 36 else
37 37 flash[:notice] = 'New message posted'
38 + end
38 39 redirect_to :action => 'list'
39 40 end
40 - end
41 41
42 42 def reply
43 43 user = User.find(session[:user_id])
44 44 @message = Message.new(params[:r_message])
45 45 @message.sender = user
46 - if !@message.save
47 - render :action => 'show' and return
46 + if @message.body == '' or !@message.save
47 + flash[:notice] = 'An error occurred'
48 + redirect_to :action => 'show', :id => @message.replying_message_id
48 49 else
49 50 flash[:notice] = 'Message replied'
50 51 rep_msg = @message.replying_message
51 52 rep_msg.replied = true
52 53 rep_msg.save
53 54 redirect_to :action => 'console'
54 55 end
55 56 end
56 57
57 58 def hide
58 59 message = Message.find(params[:id])
59 60 message.replied = true
60 61 message.save
61 - flash[:notice] = 'Message hided (just marked replied)'
62 + flash[:notice] = 'Message hidden (just marked replied)'
62 63 redirect_to :action => 'console'
63 64 end
64 65
65 66 protected
66 67 def build_replying_message_hierarchy(user)
67 68 @all_messages = {}
68 69
69 70
70 71 # manually build replies hierarchy (to improve efficiency)
71 72 [@messages, @replied_messages].each do |collection|
72 73 collection.each do |m|
73 74 @all_messages[m.id] = {:msg => m, :replies => []}
74 75 end
75 76 end
76 77
77 78 @all_messages.each do |m|
78 79 rep_id = m.replying_message_id
79 80 if @all_messages[rep_id]!=nil
80 81 @all_messages[rep_id][:replies] << m
81 82 end
82 83 end
83 84 end
84 85
85 86 end
@@ -1,118 +1,118
1 1 class TestController < ApplicationController
2 2
3 3 before_filter :authenticate, :check_viewability
4 4
5 5 #
6 6 # COMMENT OUT: filter in each action instead
7 7 #
8 8 # before_filter :verify_time_limit, :only => [:submit]
9 9
10 10 verify :method => :post, :only => [:submit],
11 11 :redirect_to => { :action => :index }
12 12
13 13 def index
14 14 prepare_index_information
15 15 end
16 16
17 17 def submit
18 18 @user = User.find(session[:user_id])
19 19
20 20 @submitted_test_request = TestRequest.new_from_form_params(@user,params[:test_request])
21 21
22 22 if ! @submitted_test_request.errors.empty?
23 23 prepare_index_information
24 24 render :action => 'index' and return
25 25 end
26 26
27 27 if GraderConfiguration.time_limit_mode?
28 28 if @user.contest_finished?
29 - @submitted_test_request.errors.add_to_base('Contest is over.')
29 + @submitted_test_request.errors.add(:base,'Contest is over.')
30 30 prepare_index_information
31 31 render :action => 'index' and return
32 32 end
33 33
34 34 if !GraderConfiguration.allow_test_request(@user)
35 35 prepare_index_information
36 36 flash[:notice] = 'Test request is not allowed during the last 30 minutes'
37 37 redirect_to :action => 'index' and return
38 38 end
39 39 end
40 40
41 41 if @submitted_test_request.save
42 42 redirect_to :action => 'index'
43 43 else
44 44 prepare_index_information
45 45 render :action => 'index'
46 46 end
47 47 end
48 48
49 49 def read
50 50 user = User.find(session[:user_id])
51 51 begin
52 52 test_request = TestRequest.find(params[:id])
53 53 rescue
54 54 test_request = nil
55 55 end
56 56 if test_request==nil or test_request.user_id != user.id
57 57 flash[:notice] = 'Invalid output'
58 58 redirect_to :action => 'index'
59 59 return
60 60 end
61 61 if test_request.output_file_name!=nil
62 62 data = File.open(test_request.output_file_name).read(2048)
63 63 if data==nil
64 64 data=""
65 65 end
66 66 send_data(data,
67 67 {:filename => 'output.txt',
68 68 :type => 'text/plain'})
69 69 return
70 70 end
71 71 redirect_to :action => 'index'
72 72 end
73 73
74 74 def result
75 75 @user = User.find(session[:user_id])
76 76 begin
77 77 @test_request = TestRequest.find(params[:id])
78 78 rescue
79 79 @test_request = nil
80 80 end
81 81 if @test_request==nil or @test_request.user_id != @user.id
82 82 flash[:notice] = 'Invalid request'
83 83 redirect_to :action => 'index'
84 84 return
85 85 end
86 86 end
87 87
88 88 protected
89 89
90 90 def prepare_index_information
91 91 @user = User.find(session[:user_id])
92 92 @submissions = Submission.find_last_for_all_available_problems(@user.id)
93 93 all_problems = @submissions.collect { |submission| submission.problem }
94 94 @problems = []
95 95 all_problems.each do |problem|
96 96 if problem.test_allowed
97 97 @problems << problem
98 98 end
99 99 end
100 100 @test_requests = []
101 101 @user.test_requests.each do |ts|
102 102 if ts.problem and ts.problem.available
103 103 @test_requests << ts
104 104 end
105 105 end
106 106 end
107 107
108 108 def check_viewability
109 109 user = User.find(session[:user_id])
110 110 if !GraderConfiguration.show_tasks_to?(user)
111 111 redirect_to :controller => 'main', :action => 'list'
112 112 end
113 113 if (!GraderConfiguration.show_submitbox_to?(user)) and (action_name=='submit')
114 114 redirect_to :controller => 'test', :action => 'index'
115 115 end
116 116 end
117 117
118 118 end
@@ -1,256 +1,248
1 1 require 'csv'
2 2
3 3 class UserAdminController < ApplicationController
4 4
5 -
6 5 include MailHelperMethods
7 6
8 7 before_filter :admin_authorization
9 8
10 9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 10 verify :method => :post, :only => [ :destroy,
12 11 :create, :create_from_list,
13 12 :update,
14 13 :manage_contest,
15 14 :bulk_mail
16 15 ],
17 16 :redirect_to => { :action => :list }
18 17
19 18 def index
20 19 list
21 20 render :action => 'list'
22 21 end
23 22
24 23 def list
25 24 @user_count = User.count
26 25 if params[:page] == 'all'
27 26 @users = User.all
28 27 @paginated = false
29 28 else
30 29 @users = User.paginate :page => params[:page]
31 30 @paginated = true
32 31 end
33 32 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
34 33 @contests = Contest.enabled
35 34 end
36 35
37 36 def active
38 37 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
39 38 @users = []
40 39 sessions.each do |session|
41 40 if session.data[:user_id]
42 41 @users << User.find(session.data[:user_id])
43 42 end
44 43 end
45 44 end
46 45
47 46 def show
48 47 @user = User.find(params[:id])
49 48 end
50 49
51 50 def new
52 51 @user = User.new
53 52 end
54 53
55 54 def create
56 55 @user = User.new(params[:user])
57 56 @user.activated = true
58 57 if @user.save
59 58 flash[:notice] = 'User was successfully created.'
60 59 redirect_to :action => 'list'
61 60 else
62 61 render :action => 'new'
63 62 end
64 63 end
65 64
66 65 def create_from_list
67 66 lines = params[:user_list]
68 67
69 68 note = []
70 69
71 70 lines.split("\n").each do |line|
72 71 items = line.chomp.split(',')
73 72 if items.length>=2
74 73 login = items[0]
75 74 full_name = items[1]
76 75
77 76 added_random_password = false
78 77 if items.length>=3
79 78 password = items[2].chomp(" ")
80 79 user_alias = (items.length>=4) ? items[3] : login
81 80 else
82 81 password = random_password
83 82 user_alias = (items.length>=4) ? items[3] : login
84 83 added_random_password = true
85 84 end
86 85
87 86 user = User.find_by_login(login)
88 87 if (user)
89 88 user.full_name = full_name
90 89 user.password = password
91 90 else
92 91 user = User.new({:login => login,
93 92 :full_name => full_name,
94 93 :password => password,
95 94 :password_confirmation => password,
96 95 :alias => user_alias})
97 96 end
98 97 user.activated = true
99 98 user.save
100 99
101 100 if added_random_password
102 101 note << "'#{login}' (+)"
103 102 else
104 103 note << login
105 104 end
106 105 end
107 106 end
108 107 flash[:notice] = 'User(s) ' + note.join(', ') +
109 108 ' were successfully created. ' +
110 109 '( (+) - created with random passwords.)'
111 110 redirect_to :action => 'list'
112 111 end
113 112
114 113 def edit
115 114 @user = User.find(params[:id])
116 115 end
117 116
118 117 def update
119 118 @user = User.find(params[:id])
120 119 if @user.update_attributes(params[:user])
121 120 flash[:notice] = 'User was successfully updated.'
122 121 redirect_to :action => 'show', :id => @user
123 122 else
124 123 render :action => 'edit'
125 124 end
126 125 end
127 126
128 127 def destroy
129 128 User.find(params[:id]).destroy
130 129 redirect_to :action => 'list'
131 130 end
132 131
133 132 def user_stat
134 133 if params[:commit] == 'download csv'
135 134 @problems = Problem.all
136 135 else
137 136 @problems = Problem.find_available_problems
138 137 end
139 138 @users = User.find(:all, :include => [:contests, :contest_stat])
140 139 @scorearray = Array.new
141 140 @users.each do |u|
142 141 ustat = Array.new
143 142 ustat[0] = u
144 143 @problems.each do |p|
145 144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
146 145 if (sub!=nil) and (sub.points!=nil)
147 146 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
148 147 else
149 148 ustat << [0,false]
150 149 end
151 150 end
152 151 @scorearray << ustat
153 152 end
154 -
155 - if params[:commit] == 'download csv' then
156 - csv = gen_csv_from_scorearray(@scorearray,@problems)
157 - send_data csv, filename: 'last_score.csv'
158 - else
159 - render template: 'user_admin/user_stat'
160 - end
161 153 end
162 154
163 155 def user_stat_max
164 156 if params[:commit] == 'download csv'
165 157 @problems = Problem.all
166 158 else
167 159 @problems = Problem.find_available_problems
168 160 end
169 161 @users = User.find(:all, :include => [:contests, :contest_stat])
170 162 @scorearray = Array.new
171 163 #set up range from param
172 164 since_id = params.fetch(:since_id, 0).to_i
173 165 until_id = params.fetch(:until_id, 0).to_i
174 166 @users.each do |u|
175 167 ustat = Array.new
176 168 ustat[0] = u
177 169 @problems.each do |p|
178 170 max_points = 0
179 171 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
180 172 max_points = sub.points if sub and sub.points and (sub.points > max_points)
181 173 end
182 174 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
183 175 end
184 176 @scorearray << ustat
185 177 end
186 178
187 179 if params[:commit] == 'download csv' then
188 180 csv = gen_csv_from_scorearray(@scorearray,@problems)
189 181 send_data csv, filename: 'max_score.csv'
190 182 else
191 183 render template: 'user_admin/user_stat'
192 184 end
193 185 end
194 186
195 187 def import
196 188 if params[:file]==''
197 189 flash[:notice] = 'Error importing no file'
198 190 redirect_to :action => 'list' and return
199 191 end
200 192 import_from_file(params[:file])
201 193 end
202 194
203 195 def random_all_passwords
204 196 users = User.find(:all)
205 197 @prefix = params[:prefix] || ''
206 198 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
207 199 @changed = false
208 200 if request.request_method == 'POST'
209 201 @non_admin_users.each do |user|
210 202 password = random_password
211 203 user.password = password
212 204 user.password_confirmation = password
213 205 user.save
214 206 end
215 207 @changed = true
216 208 end
217 209 end
218 210
219 211 # contest management
220 212
221 213 def contests
222 214 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
223 215 @contests = Contest.enabled
224 216 end
225 217
226 218 def assign_from_list
227 219 contest_id = params[:users_contest_id]
228 220 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
229 221 contest = Contest.find(params[:new_contest][:id])
230 222 if !contest
231 223 flash[:notice] = 'Error: no contest'
232 224 redirect_to :action => 'contests', :id =>contest_id
233 225 end
234 226
235 227 note = []
236 228 users.each do |u|
237 229 u.contests = [contest]
238 230 note << u.login
239 231 end
240 232 flash[:notice] = 'User(s) ' + note.join(', ') +
241 233 " were successfully reassigned to #{contest.title}."
242 234 redirect_to :action => 'contests', :id =>contest.id
243 235 end
244 236
245 237 def add_to_contest
246 238 user = User.find(params[:id])
247 239 contest = Contest.find(params[:contest_id])
248 240 if user and contest
249 241 user.contests << contest
250 242 end
251 243 redirect_to :action => 'list'
252 244 end
253 245
254 246 def remove_from_contest
255 247 user = User.find(params[:id])
256 248 contest = Contest.find(params[:contest_id])
@@ -1,195 +1,195
1 1 require 'net/smtp'
2 2
3 3 class UsersController < ApplicationController
4 4
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 17 before_filter :authenticate, :profile_authorization, only: [:profile]
18 18
19 19 verify :method => :post, :only => [:chg_passwd],
20 20 :redirect_to => { :action => :index }
21 21
22 22 #in_place_edit_for :user, :alias_for_editing
23 23 #in_place_edit_for :user, :email_for_editing
24 24
25 25 def index
26 26 if !GraderConfiguration['system.user_setting_enabled']
27 27 redirect_to :controller => 'main', :action => 'list'
28 28 else
29 29 @user = User.find(session[:user_id])
30 30 end
31 31 end
32 32
33 33 def chg_passwd
34 34 user = User.find(session[:user_id])
35 35 user.password = params[:passwd]
36 36 user.password_confirmation = params[:passwd_verify]
37 37 if user.save
38 38 flash[:notice] = 'password changed'
39 39 else
40 40 flash[:notice] = 'Error: password changing failed'
41 41 end
42 42 redirect_to :action => 'index'
43 43 end
44 44
45 45 def new
46 46 @user = User.new
47 47 render :action => 'new', :layout => 'empty'
48 48 end
49 49
50 50 def register
51 51 if(params[:cancel])
52 52 redirect_to :controller => 'main', :action => 'login'
53 53 return
54 54 end
55 55 @user = User.new(params[:user])
56 56 @user.password_confirmation = @user.password = User.random_password
57 57 @user.activated = false
58 58 if (@user.valid?) and (@user.save)
59 59 if send_confirmation_email(@user)
60 60 render :action => 'new_splash', :layout => 'empty'
61 61 else
62 62 @admin_email = GraderConfiguration['system.admin_email']
63 63 render :action => 'email_error', :layout => 'empty'
64 64 end
65 65 else
66 - @user.errors.add_to_base("Email cannot be blank") if @user.email==''
66 + @user.errors.add(:base,"Email cannot be blank") if @user.email==''
67 67 render :action => 'new', :layout => 'empty'
68 68 end
69 69 end
70 70
71 71 def confirm
72 72 login = params[:login]
73 73 key = params[:activation]
74 74 @user = User.find_by_login(login)
75 75 if (@user) and (@user.verify_activation_key(key))
76 76 if @user.valid? # check uniquenss of email
77 77 @user.activated = true
78 78 @user.save
79 79 @result = :successful
80 80 else
81 81 @result = :email_used
82 82 end
83 83 else
84 84 @result = :failed
85 85 end
86 86 render :action => 'confirm', :layout => 'empty'
87 87 end
88 88
89 89 def forget
90 90 render :action => 'forget', :layout => 'empty'
91 91 end
92 92
93 93 def retrieve_password
94 94 email = params[:email]
95 95 user = User.find_by_email(email)
96 96 if user
97 97 last_updated_time = user.updated_at || user.created_at || (Time.now.gmtime - 1.hour)
98 98 if last_updated_time > Time.now.gmtime - 5.minutes
99 99 flash[:notice] = 'The account has recently created or new password has recently been requested. Please wait for 5 minutes'
100 100 else
101 101 user.password = user.password_confirmation = User.random_password
102 102 user.save
103 103 send_new_password_email(user)
104 104 flash[:notice] = 'New password has been mailed to you.'
105 105 end
106 106 else
107 107 flash[:notice] = I18n.t 'registration.password_retrieval.no_email'
108 108 end
109 109 redirect_to :action => 'forget'
110 110 end
111 111
112 112 def profile
113 113 @user = User.find(params[:id])
114 114 @submission = Submission.includes(:problem).where(user_id: params[:id])
115 115
116 116 range = 120
117 117 @histogram = { data: Array.new(range,0), summary: {} }
118 118 @summary = {count: 0, solve: 0, attempt: 0}
119 119 problem = Hash.new(0)
120 120
121 121 @submission.find_each do |sub|
122 122 #histogram
123 123 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
124 124 @histogram[:data][d.to_i] += 1 if d < range
125 125
126 126 @summary[:count] += 1
127 127 next unless sub.problem
128 128 problem[sub.problem] = [problem[sub.problem], (sub.points >= sub.problem.full_score) ? 1 : 0].max
129 129 end
130 130
131 131 @histogram[:summary][:max] = [@histogram[:data].max,1].max
132 132 @summary[:attempt] = problem.count
133 133 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
134 134 end
135 135
136 136 protected
137 137
138 138 def verify_online_registration
139 139 if !GraderConfiguration['system.online_registration']
140 140 redirect_to :controller => 'main', :action => 'login'
141 141 end
142 142 end
143 143
144 144 def send_confirmation_email(user)
145 145 contest_name = GraderConfiguration['contest.name']
146 146 activation_url = url_for(:action => 'confirm',
147 147 :login => user.login,
148 148 :activation => user.activation_key)
149 149 home_url = url_for(:controller => 'main', :action => 'index')
150 150 mail_subject = "[#{contest_name}] Confirmation"
151 151 mail_body = t('registration.email_body', {
152 152 :full_name => user.full_name,
153 153 :contest_name => contest_name,
154 154 :login => user.login,
155 155 :password => user.password,
156 156 :activation_url => activation_url,
157 - :admin_email => admin_email
157 + :admin_email => GraderConfiguration['system.admin_email']
158 158 })
159 159
160 160 logger.info mail_body
161 161
162 162 send_mail(user.email, mail_subject, mail_body)
163 163 end
164 164
165 165 def send_new_password_email(user)
166 166 contest_name = GraderConfiguration['contest.name']
167 167 mail_subject = "[#{contest_name}] Password recovery"
168 168 mail_body = t('registration.password_retrieval.email_body', {
169 169 :full_name => user.full_name,
170 170 :contest_name => contest_name,
171 171 :login => user.login,
172 172 :password => user.password,
173 - :admin_email => admin_email
173 + :admin_email => GraderConfiguration['system.admin_email']
174 174 })
175 175
176 176 logger.info mail_body
177 177
178 178 send_mail(user.email, mail_subject, mail_body)
179 179 end
180 180
181 181 # allow viewing of regular user profile only when options allow so
182 182 # only admins can view admins profile
183 183 def profile_authorization
184 184 #if view admins' profile, allow only admin
185 185 return false unless(params[:id])
186 186 user = User.find(params[:id])
187 187 return false unless user
188 188 return admin_authorization if user.admin?
189 189 return true if GraderConfiguration["right.user_view_submission"]
190 190
191 191 #finally, we allow only admin
192 192 admin_authorization
193 193 end
194 194
195 195 end
@@ -25,114 +25,114
25 25 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
26 26 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
27 27
28 28 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
29 29 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
30 30 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
31 31 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
32 32 end
33 33
34 34 if GraderConfiguration['right.user_hall_of_fame']
35 35 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
36 36 end
37 37 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
38 38
39 39 if GraderConfiguration['system.user_setting_enabled']
40 40 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
41 41 end
42 42 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
43 43
44 44 menu_items.html_safe
45 45 end
46 46
47 47 def append_to(option,label, controller, action)
48 48 option << ' ' if option!=''
49 49 option << link_to_unless_current(label,
50 50 :controller => controller,
51 51 :action => action)
52 52 end
53 53
54 54 def format_short_time(time)
55 55 now = Time.now.gmtime
56 56 st = ''
57 57 if (time.yday != now.yday) or
58 58 (time.year != now.year)
59 59 st = time.strftime("%x ")
60 60 end
61 61 st + time.strftime("%X")
62 62 end
63 63
64 64 def format_short_duration(duration)
65 65 return '' if duration==nil
66 66 d = duration.to_f
67 67 return Time.at(d).gmtime.strftime("%X")
68 68 end
69 69
70 70 def read_textfile(fname,max_size=2048)
71 71 begin
72 72 File.open(fname).read(max_size)
73 73 rescue
74 74 nil
75 75 end
76 76 end
77 77
78 78 def user_title_bar(user)
79 79 header = ''
80 80 time_left = ''
81 81
82 82 #
83 83 # if the contest is over
84 84 if GraderConfiguration.time_limit_mode?
85 85 if user.contest_finished?
86 86 header = <<CONTEST_OVER
87 87 <tr><td colspan="2" align="center">
88 88 <span class="contest-over-msg">THE CONTEST IS OVER</span>
89 89 </td></tr>
90 90 CONTEST_OVER
91 91 end
92 92 if !user.contest_started?
93 93 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
94 94 else
95 95 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
96 96 " #{format_short_duration(user.contest_time_left)}"
97 97 end
98 98 end
99 99
100 100 #
101 101 # if the contest is in the anaysis mode
102 102 if GraderConfiguration.analysis_mode?
103 103 header = <<ANALYSISMODE
104 104 <tr><td colspan="2" align="center">
105 105 <span class="contest-over-msg">ANALYSIS MODE</span>
106 106 </td></tr>
107 107 ANALYSISMODE
108 108 end
109 109
110 110 contest_name = GraderConfiguration['contest.name']
111 111
112 112 #
113 113 # build real title bar
114 114 result = <<TITLEBAR
115 115 <div class="title">
116 116 <table>
117 117 #{header}
118 118 <tr>
119 119 <td class="left-col">
120 120 #{user.full_name}<br/>
121 - #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
121 + #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
122 122 #{time_left}
123 123 <br/>
124 124 </td>
125 125 <td class="right-col">#{contest_name}</td>
126 126 </tr>
127 127 </table>
128 128 </div>
129 129 TITLEBAR
130 130 result.html_safe
131 131 end
132 132
133 133 def markdown(text)
134 134 markdown = RDiscount.new(text)
135 135 markdown.to_html.html_safe
136 136 end
137 137
138 138 end
@@ -1,128 +1,128
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_and_belongs_to_many :contests, :uniq => true
5 5 has_many :test_pairs, :dependent => :delete_all
6 6
7 7 validates_presence_of :name
8 8 validates_format_of :name, :with => /^\w+$/
9 9 validates_presence_of :full_name
10 10
11 11 scope :available, :conditions => {:available => true}
12 12
13 13 DEFAULT_TIME_LIMIT = 1
14 14 DEFAULT_MEMORY_LIMIT = 32
15 15
16 16 def self.find_available_problems
17 17 Problem.available.all(:order => "date_added DESC, name ASC")
18 18 end
19 19
20 20 def self.create_from_import_form_params(params, old_problem=nil)
21 21 org_problem = old_problem || Problem.new
22 22 import_params, problem = Problem.extract_params_and_check(params,
23 23 org_problem)
24 24
25 25 if !problem.errors.empty?
26 26 return problem, 'Error importing'
27 27 end
28 28
29 29 problem.full_score = 100
30 30 problem.date_added = Time.new
31 31 problem.test_allowed = true
32 32 problem.output_only = false
33 33 problem.available = false
34 34
35 35 if not problem.save
36 36 return problem, 'Error importing'
37 37 end
38 38
39 39 import_to_db = params.has_key? :import_to_db
40 40
41 41 importer = TestdataImporter.new(problem)
42 42
43 43 if not importer.import_from_file(import_params[:file],
44 44 import_params[:time_limit],
45 45 import_params[:memory_limit],
46 46 import_params[:checker_name],
47 47 import_to_db)
48 - problem.errors.add_to_base('Import error.')
48 + problem.errors.add(:base,'Import error.')
49 49 end
50 50
51 51 return problem, importer.log_msg
52 52 end
53 53
54 54 def self.download_file_basedir
55 55 return "#{Rails.root}/data/tasks"
56 56 end
57 57
58 58 def get_submission_stat
59 59 result = Hash.new
60 60 #total number of submission
61 61 result[:total_sub] = Submission.where(problem_id: self.id).count
62 62 result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
63 63 end
64 64
65 65 protected
66 66
67 67 def self.to_i_or_default(st, default)
68 68 if st!=''
69 69 result = st.to_i
70 70 end
71 71 result ||= default
72 72 end
73 73
74 74 def self.to_f_or_default(st, default)
75 75 if st!=''
76 76 result = st.to_f
77 77 end
78 78 result ||= default
79 79 end
80 80
81 81 def self.extract_params_and_check(params, problem)
82 82 time_limit = Problem.to_f_or_default(params[:time_limit],
83 83 DEFAULT_TIME_LIMIT)
84 84 memory_limit = Problem.to_i_or_default(params[:memory_limit],
85 85 DEFAULT_MEMORY_LIMIT)
86 86
87 87 if time_limit<=0 or time_limit >60
88 - problem.errors.add_to_base('Time limit out of range.')
88 + problem.errors.add(:base,'Time limit out of range.')
89 89 end
90 90
91 91 if memory_limit==0 and params[:memory_limit]!='0'
92 - problem.errors.add_to_base('Memory limit format errors.')
92 + problem.errors.add(:base,'Memory limit format errors.')
93 93 elsif memory_limit<=0 or memory_limit >512
94 - problem.errors.add_to_base('Memory limit out of range.')
94 + problem.errors.add(:base,'Memory limit out of range.')
95 95 end
96 96
97 97 if params[:file]==nil or params[:file]==''
98 - problem.errors.add_to_base('No testdata file.')
98 + problem.errors.add(:base,'No testdata file.')
99 99 end
100 100
101 101 checker_name = 'text'
102 102 if ['text','float'].include? params[:checker]
103 103 checker_name = params[:checker]
104 104 end
105 105
106 106 file = params[:file]
107 107
108 108 if !problem.errors.empty?
109 109 return nil, problem
110 110 end
111 111
112 112 problem.name = params[:name]
113 113 if params[:full_name]!=''
114 114 problem.full_name = params[:full_name]
115 115 else
116 116 problem.full_name = params[:name]
117 117 end
118 118
119 119 return [{
120 120 :time_limit => time_limit,
121 121 :memory_limit => memory_limit,
122 122 :file => file,
123 123 :checker_name => checker_name
124 124 },
125 125 problem]
126 126 end
127 127
128 128 end
@@ -1,157 +1,157
1 1 #
2 2 # A TestRequest is a composition of submission with user's testdata.
3 3 #
4 4 # Note about TestRequest#problem: Usually, A TestRequest has to be
5 5 # associated with a problem, so that execution environment can be
6 6 # determined. However, to be more flexible, we have to ensure that
7 7 # it works as well with problem=nil. In this case, we shall provide
8 8 # a "default" execution environment for it. This can be done
9 9 # seamlessly by using TestRequest#problem_name or
10 10 # TestRequest#name_of(problem) when retrieving the name of the
11 11 # problem: #name_of would return problem.name when problem!=nil and
12 12 # it would return "default" when problem=nil, #problem_name just
13 13 # call #name_of.
14 14 #
15 15
16 16 require 'fileutils'
17 17
18 18 class TestRequest < Task
19 19
20 20 set_table_name "test_requests"
21 21
22 22 belongs_to :user
23 23 belongs_to :problem
24 24 belongs_to :submission
25 25
26 26 validates_presence_of :submission
27 27 validate :must_have_valid_problem
28 28
29 29 def problem_name
30 30 TestRequest.name_of(self.problem)
31 31 end
32 32
33 33 def language
34 34 self.submission.language
35 35 end
36 36
37 37 def self.get_inqueue_and_change_status(status)
38 38 # since there will be only one grader grading TestRequest
39 39 # we do not need locking (hopefully)
40 40
41 41 test_request = TestRequest.find(:first,
42 42 :order => "created_at",
43 43 :conditions => {:status=> Task::STATUS_INQUEUE})
44 44 if test_request!=nil
45 45 test_request.status = status
46 46 test_request.save!
47 47 end
48 48
49 49 test_request
50 50 end
51 51
52 52 # interfacing with form
53 53 def self.new_from_form_params(user,params)
54 54 test_request = TestRequest.new
55 55 test_request.user = user
56 56 begin
57 57 problem = Problem.find(params[:problem_id])
58 58 rescue ActiveRecord::RecordNotFound
59 59 problem = nil
60 60 end
61 61 test_request.problem = problem
62 62 if problem!=nil
63 63 test_request.submission =
64 64 Submission.find_by_user_problem_number(user.id,
65 65 problem.id,
66 66 params[:submission_number])
67 67 else
68 68 test_request.submission = nil
69 69 end
70 70
71 71 # checks if the user submits any input file
72 72 if params[:input_file]==nil or params[:input_file]==""
73 - test_request.errors.add_to_base("No input submitted.")
73 + test_request.errors.add(:base,"No input submitted.")
74 74 test_request.input_file_name = nil
75 75 else
76 76 test_request.input_file_name = save_input_file(params[:input_file], user, problem)
77 77 if test_request.input_file_name == nil
78 - test_request.errors.add_to_base("No input submitted.")
78 + test_request.errors.adds(:base,"No input submitted.")
79 79 end
80 80 if params[:additional_file]!=nil and params[:additional_file]!=""
81 81 save_additional_file(params[:additional_file],
82 82 "#{test_request.input_file_name}.files")
83 83 end
84 84 end
85 85 test_request.submitted_at = Time.new.gmtime
86 86 test_request.status_inqueue
87 87 test_request
88 88 end
89 89
90 90 protected
91 91
92 92 def self.name_of(problem)
93 93 if problem!=nil
94 94 problem.name
95 95 else
96 96 "default"
97 97 end
98 98 end
99 99
100 100 def self.random_input_file_name(user,problem)
101 101 problem_name = TestRequest.name_of(problem)
102 102 begin
103 103 tmpname = TEST_REQUEST_INPUT_FILE_DIR + "/#{user.login}/#{problem_name}/#{rand(10000)}"
104 104 end while File.exists?(tmpname)
105 105 tmpname
106 106 end
107 107
108 108 def self.save_input_file(tempfile, user, problem)
109 109 new_file_name = random_input_file_name(user,problem)
110 110 dirname = File.dirname(new_file_name)
111 111 FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
112 112
113 113 # when the user did not submit any file
114 114 return nil if tempfile==""
115 115
116 116 if tempfile.instance_of?(Tempfile)
117 117 tempfile.close
118 118 FileUtils.move(tempfile.path,new_file_name)
119 119 else
120 120 File.open(new_file_name, "wb") do |f|
121 121 f.write(tempfile.read)
122 122 end
123 123 end
124 124 new_file_name
125 125 end
126 126
127 127 def self.save_additional_file(tempfile,dir)
128 128 new_file_name = "#{dir}/#{tempfile.original_filename}"
129 129 dirname = File.dirname(new_file_name)
130 130 FileUtils.mkdir_p(File.dirname(new_file_name)) if !File.exists?(dirname)
131 131
132 132 # when the user did not submit any file
133 133 return nil if tempfile==""
134 134
135 135 if tempfile.instance_of?(Tempfile)
136 136 tempfile.close
137 137 FileUtils.move(tempfile.path,new_file_name)
138 138 else
139 139 File.open(new_file_name, "wb") do |f|
140 140 f.write(tempfile.read)
141 141 end
142 142 end
143 143 new_file_name
144 144 end
145 145
146 146 #
147 147 # validations
148 148 #
149 149 def must_have_valid_problem
150 150 if problem==nil
151 151 errors.add('problem',"must be specified.")
152 152 elsif (!problem.available) and (self.new_record?)
153 153 errors.add('problem',"must be valid.")
154 154 end
155 155 end
156 156
157 157 end
@@ -1,223 +1,176
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 9 has_and_belongs_to_many :roles
10 10
11 11 has_many :test_requests, :order => "submitted_at DESC"
12 12
13 13 has_many :messages,
14 14 :class_name => "Message",
15 15 :foreign_key => "sender_id",
16 16 :order => 'created_at DESC'
17 17
18 18 has_many :replied_messages,
19 19 :class_name => "Message",
20 20 :foreign_key => "receiver_id",
21 21 :order => 'created_at DESC'
22 22
23 23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24 24
25 25 belongs_to :site
26 26 belongs_to :country
27 27
28 28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
29 29
30 30 scope :activated_users, :conditions => {:activated => true}
31 31
32 32 validates_presence_of :login
33 33 validates_uniqueness_of :login
34 34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
35 35 validates_length_of :login, :within => 3..30
36 36
37 37 validates_presence_of :full_name
38 38 validates_length_of :full_name, :minimum => 1
39 39
40 40 validates_presence_of :password, :if => :password_required?
41 41 validates_length_of :password, :within => 4..20, :if => :password_required?
42 42 validates_confirmation_of :password, :if => :password_required?
43 43
44 44 validates_format_of :email,
45 45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 46 :if => :email_validation?
47 47 validate :uniqueness_of_email_from_activated_users,
48 48 :if => :email_validation?
49 49 validate :enough_time_interval_between_same_email_registrations,
50 50 :if => :email_validation?
51 51
52 52 # these are for ytopc
53 53 # disable for now
54 54 #validates_presence_of :province
55 55
56 56 attr_accessor :password
57 57
58 58 before_save :encrypt_new_password
59 59 before_save :assign_default_site
60 60 before_save :assign_default_contest
61 61
62 62 # this is for will_paginate
63 63 cattr_reader :per_page
64 64 @@per_page = 50
65 65
66 66 def self.authenticate(login, password)
67 67 user = find_by_login(login)
68 68 if user
69 69 return user if user.authenticated?(password)
70 - if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 - user.password = password
72 - user.save
73 - return user
74 - end
75 70 end
76 71 end
77 72
78 73 def authenticated?(password)
79 74 if self.activated
80 75 hashed_password == User.encrypt(password,self.salt)
81 76 else
82 77 false
83 78 end
84 79 end
85 80
86 - def authenticated_by_pop3?(password)
87 - Net::POP3.enable_ssl
88 - pop = Net::POP3.new('pops.it.chula.ac.th')
89 - authen = true
90 - begin
91 - pop.start(login, password)
92 - pop.finish
93 - return true
94 - rescue
95 - return false
96 - end
97 - end
98 -
99 - def authenticated_by_cucas?(password)
100 - url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
101 - appid = '41508763e340d5858c00f8c1a0f5a2bb'
102 - appsecret ='d9cbb5863091dbe186fded85722a1e31'
103 - post_args = {
104 - 'appid' => appid,
105 - 'appsecret' => appsecret,
106 - 'username' => login,
107 - 'password' => password
108 - }
109 -
110 - #simple call
111 - begin
112 - http = Net::HTTP.new('www.cas.chula.ac.th', 443)
113 - http.use_ssl = true
114 - result = [ ]
115 - http.start do |http|
116 - req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
117 - param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
118 - resp = http.request(req,param)
119 - result = JSON.parse resp.body
120 - end
121 - return true if result["type"] == "beanStudent"
122 - rescue
123 - return false
124 - end
125 - return false
126 - end
127 -
128 81 def admin?
129 82 self.roles.detect {|r| r.name == 'admin' }
130 83 end
131 84
132 85 def email_for_editing
133 86 if self.email==nil
134 87 "(unknown)"
135 88 elsif self.email==''
136 89 "(blank)"
137 90 else
138 91 self.email
139 92 end
140 93 end
141 94
142 95 def email_for_editing=(e)
143 96 self.email=e
144 97 end
145 98
146 99 def alias_for_editing
147 100 if self.alias==nil
148 101 "(unknown)"
149 102 elsif self.alias==''
150 103 "(blank)"
151 104 else
152 105 self.alias
153 106 end
154 107 end
155 108
156 109 def alias_for_editing=(e)
157 110 self.alias=e
158 111 end
159 112
160 113 def activation_key
161 114 if self.hashed_password==nil
162 115 encrypt_new_password
163 116 end
164 117 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
165 118 end
166 119
167 120 def verify_activation_key(key)
168 121 key == activation_key
169 122 end
170 123
171 124 def self.random_password(length=5)
172 125 chars = 'abcdefghjkmnopqrstuvwxyz'
173 126 password = ''
174 127 length.times { password << chars[rand(chars.length - 1)] }
175 128 password
176 129 end
177 130
178 131 def self.find_non_admin_with_prefix(prefix='')
179 132 users = User.find(:all)
180 133 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
181 134 end
182 135
183 136 # Contest information
184 137
185 138 def self.find_users_with_no_contest()
186 139 users = User.find(:all)
187 140 return users.find_all { |u| u.contests.length == 0 }
188 141 end
189 142
190 143
191 144 def contest_time_left
192 145 if GraderConfiguration.contest_mode?
193 146 return nil if site==nil
194 147 return site.time_left
195 148 elsif GraderConfiguration.indv_contest_mode?
196 149 time_limit = GraderConfiguration.contest_time_limit
197 150 if time_limit == nil
198 151 return nil
199 152 end
200 153 if contest_stat==nil or contest_stat.started_at==nil
201 154 return (Time.now.gmtime + time_limit) - Time.now.gmtime
202 155 else
203 156 finish_time = contest_stat.started_at + time_limit
204 157 current_time = Time.now.gmtime
205 158 if current_time > finish_time
206 159 return 0
207 160 else
208 161 return finish_time - current_time
209 162 end
210 163 end
211 164 else
212 165 return nil
213 166 end
214 167 end
215 168
216 169 def contest_finished?
217 170 if GraderConfiguration.contest_mode?
218 171 return false if site==nil
219 172 return site.finished?
220 173 elsif GraderConfiguration.indv_contest_mode?
221 174 return false if self.contest_stat(true)==nil
222 175 return contest_time_left == 0
223 176 else
@@ -258,119 +211,119
258 211 return true
259 212 end
260 213 end
261 214 return false
262 215 end
263 216
264 217 def available_problems_group_by_contests
265 218 contest_problems = []
266 219 pin = {}
267 220 contests.enabled.each do |contest|
268 221 available_problems = contest.problems.available
269 222 contest_problems << {
270 223 :contest => contest,
271 224 :problems => available_problems
272 225 }
273 226 available_problems.each {|p| pin[p.id] = true}
274 227 end
275 228 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
276 229 contest_problems << {
277 230 :contest => nil,
278 231 :problems => other_avaiable_problems
279 232 }
280 233 return contest_problems
281 234 end
282 235
283 236 def available_problems
284 237 if not GraderConfiguration.multicontests?
285 238 return Problem.find_available_problems
286 239 else
287 240 contest_problems = []
288 241 pin = {}
289 242 contests.enabled.each do |contest|
290 243 contest.problems.available.each do |problem|
291 244 if not pin.has_key? problem.id
292 245 contest_problems << problem
293 246 end
294 247 pin[problem.id] = true
295 248 end
296 249 end
297 250 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
298 251 return contest_problems + other_avaiable_problems
299 252 end
300 253 end
301 254
302 255 def can_view_problem?(problem)
303 256 if not GraderConfiguration.multicontests?
304 257 return problem.available
305 258 else
306 259 return problem_in_user_contests? problem
307 260 end
308 261 end
309 262
310 263 protected
311 264 def encrypt_new_password
312 265 return if password.blank?
313 266 self.salt = (10+rand(90)).to_s
314 267 self.hashed_password = User.encrypt(self.password,self.salt)
315 268 end
316 269
317 270 def assign_default_site
318 271 # have to catch error when migrating (because self.site is not available).
319 272 begin
320 273 if self.site==nil
321 274 self.site = Site.find_by_name('default')
322 275 if self.site==nil
323 276 self.site = Site.find(1) # when 'default has be renamed'
324 277 end
325 278 end
326 279 rescue
327 280 end
328 281 end
329 282
330 283 def assign_default_contest
331 284 # have to catch error when migrating (because self.site is not available).
332 285 begin
333 286 if self.contests.length == 0
334 287 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
335 288 if default_contest
336 289 self.contests = [default_contest]
337 290 end
338 291 end
339 292 rescue
340 293 end
341 294 end
342 295
343 296 def password_required?
344 297 self.hashed_password.blank? || !self.password.blank?
345 298 end
346 299
347 300 def self.encrypt(string,salt)
348 301 Digest::SHA1.hexdigest(salt + string)
349 302 end
350 303
351 304 def uniqueness_of_email_from_activated_users
352 305 user = User.activated_users.find_by_email(self.email)
353 306 if user and (user.login != self.login)
354 - self.errors.add_to_base("Email has already been taken")
307 + self.errors.add(:base,"Email has already been taken")
355 308 end
356 309 end
357 310
358 311 def enough_time_interval_between_same_email_registrations
359 312 return if !self.new_record?
360 313 return if self.activated
361 314 open_user = User.find_by_email(self.email,
362 315 :order => 'created_at DESC')
363 316 if open_user and open_user.created_at and
364 317 (open_user.created_at > Time.now.gmtime - 5.minutes)
365 - self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
318 + self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
366 319 end
367 320 end
368 321
369 322 def email_validation?
370 323 begin
371 324 return VALIDATE_USER_EMAILS
372 325 rescue
373 326 return false
374 327 end
375 328 end
376 329 end
@@ -1,31 +1,34
1 1 %h1 Contest management
2 2
3 3 .infobox
4 4
5 5 - if @num_contests>1
6 6 %b Multiple contests:
7 7 = "There are #{@num_contests} contests running."
8 8 - else
9 9 %b Single contest:
10 10 =raw "[#{link_to 'Add/remove contests', :controller => 'contests', :action => 'index'}]"
11 11
12 12 .infobox
13 13 %b Web interface mode:
14 - - if (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
15 - standard mode
14 + - if GraderConfiguration.analysis_mode?
15 + Analysis Mode
16 + - elsif (not GraderConfiguration.contest_mode?) and (not GraderConfiguration.indv_contest_mode?)
17 + Standard Mode
16 18 - elsif GraderConfiguration.contest_mode?
17 - normal contest mode.
19 + Normal Contest Mode
18 20 - else
19 - individual contest mode.
21 + Individual Contest Mode
20 22
21 23 %br/
22 24 Change mode to:
23 - =raw "[#{link_to 'standard', :action => 'change_contest_mode', :id => 'standard'}]"
24 - =raw "[#{link_to 'contest', :action => 'change_contest_mode', :id => 'contest'}]"
25 - =raw "[#{link_to 'individual contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
25 + =raw "[#{link_to 'Standard', :action => 'change_contest_mode', :id => 'standard'}]"
26 + =raw "[#{link_to 'Contest', :action => 'change_contest_mode', :id => 'contest'}]"
27 + =raw "[#{link_to 'Individual Contest', :action => 'change_contest_mode', :id => 'indv-contest'}]"
28 + =raw "[#{link_to 'Analysis', :action => 'change_contest_mode', :id => 'analysis'}]"
26 29
27 30 - if GraderConfiguration.indv_contest_mode?
28 31 = render :partial => 'indv_contest_mode_index'
29 32
30 33 %br/
31 34
@@ -1,40 +1,40
1 1 %h1= "Test Request: #{@test_request.id}"
2 2
3 3 %p
4 4 User:
5 5 = "#{@test_request.user.login}"
6 6 %br/
7 7 Problem:
8 8 - if @test_request.problem!=nil
9 9 = "#{@test_request.problem.full_name}"
10 10 - else
11 11 = "(n/a)"
12 12 %br/
13 13 = "Submission: #{@test_request.submission.number}"
14 14 = link_to '[view submission]', :action => 'submission', :id => @test_request.submission.id
15 15 %br/
16 16 = "Test submitted at: #{format_short_time(@test_request.submitted_at)}"
17 17 %br/
18 18 = "Execution time: #{@test_request.running_time} s."
19 19 %br/
20 20 = "Memory usage: #{@test_request.memory_usage}kb"
21 21 %br/
22 22 %b= @test_request.exit_status
23 23 %br/
24 24
25 25 - if @test_request.compiler_message!=nil and @test_request.compiler_message!=''
26 26 %b Compiler Message
27 27 %div{:style => "border: 1px solid black; background: lightgrey"}
28 - = simple_format(truncate((@test_request.compiler_message or ''),200))
28 + = simple_format(truncate((@test_request.compiler_message or ''), :length => 200))
29 29
30 30 %b Input (first 2kb)
31 31 %div{:style => "border: 1px solid black; background: lightgrey"}
32 32 - if @test_request.input_file_name!=nil
33 33 = simple_format(read_textfile(@test_request.input_file_name,2048))
34 34
35 35 %b Output (first 2kb)
36 36 %div{:style => "border: 1px solid black; background: lightgrey"}
37 37 - if @test_request.output_file_name!=nil
38 38 = simple_format(read_textfile(@test_request.output_file_name,2048))
39 39 - else
40 40 (no output)
@@ -1,15 +1,15
1 1
2 - <% if compiler_message==nil or compiler_message=='' %>
2 + <% if compiler_message == nil or compiler_message.chomp == '' %>
3 3 No message
4 4 <% else %>
5 5 <div><div><a href="#" onClick="n = this.parentNode.parentNode.lastChild;
6 6 if(n.style.display == 'none') { n.style.display = 'block'; }
7 7 else {n.style.display ='none'; } return false;">
8 8 (click to see)</a>
9 9 </div>
10 10 <div style="display: none">
11 11 <div class="compilermsgbody" style="border: thin solid grey; margin: 2px">
12 12 <%=simple_format(compiler_message) %>
13 13 </div>
14 14 </div></div>
15 15 <% end %>
@@ -1,6 +1,6
1 1 %h2= "Compiler message for submission \##{@submission.number}, task: #{@submission.problem.name}"
2 2 %p
3 - - if @submission.compiler_message.chomp == ''
4 - no message
3 + - if @submission.compiler_message == nil or @submission.compiler_message.chomp == ''
4 + No message
5 5 - else
6 6 = simple_format(@submission.compiler_message)
@@ -1,16 +1,16
1 1 = user_title_bar(@user)
2 2
3 3 .announcementbox
4 4 %span{:class => 'title'}
5 5 =t 'main.confirm_contest_start.box_title'
6 6 .announcement
7 7 %center
8 8 =t 'main.confirm_contest_start.contest_list'
9 9 - @contests.each do |contest|
10 10 = contest.title
11 11 %br
12 12
13 13 =t 'main.confirm_contest_start.timer_starts_after_click'
14 14
15 - = form_tag :action => 'confirm_contest_start', :method => 'post' do
15 + = form_tag :action => 'confirm_contest_start' do
16 16 = submit_tag t('main.confirm_contest_start.start_button'), :confirm => t('main.confirm_contest_start.start_button_confirm')
@@ -1,25 +1,25
1 1 <%= error_messages_for 'user' %>
2 2
3 3 <!--[form:user]-->
4 4 <p><label for="user_name">Login</label><br/>
5 5 <%= text_field 'user', 'login' %></p>
6 6
7 7 <p><label for="user_name">Full name</label><br/>
8 8 <%= text_field 'user', 'full_name' %></p>
9 9
10 10 <p><label for="password">Password</label><br/>
11 11 <%= password_field 'user', 'password' %></p>
12 12
13 13 <p><label for="password_confirmation">Password (confirm)</label><br/>
14 14 <%= password_field 'user', 'password_confirmation' %></p>
15 15
16 16 <p><label for="user_email">E-mail</label><br/>
17 - <%= text_field 'user', 'email' %></p>
17 + <%= email_field 'user', 'email' %></p>
18 18
19 19 <p><label for="user_alias">Alias</label><br/>
20 20 <%= text_field 'user', 'alias' %></p>
21 21
22 22 <p><label for="user_remark">Remark</label><br/>
23 23 <%= text_field 'user', 'remark' %></p>
24 24 <!--[eoform:user]-->
25 25
@@ -1,87 +1,87
1 1 <h1>Listing users</h1>
2 2
3 3 <div class="submitbox">
4 4 <b>Quick add</b>
5 5 <%= form_tag :action => 'create' do %>
6 6 <table border="0">
7 7 <tr>
8 8 <td><label for="user_login">Login</label></td>
9 9 <td><label for="user_full_name">Full name</label></td>
10 10 <td><label for="user_password">Password</label></td>
11 11 <td><label for="user_password_confirmation">Confirm</label></td>
12 12 <td><label for="user_email">Email</label></td>
13 13 </tr>
14 14 <tr>
15 15 <td><%= text_field 'user', 'login', :size => 10 %></td>
16 16 <td><%= text_field 'user', 'full_name', :size => 30 %></td>
17 17 <td><%= password_field 'user', 'password', :size => 10 %></td>
18 18 <td><%= password_field 'user', 'password_confirmation', :size => 10 %></td>
19 - <td><%= text_field 'user', 'email', :size => 15 %></td>
19 + <td><%= email_field 'user', 'email', :size => 15 %></td>
20 20 <td><%= submit_tag "Create" %></td>
21 21 </tr>
22 22 </table>
23 23 <% end %>
24 24 <br/>
25 25 <b>Import from site management</b>
26 26 <%= form_tag({:action => 'import'}, :multipart => true) do %>
27 27 File: <%= file_field_tag 'file' %> <%= submit_tag 'Import' %>
28 28 <% end %>
29 29 <br/>
30 30 <b>What else: </b>
31 31 <%= link_to '[New user]', :action => 'new' %>
32 32 <%= link_to '[New list of users]', :action => 'new_list' %>
33 33 <%= link_to '[View administrators]', :action => 'admin' %>
34 34 <%= link_to '[Random passwords]', :action => 'random_all_passwords' %>
35 35 <%= link_to '[View active users]', :action => 'active' %>
36 36 <%= link_to '[Mass mailing]', :action => 'mass_mailing' %>
37 37 <% if GraderConfiguration.multicontests? %>
38 38 <br/><b>Multi-contest:</b>
39 39 <%= link_to '[Manage bulk users in contests]', :action => 'contest_management' %>
40 40 View users in:
41 41 <% @contests.each do |contest| %>
42 42 <%= link_to "[#{contest.name}]", :action => 'contests', :id => contest.id %>
43 43 <% end %>
44 44 <%= link_to "[no contest]", :action => 'contests', :id => 'none' %>
45 45 <% end %>
46 46 </div>
47 47
48 48 Total <%= @user_count %> users |
49 49 <% if !@paginated %>
50 50 Display all users.
51 51 <%= link_to '[show in pages]', :action => 'list', :page => '1' %>
52 52 <% else %>
53 53 Display in pages.
54 54 <%= link_to '[display all]', :action => 'list', :page => 'all' %> |
55 55 <%= will_paginate @users, :container => false %>
56 56 <% end %>
57 57 <table class="info">
58 58 <tr class="info-head">
59 59 <% for column in User.content_columns %>
60 60 <% if !@hidden_columns.index(column.name) %>
61 61 <th><%= column.human_name %></th>
62 62 <% end %>
63 63 <% end %>
64 64 <th></th>
65 65 <th></th>
66 66 <th></th>
67 67 </tr>
68 68
69 69 <% for user in @users %>
70 70 <tr class="info-<%= cycle("odd","even") %>">
71 71 <td><%= link_to user.login, controller: :users, :action => 'profile', :id => user %></td>
72 72 <% for column in User.content_columns %>
73 73 <% if !@hidden_columns.index(column.name) and column.name != 'login' %>
74 74 <td><%=h user.send(column.name) %></td>
75 75 <% end %>
76 76 <% end %>
77 77 <td><%= link_to 'Show', :action => 'show', :id => user %></td>
78 78 <td><%= link_to 'Edit', :action => 'edit', :id => user %></td>
79 79 <td><%= link_to 'Destroy', { :action => 'destroy', :id => user }, :confirm => 'Are you sure?', :method => :post %></td>
80 80 </tr>
81 81 <% end %>
82 82 </table>
83 83
84 84 <br />
85 85
86 86 <%= link_to '[New user]', :action => 'new' %>
87 87 <%= link_to '[New list of users]', :action => 'new_list' %>
@@ -1,18 +1,19
1 1 .contest-title
2 2 %h1
3 3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.password_retrieval.header'}"
4 4
5 5 - if flash[:notice]
6 6 %hr/
7 7 %b= flash[:notice]
8 8 %hr/
9 9
10 10 %br/
11 11
12 12 = form_tag :action => 'retrieve_password' do
13 13 =t 'registration.password_retrieval.instructions'
14 - = text_field 'email', nil, :size => 20
14 + %br/
15 + = email_field 'email', nil, :size => 20
15 16 %br/
16 17 = submit_tag(t 'registration.password_retrieval.button_label')
17 18
18 19 = link_to "#{t 'go_back_to'}#{t 'home_page'}", :controller => 'main', :action => 'index'
@@ -1,39 +1,39
1 1 .contest-title
2 2 %h1
3 3 = "#{GraderConfiguration['contest.name']}: #{t 'registration.title'}"
4 4
5 5 .registration-desc
6 6 =t 'registration.description'
7 7
8 8 = error_messages_for :user, :header_message => (t 'registration.errors.header')
9 9
10 10 %table
11 11 = form_for @user, :url => { :action => 'register' } do |f|
12 12 %tr
13 13 %td{:align => "right"}
14 14 = "#{t 'login_label'}:"
15 15 %td= f.text_field :login
16 16 %tr
17 17 %td
18 18 %td
19 19 %small
20 20 =t 'registration.login_guide'
21 21 %tr
22 22 %td{:align => "right"}
23 23 = "#{t 'full_name_label'}:"
24 24 %td= f.text_field :full_name
25 25 %tr
26 26 %td{:align => "right"}
27 27 = "#{t 'email_label'}:"
28 - %td= f.text_field :email
28 + %td= f.email_field :email
29 29 %tr
30 30 %td
31 31 %td
32 32 %small
33 - =t 'registration.email_guide'
33 + =t('registration.email_guide').html_safe
34 34 %tr
35 35 %td/
36 36 %td
37 37 = submit_tag((t 'registration.register'), :name => 'commit')
38 38 = submit_tag((t 'cancel'), :name => 'cancel')
39 39
@@ -1,37 +1,40
1 1 CafeGrader::Application.configure do
2 2 # Settings specified here will take precedence over those in config/application.rb
3 3
4 4 # In the development environment your application's code is reloaded on
5 5 # every request. This slows down response time but is perfect for development
6 6 # since you don't have to restart the web server when you make code changes.
7 7 config.cache_classes = false
8 8
9 9 # Log error messages when you accidentally call methods on nil.
10 10 config.whiny_nils = true
11 11
12 12 # Show full error reports and disable caching
13 13 config.consider_all_requests_local = true
14 14 config.action_controller.perform_caching = false
15 15
16 16 # Don't care if the mailer can't send
17 17 config.action_mailer.raise_delivery_errors = false
18 18
19 19 # Print deprecation notices to the Rails logger
20 20 config.active_support.deprecation = :log
21 21
22 22 # Only use best-standards-support built into browsers
23 23 config.action_dispatch.best_standards_support = :builtin
24 24
25 25 # Raise exception on mass assignment protection for Active Record models
26 26 config.active_record.mass_assignment_sanitizer = :strict
27 27
28 28 # Log the query plan for queries taking more than this (works
29 29 # with SQLite, MySQL, and PostgreSQL)
30 30 config.active_record.auto_explain_threshold_in_seconds = 0.5
31 31
32 32 # Do not compress assets
33 33 config.assets.compress = false
34 34
35 35 # Expands the lines which load the assets
36 36 config.assets.debug = true
37 +
38 + # Prevents assets from rendering twice
39 + config.serve_static_assets = false
37 40 end
@@ -1,30 +1,41
1 1 module MailHelperMethods
2 2
3 3 def send_mail(mail_to, mail_subject, mail_body)
4 4 mail_from = GraderConfiguration['system.online_registration.from']
5 5 smtp_server = GraderConfiguration['system.online_registration.smtp']
6 6
7 7 if ['fake', 'debug'].include? smtp_server
8 8 puts "-------------------------
9 9 To: #{mail_to}
10 10 From: #{mail_from}
11 11 Subject: #{mail_subject}
12 12 #{mail_body}
13 13 --------------------------
14 14 "
15 15 return true
16 16 end
17 17
18 18 mail = Mail.new do
19 19 from mail_from
20 20 to mail_to
21 21 subject mail_subject
22 22 body mail_body
23 23 end
24 24
25 - mail.delivery_settings = { :address => smtp_server }
25 + mail_option = {
26 + :address => smtp_server,
27 + # :domain => nil,
28 + # :port => 25,
29 + # :user_name => nil,
30 + # :password => nil,
31 + # :authentication=>'plain',
32 + # :enable_starttls_auto => true
33 + }
34 +
35 + mail.delivery_method :smtp, mail_option
36 +
26 37 mail.deliver
27 38 end
28 39
29 40 end
30 41
You need to be logged in to leave comments. Login now