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

r665:ecbd1a5dbc27 - - 7 files changed: 108 inserted, 8 deleted

@@ -0,0 +1,34
1 + .container-fluid
2 + %h1 Editing announcement
3 + = error_messages_for :announcement
4 + .row
5 + .col-md-6
6 + = form_for(@announcement) do |f|
7 + .form-group
8 + %label Title
9 + = f.text_field :title, class: 'form-control'
10 + .form-group
11 + %label Notes
12 + (shown internally, used to organize announcements)
13 + = f.text_field :notes, class: 'form-control'
14 + .form-group
15 + %label Body
16 + = f.text_area :body, class: 'form-control', style: 'height: 200px;'
17 + .form-group
18 + %label Author
19 + = f.text_field :author, class: 'form-control'
20 + .checkbox
21 + %label
22 + = f.check_box :published
23 + Published
24 + .checkbox
25 + %label
26 + = f.check_box :frontpage
27 + Show on front page?
28 + .checkbox
29 + %label
30 + = f.check_box :contest_only
31 + Show only in contest?
32 + = f.submit "Update", class: 'btn btn-primary'
33 + = link_to 'Show', @announcement, class: 'btn btn-default'
34 + = link_to 'Back', announcements_path, class: 'btn btn-default'
@@ -0,0 +1,52
1 + = error_messages_for 'problem'
2 + / [form:problem]
3 + .form-group
4 + %label{:for => "problem_name"} Name
5 + = text_field 'problem', 'name', class: 'form-control'
6 + %small
7 + Do not directly edit the problem name, unless you know what you are doing. If you want to change the name, use the name change button in the problem management menu instead.
8 + .form-group
9 + %label{:for => "problem_full_name"} Full name
10 + = text_field 'problem', 'full_name', class: 'form-control'
11 + .form-group
12 + %label{:for => "problem_full_score"} Full score
13 + = text_field 'problem', 'full_score', class: 'form-control'
14 + .form-group
15 + %label{:for => "problem_date_added"} Date added
16 + = date_select 'problem', 'date_added', class: 'form-control'
17 + - # TODO: these should be put in model Problem, but I can't think of
18 + - # nice default values for them. These values look fine only
19 + - # in this case (of lazily adding new problems).
20 + - @problem.available = true if @problem!=nil and @problem.available==nil
21 + - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil
22 + - @problem.output_only = false if @problem!=nil and @problem.output_only==nil
23 + .checkbox
24 + %label{:for => "problem_available"}
25 + = check_box :problem, :available
26 + Available?
27 + .checkbox
28 + %label{:for => "problem_test_allowed"}
29 + = check_box :problem, :test_allowed
30 + Test allowed?
31 + .checkbox
32 + %label{:for => "problem_output_only"}
33 + = check_box :problem, :output_only
34 + Output only?
35 + = error_messages_for 'description'
36 + .form-group
37 + %label{:for => "description_body"} Description
38 + %br/
39 + = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control'
40 + .form-group
41 + %label{:for => "description_markdowned"} Markdowned?
42 + = select "description", |
43 + "markdowned", |
44 + [['True',true],['False',false]], |
45 + {:selected => (@description) ? @description.markdowned : false } |
46 + .form-group
47 + %label{:for => "problem_url"} URL
48 + %br/
49 + = text_field 'problem', 'url',class: 'form-control'
50 + %p
51 + Task PDF #{file_field_tag 'file'}
52 + / [eoform:problem]
@@ -0,0 +1,14
1 + .container-fluid
2 + = form_for @problem,url:{action: 'update'},html: {multipart: true} do
3 + .row
4 + .col-md-6
5 + %h1 Editing problem
6 + = render :partial => 'form'
7 + .row
8 + .col-md-4
9 + = submit_tag 'Edit', class: 'btn btn-primary btn-block'
10 + .col-md-4
11 + = link_to 'Show', {:action => 'show', :id => @problem}, class: 'btn btn-default btn-block'
12 + .col-md-4
13 + = link_to 'Back', problems_path, class: 'btn btn-default btn-block'
14 + .div{style: 'height: 5em'}
@@ -0,0 +1,5
1 + require 'spec_helper'
2 +
3 + describe Testcases do
4 + pending "add some examples to (or delete) #{__FILE__}"
5 + end
@@ -132,193 +132,193
132 132 .select(:ip_address).uniq
133 133
134 134 }
135 135 end
136 136 end
137 137
138 138 def submission_stat
139 139
140 140 date_and_time = '%Y-%m-%d %H:%M'
141 141 begin
142 142 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
143 143 rescue
144 144 @since_time = DateTime.new(1000,1,1)
145 145 end
146 146 begin
147 147 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
148 148 rescue
149 149 @until_time = DateTime.new(3000,1,1)
150 150 end
151 151
152 152 @submissions = {}
153 153
154 154 User.find_each do |user|
155 155 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
156 156 end
157 157
158 158 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
159 159 if @submissions[s.user_id]
160 160 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
161 161 a = Problem.find_by_id(s.problem_id)
162 162 @submissions[s.user_id][:sub][s.problem_id] =
163 163 { prob_name: (a ? a.full_name : '(NULL)'),
164 164 sub_ids: [s.id] }
165 165 else
166 166 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
167 167 end
168 168 @submissions[s.user_id][:count] += 1
169 169 end
170 170 end
171 171 end
172 172
173 173 def problem_hof
174 174 # gen problem list
175 175 @user = User.find(session[:user_id])
176 176 @problems = @user.available_problems
177 177
178 178 # get selected problems or the default
179 179 if params[:id]
180 180 begin
181 181 @problem = Problem.available.find(params[:id])
182 182 rescue
183 183 redirect_to action: :problem_hof
184 184 flash[:notice] = 'Error: submissions for that problem are not viewable.'
185 185 return
186 186 end
187 187 end
188 188
189 189 return unless @problem
190 190
191 191 @by_lang = {} #aggregrate by language
192 192
193 193 range =65
194 194 @histogram = { data: Array.new(range,0), summary: {} }
195 195 @summary = {count: 0, solve: 0, attempt: 0}
196 196 user = Hash.new(0)
197 197 Submission.where(problem_id: @problem.id).find_each do |sub|
198 198 #histogram
199 199 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
200 200 @histogram[:data][d.to_i] += 1 if d < range
201 201
202 202 next unless sub.points
203 203 @summary[:count] += 1
204 204 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
205 205
206 206 lang = Language.find_by_id(sub.language_id)
207 207 next unless lang
208 208 next unless sub.points >= @problem.full_score
209 209
210 210 #initialize
211 211 unless @by_lang.has_key?(lang.pretty_name)
212 212 @by_lang[lang.pretty_name] = {
213 213 runtime: { avail: false, value: 2**30-1 },
214 214 memory: { avail: false, value: 2**30-1 },
215 215 length: { avail: false, value: 2**30-1 },
216 216 first: { avail: false, value: DateTime.new(3000,1,1) }
217 217 }
218 218 end
219 219
220 220 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
221 221 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
222 222 end
223 223
224 224 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
225 225 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
226 226 end
227 227
228 - if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
228 + if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
229 229 !sub.user.admin?
230 230 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
231 231 end
232 232
233 233 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
234 234 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
235 235 end
236 236 end
237 237
238 238 #process user_id
239 239 @by_lang.each do |lang,prop|
240 240 prop.each do |k,v|
241 241 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
242 242 end
243 243 end
244 244
245 245 #sum into best
246 246 if @by_lang and @by_lang.first
247 247 @best = @by_lang.first[1].clone
248 248 @by_lang.each do |lang,prop|
249 249 if @best[:runtime][:value] >= prop[:runtime][:value]
250 250 @best[:runtime] = prop[:runtime]
251 251 @best[:runtime][:lang] = lang
252 252 end
253 253 if @best[:memory][:value] >= prop[:memory][:value]
254 254 @best[:memory] = prop[:memory]
255 255 @best[:memory][:lang] = lang
256 256 end
257 257 if @best[:length][:value] >= prop[:length][:value]
258 258 @best[:length] = prop[:length]
259 259 @best[:length][:lang] = lang
260 260 end
261 261 if @best[:first][:value] >= prop[:first][:value]
262 262 @best[:first] = prop[:first]
263 263 @best[:first][:lang] = lang
264 264 end
265 265 end
266 266 end
267 267
268 268 @histogram[:summary][:max] = [@histogram[:data].max,1].max
269 269 @summary[:attempt] = user.count
270 270 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
271 271 end
272 272
273 273 def stuck #report struggling user,problem
274 274 # init
275 275 user,problem = nil
276 276 solve = true
277 277 tries = 0
278 278 @struggle = Array.new
279 279 record = {}
280 280 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
281 281 next unless sub.problem and sub.user
282 282 if user != sub.user_id or problem != sub.problem_id
283 283 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
284 284 record = {user: sub.user, problem: sub.problem}
285 285 user,problem = sub.user_id, sub.problem_id
286 286 solve = false
287 287 tries = 0
288 288 end
289 289 if sub.points >= sub.problem.full_score
290 290 solve = true
291 291 else
292 292 tries += 1
293 293 end
294 294 end
295 295 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
296 296 @struggle = @struggle[0..50]
297 297 end
298 298
299 299
300 300 def multiple_login
301 301 #user with multiple IP
302 302 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
303 303 last,count = 0,0
304 304 first = 0
305 305 @users = []
306 306 raw.each do |r|
307 307 if last != r.user.login
308 308 count = 1
309 309 last = r.user.login
310 310 first = r
311 311 else
312 312 @users << first if count == 1
313 313 @users << r
314 314 count += 1
315 315 end
316 316 end
317 317
318 318 #IP with multiple user
319 319 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
320 320 last,count = 0,0
321 321 first = 0
322 322 @ip = []
323 323 raw.each do |r|
324 324 if last != r.ip_address
@@ -18,193 +18,194
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(user_params)
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 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 stat
113 113 @user = User.find(params[:id])
114 - @submission = Submission.includes(:problem).where(user_id: params[:id])
114 + @submission = Submission.joins(:problem).where(user_id: params[:id])
115 + @submission = @submission.where('problems.available = true') unless current_user.admin?
115 116
116 117 range = 120
117 118 @histogram = { data: Array.new(range,0), summary: {} }
118 119 @summary = {count: 0, solve: 0, attempt: 0}
119 120 problem = Hash.new(0)
120 121
121 122 @submission.find_each do |sub|
122 123 #histogram
123 124 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
124 125 @histogram[:data][d.to_i] += 1 if d < range
125 126
126 127 @summary[:count] += 1
127 128 next unless sub.problem
128 129 problem[sub.problem] = [problem[sub.problem], ( (sub.try(:points) || 0) >= sub.problem.full_score) ? 1 : 0].max
129 130 end
130 131
131 132 @histogram[:summary][:max] = [@histogram[:data].max,1].max
132 133 @summary[:attempt] = problem.count
133 134 problem.each_value { |v| @summary[:solve] += 1 if v == 1 }
134 135 end
135 136
136 137 def toggle_activate
137 138 @user = User.find(params[:id])
138 139 @user.update_attributes( activated: !@user.activated? )
139 140 respond_to do |format|
140 141 format.js { render partial: 'toggle_button',
141 142 locals: {button_id: "#toggle_activate_user_#{@user.id}",button_on: @user.activated? } }
142 143 end
143 144 end
144 145
145 146 def toggle_enable
146 147 @user = User.find(params[:id])
147 148 @user.update_attributes( enabled: !@user.enabled? )
148 149 respond_to do |format|
149 150 format.js { render partial: 'toggle_button',
150 151 locals: {button_id: "#toggle_enable_user_#{@user.id}",button_on: @user.enabled? } }
151 152 end
152 153 end
153 154
154 155 protected
155 156
156 157 def verify_online_registration
157 158 if !GraderConfiguration['system.online_registration']
158 159 redirect_to :controller => 'main', :action => 'login'
159 160 end
160 161 end
161 162
162 163 def send_confirmation_email(user)
163 164 contest_name = GraderConfiguration['contest.name']
164 165 activation_url = url_for(:action => 'confirm',
165 166 :login => user.login,
166 167 :activation => user.activation_key)
167 168 home_url = url_for(:controller => 'main', :action => 'index')
168 169 mail_subject = "[#{contest_name}] Confirmation"
169 170 mail_body = t('registration.email_body', {
170 171 :full_name => user.full_name,
171 172 :contest_name => contest_name,
172 173 :login => user.login,
173 174 :password => user.password,
174 175 :activation_url => activation_url,
175 176 :admin_email => GraderConfiguration['system.admin_email']
176 177 })
177 178
178 179 logger.info mail_body
179 180
180 181 send_mail(user.email, mail_subject, mail_body)
181 182 end
182 183
183 184 def send_new_password_email(user)
184 185 contest_name = GraderConfiguration['contest.name']
185 186 mail_subject = "[#{contest_name}] Password recovery"
186 187 mail_body = t('registration.password_retrieval.email_body', {
187 188 :full_name => user.full_name,
188 189 :contest_name => contest_name,
189 190 :login => user.login,
190 191 :password => user.password,
191 192 :admin_email => GraderConfiguration['system.admin_email']
192 193 })
193 194
194 195 logger.info mail_body
195 196
196 197 send_mail(user.email, mail_subject, mail_body)
197 198 end
198 199
199 200 # allow viewing of regular user profile only when options allow so
200 201 # only admins can view admins profile
201 202 def profile_authorization
202 203 #if view admins' profile, allow only admin
203 204 return false unless(params[:id])
204 205 user = User.find(params[:id])
205 206 return false unless user
206 207 return admin_authorization if user.admin?
207 208 return true if GraderConfiguration["right.user_view_submission"]
208 209
209 210 #finally, we allow only admin
210 211 admin_authorization
@@ -1,78 +1,72
1 1 require File.expand_path('../boot', __FILE__)
2 2
3 3 require 'rails/all'
4 4
5 5 if defined?(Bundler)
6 6 # If you precompile assets before deploying to production, use this line
7 7 Bundler.require(*Rails.groups(:assets => %w(development test)))
8 8 # If you want your assets lazily compiled in production, use this line
9 9 # Bundler.require(:default, :assets, Rails.env)
10 10 end
11 11
12 12 module CafeGrader
13 13 class Application < Rails::Application
14 14 # Settings in config/environments/* take precedence over those specified here.
15 15 # Application configuration should go into files in config/initializers
16 16 # -- all .rb files in that directory are automatically loaded.
17 17
18 18 # Custom directories with classes and modules you want to be autoloadable.
19 19 config.autoload_paths += %W(#{config.root}/lib)
20 20
21 21 # Only load the plugins named here, in the order given (default is alphabetical).
22 22 # :all can be used as a placeholder for all plugins not explicitly named.
23 23 # config.plugins = [ :exception_notification, :ssl_requirement, :all ]
24 24
25 25 # Activate observers that should always be running.
26 26 # config.active_record.observers = :cacher, :garbage_collector, :forum_observer
27 27
28 28 # Set Time.zone default to the specified zone and make Active Record auto-convert to this zone.
29 29 # Run "rake -D time" for a list of tasks for finding time zone names. Default is UTC.
30 30 config.time_zone = 'UTC'
31 31
32 32 # The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
33 33 # config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
34 34 config.i18n.default_locale = :en
35 35
36 36 # Configure the default encoding used in templates for Ruby 1.9.
37 37 config.encoding = "utf-8"
38 38
39 39 # Configure sensitive parameters which will be filtered from the log file.
40 40 config.filter_parameters += [:password]
41 41
42 42 # Enable escaping HTML in JSON.
43 43 config.active_support.escape_html_entities_in_json = true
44 44
45 45 # Use SQL instead of Active Record's schema dumper when creating the database.
46 46 # This is necessary if your schema can't be completely dumped by the schema dumper,
47 47 # like if you have constraints or database-specific column types
48 48 # config.active_record.schema_format = :sql
49 49
50 - # Enforce whitelist mode for mass assignment.
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
53 - # parameters by using an attr_accessible or attr_protected declaration.
54 - config.active_record.whitelist_attributes = false
55 -
56 50 # Enable the asset pipeline
57 51 config.assets.enabled = true
58 52
59 53 # Version of your assets, change this if you want to expire all your assets
60 54 config.assets.version = '1.0'
61 55
62 56 # ---------------- IMPORTANT ----------------------
63 57 # If we deploy the app into a subdir name "grader", be sure to do "rake assets:precompile RAILS_RELATIVE_URL_ROOT=/grader"
64 58 # moreover, using the following line instead also known to works
65 59 #config.action_controller.relative_url_root = '/grader'
66 60
67 61 #font path
68 62 config.assets.paths << "#{Rails}/vendor/assets/fonts"
69 63
70 64 config.assets.precompile += ['announcement_refresh.js','effects.js','site_update.js']
71 65 config.assets.precompile += ['local_jquery.js','tablesorter-theme.cafe.css']
72 66 %w( announcements submissions configurations contests contest_management graders heartbeat
73 67 login main messages problems report site sites sources tasks
74 68 test user_admin users ).each do |controller|
75 69 config.assets.precompile += ["#{controller}.js", "#{controller}.css"]
76 70 end
77 71 end
78 72 end
You need to be logged in to leave comments. Login now