Description:
heartbeat response full
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r649:3cb38436f7f6 - - 6 files changed: 42 inserted, 4 deleted

@@ -0,0 +1,9
1 + class AddHeartBeatFull < ActiveRecord::Migration
2 + def up
3 + GraderConfiguration.create key: 'right.heartbeat_response_full', value_type: 'string', value:'RESTART', description:'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
4 + end
5 +
6 + def down
7 +
8 + end
9 + end
@@ -1,31 +1,46
1 1 class HeartbeatController < ApplicationController
2 2 before_filter :admin_authorization, :only => ['index']
3 3
4 4 def edit
5 5 #@user = User.find_by_login(params[:id])
6 6 #unless @user
7 7 # render text: "LOGIN_NOT_FOUND"
8 8 # return
9 9 #end
10 10
11 11 #hb = HeartBeat.where(user_id: @user.id, ip_address: request.remote_ip).first
12 12 #puts "status = #{params[:status]}"
13 13 #if hb
14 14 # if params[:status]
15 15 # hb.status = params[:status]
16 16 # hb.save
17 17 # end
18 18 # hb.touch
19 19 #else
20 20 # HeartBeat.creae(user_id: @user.id, ip_address: request.remote_ip)
21 21 #end
22 22 #HeartBeat.create(user_id: @user.id, ip_address: request.remote_ip, status: params[:status])
23 23
24 - render text: (GraderConfiguration['right.heartbeat_response'] || 'OK')
24 + res = GraderConfiguration['right.heartbeat_response']
25 + res.strip! if res
26 + full = GraderConfiguration['right.heartbeat_response_full']
27 + full.strip! if full
28 +
29 + if full and full != ''
30 + l = Login.where(ip_address: request.remote_ip).last
31 + @user = l.user
32 + if @user.solve_all_available_problems?
33 + render text: (full || 'OK')
34 + else
35 + render text: (res || 'OK')
36 + end
37 + else
38 + render text: (GraderConfiguration['right.heartbeat_response'] || 'OK')
39 + end
25 40 end
26 41
27 42 def index
28 43 @hb = HeartBeat.where("updated_at >= ?",Time.zone.now-2.hours).includes(:user).order(:user_id).all
29 44 @num = HeartBeat.where("updated_at >= ?",Time.zone.now-5.minutes).count(:user_id,distinct: true)
30 45 end
31 46 end
@@ -1,379 +1,388
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, -> { order(created_at: DESC) },
14 14 :class_name => "Message",
15 15 :foreign_key => "sender_id"
16 16
17 17 has_many :replied_messages, -> { order(created_at: DESC) },
18 18 :class_name => "Message",
19 19 :foreign_key => "receiver_id"
20 20
21 21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
22 22
23 23 belongs_to :site
24 24 belongs_to :country
25 25
26 26 has_and_belongs_to_many :contests, -> { order(:name); uniq}
27 27
28 28 scope :activated_users, -> {where activated: true}
29 29
30 30 validates_presence_of :login
31 31 validates_uniqueness_of :login
32 32 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
33 33 validates_length_of :login, :within => 3..30
34 34
35 35 validates_presence_of :full_name
36 36 validates_length_of :full_name, :minimum => 1
37 37
38 38 validates_presence_of :password, :if => :password_required?
39 39 validates_length_of :password, :within => 4..20, :if => :password_required?
40 40 validates_confirmation_of :password, :if => :password_required?
41 41
42 42 validates_format_of :email,
43 43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
44 44 :if => :email_validation?
45 45 validate :uniqueness_of_email_from_activated_users,
46 46 :if => :email_validation?
47 47 validate :enough_time_interval_between_same_email_registrations,
48 48 :if => :email_validation?
49 49
50 50 # these are for ytopc
51 51 # disable for now
52 52 #validates_presence_of :province
53 53
54 54 attr_accessor :password
55 55
56 56 before_save :encrypt_new_password
57 57 before_save :assign_default_site
58 58 before_save :assign_default_contest
59 59
60 60 # this is for will_paginate
61 61 cattr_reader :per_page
62 62 @@per_page = 50
63 63
64 64 def self.authenticate(login, password)
65 65 user = find_by_login(login)
66 66 if user
67 67 return user if user.authenticated?(password)
68 68 if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
69 69 user.password = password
70 70 user.save
71 71 return user
72 72 end
73 73 end
74 74 end
75 75
76 76 def authenticated?(password)
77 77 if self.activated
78 78 hashed_password == User.encrypt(password,self.salt)
79 79 else
80 80 false
81 81 end
82 82 end
83 83
84 84 def authenticated_by_pop3?(password)
85 85 Net::POP3.enable_ssl
86 86 pop = Net::POP3.new('pops.it.chula.ac.th')
87 87 authen = true
88 88 begin
89 89 pop.start(login, password)
90 90 pop.finish
91 91 return true
92 92 rescue
93 93 return false
94 94 end
95 95 end
96 96
97 97 def authenticated_by_cucas?(password)
98 98 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
99 99 appid = '41508763e340d5858c00f8c1a0f5a2bb'
100 100 appsecret ='d9cbb5863091dbe186fded85722a1e31'
101 101 post_args = {
102 102 'appid' => appid,
103 103 'appsecret' => appsecret,
104 104 'username' => login,
105 105 'password' => password
106 106 }
107 107
108 108 #simple call
109 109 begin
110 110 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
111 111 http.use_ssl = true
112 112 http.verify_mode = OpenSSL::SSL::VERIFY_NONE
113 113 result = [ ]
114 114 http.start do |http|
115 115 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
116 116 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
117 117 resp = http.request(req,param)
118 118 result = JSON.parse resp.body
119 119 end
120 120 return true if result["type"] == "beanStudent"
121 121 rescue => e
122 122 return false
123 123 end
124 124 return false
125 125 end
126 126
127 127 def admin?
128 128 self.roles.detect {|r| r.name == 'admin' }
129 129 end
130 130
131 131 def email_for_editing
132 132 if self.email==nil
133 133 "(unknown)"
134 134 elsif self.email==''
135 135 "(blank)"
136 136 else
137 137 self.email
138 138 end
139 139 end
140 140
141 141 def email_for_editing=(e)
142 142 self.email=e
143 143 end
144 144
145 145 def alias_for_editing
146 146 if self.alias==nil
147 147 "(unknown)"
148 148 elsif self.alias==''
149 149 "(blank)"
150 150 else
151 151 self.alias
152 152 end
153 153 end
154 154
155 155 def alias_for_editing=(e)
156 156 self.alias=e
157 157 end
158 158
159 159 def activation_key
160 160 if self.hashed_password==nil
161 161 encrypt_new_password
162 162 end
163 163 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 164 end
165 165
166 166 def verify_activation_key(key)
167 167 key == activation_key
168 168 end
169 169
170 170 def self.random_password(length=5)
171 171 chars = 'abcdefghjkmnopqrstuvwxyz'
172 172 password = ''
173 173 length.times { password << chars[rand(chars.length - 1)] }
174 174 password
175 175 end
176 176
177 177 def self.find_non_admin_with_prefix(prefix='')
178 178 users = User.all
179 179 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
180 180 end
181 181
182 182 # Contest information
183 183
184 184 def self.find_users_with_no_contest()
185 185 users = User.all
186 186 return users.find_all { |u| u.contests.length == 0 }
187 187 end
188 188
189 189
190 190 def contest_time_left
191 191 if GraderConfiguration.contest_mode?
192 192 return nil if site==nil
193 193 return site.time_left
194 194 elsif GraderConfiguration.indv_contest_mode?
195 195 time_limit = GraderConfiguration.contest_time_limit
196 196 if time_limit == nil
197 197 return nil
198 198 end
199 199 if contest_stat==nil or contest_stat.started_at==nil
200 200 return (Time.now.gmtime + time_limit) - Time.now.gmtime
201 201 else
202 202 finish_time = contest_stat.started_at + time_limit
203 203 current_time = Time.now.gmtime
204 204 if current_time > finish_time
205 205 return 0
206 206 else
207 207 return finish_time - current_time
208 208 end
209 209 end
210 210 else
211 211 return nil
212 212 end
213 213 end
214 214
215 215 def contest_finished?
216 216 if GraderConfiguration.contest_mode?
217 217 return false if site==nil
218 218 return site.finished?
219 219 elsif GraderConfiguration.indv_contest_mode?
220 220 return false if self.contest_stat(true)==nil
221 221 return contest_time_left == 0
222 222 else
223 223 return false
224 224 end
225 225 end
226 226
227 227 def contest_started?
228 228 if GraderConfiguration.indv_contest_mode?
229 229 stat = self.contest_stat
230 230 return ((stat != nil) and (stat.started_at != nil))
231 231 elsif GraderConfiguration.contest_mode?
232 232 return true if site==nil
233 233 return site.started
234 234 else
235 235 return true
236 236 end
237 237 end
238 238
239 239 def update_start_time
240 240 stat = self.contest_stat
241 241 if stat.nil? or stat.started_at.nil?
242 242 stat ||= UserContestStat.new(:user => self)
243 243 stat.started_at = Time.now.gmtime
244 244 stat.save
245 245 end
246 246 end
247 247
248 248 def problem_in_user_contests?(problem)
249 249 problem_contests = problem.contests.all
250 250
251 251 if problem_contests.length == 0 # this is public contest
252 252 return true
253 253 end
254 254
255 255 contests.each do |contest|
256 256 if problem_contests.find {|c| c.id == contest.id }
257 257 return true
258 258 end
259 259 end
260 260 return false
261 261 end
262 262
263 263 def available_problems_group_by_contests
264 264 contest_problems = []
265 265 pin = {}
266 266 contests.enabled.each do |contest|
267 267 available_problems = contest.problems.available
268 268 contest_problems << {
269 269 :contest => contest,
270 270 :problems => available_problems
271 271 }
272 272 available_problems.each {|p| pin[p.id] = true}
273 273 end
274 274 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
275 275 contest_problems << {
276 276 :contest => nil,
277 277 :problems => other_avaiable_problems
278 278 }
279 279 return contest_problems
280 280 end
281 281
282 + def solve_all_available_problems?
283 + available_problems.each do |p|
284 + u = self
285 + sub = Submission.find_last_by_user_and_problem(u.id,p.id)
286 + return false if !p or !sub or sub.points < p.full_score
287 + end
288 + return true
289 + end
290 +
282 291 def available_problems
283 292 if not GraderConfiguration.multicontests?
284 293 return Problem.available_problems
285 294 else
286 295 contest_problems = []
287 296 pin = {}
288 297 contests.enabled.each do |contest|
289 298 contest.problems.available.each do |problem|
290 299 if not pin.has_key? problem.id
291 300 contest_problems << problem
292 301 end
293 302 pin[problem.id] = true
294 303 end
295 304 end
296 305 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
297 306 return contest_problems + other_avaiable_problems
298 307 end
299 308 end
300 309
301 310 def can_view_problem?(problem)
302 311 if not GraderConfiguration.multicontests?
303 312 return problem.available
304 313 else
305 314 return problem_in_user_contests? problem
306 315 end
307 316 end
308 317
309 318 def self.clear_last_login
310 319 User.update_all(:last_ip => nil)
311 320 end
312 321
313 322 protected
314 323 def encrypt_new_password
315 324 return if password.blank?
316 325 self.salt = (10+rand(90)).to_s
317 326 self.hashed_password = User.encrypt(self.password,self.salt)
318 327 end
319 328
320 329 def assign_default_site
321 330 # have to catch error when migrating (because self.site is not available).
322 331 begin
323 332 if self.site==nil
324 333 self.site = Site.find_by_name('default')
325 334 if self.site==nil
326 335 self.site = Site.find(1) # when 'default has be renamed'
327 336 end
328 337 end
329 338 rescue
330 339 end
331 340 end
332 341
333 342 def assign_default_contest
334 343 # have to catch error when migrating (because self.site is not available).
335 344 begin
336 345 if self.contests.length == 0
337 346 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
338 347 if default_contest
339 348 self.contests = [default_contest]
340 349 end
341 350 end
342 351 rescue
343 352 end
344 353 end
345 354
346 355 def password_required?
347 356 self.hashed_password.blank? || !self.password.blank?
348 357 end
349 358
350 359 def self.encrypt(string,salt)
351 360 Digest::SHA1.hexdigest(salt + string)
352 361 end
353 362
354 363 def uniqueness_of_email_from_activated_users
355 364 user = User.activated_users.find_by_email(self.email)
356 365 if user and (user.login != self.login)
357 366 self.errors.add(:base,"Email has already been taken")
358 367 end
359 368 end
360 369
361 370 def enough_time_interval_between_same_email_registrations
362 371 return if !self.new_record?
363 372 return if self.activated
364 373 open_user = User.find_by_email(self.email,
365 374 :order => 'created_at DESC')
366 375 if open_user and open_user.created_at and
367 376 (open_user.created_at > Time.now.gmtime - 5.minutes)
368 377 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
369 378 end
370 379 end
371 380
372 381 def email_validation?
373 382 begin
374 383 return VALIDATE_USER_EMAILS
375 384 rescue
376 385 return false
377 386 end
378 387 end
379 388 end
@@ -1,100 +1,98
1 1 CafeGrader::Application.routes.draw do
2 2 get "sources/direct_edit"
3 3
4 4 root :to => 'main#login'
5 5
6 6 #logins
7 7 get 'login/login', to: 'login#login'
8 8
9 9 resources :contests
10 10
11 11 resources :sites
12 12
13 13 resources :announcements do
14 14 member do
15 15 get 'toggle','toggle_front'
16 16 end
17 17 end
18 18
19 19 resources :problems do
20 20 member do
21 21 get 'toggle'
22 22 get 'toggle_test'
23 23 get 'toggle_view_testcase'
24 24 get 'stat'
25 25 end
26 26 collection do
27 27 get 'turn_all_off'
28 28 get 'turn_all_on'
29 29 get 'import'
30 30 get 'manage'
31 31 end
32 32
33 33 end
34 34
35 35 resources :testcases, only: [] do
36 36 member do
37 37 get 'download_input'
38 38 get 'download_sol'
39 39 end
40 40 collection do
41 41 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
42 42 end
43 43 end
44 44
45 45 resources :grader_configuration, controller: 'configurations'
46 46
47 47 resources :users do
48 48 member do
49 49 get 'toggle_activate', 'toggle_enable'
50 50 get 'stat'
51 51 end
52 52 end
53 53
54 54 resources :submissions do
55 55 member do
56 56 get 'download'
57 57 get 'compiler_msg'
58 58 get 'rejudge'
59 59 end
60 60 collection do
61 61 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
62 62 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
63 63 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
64 64 end
65 65 end
66 66
67 67
68 68
69 69 #main
70 70 get "main/list"
71 71 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
72 72
73 73 #user admin
74 74 get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
75 75
76 76 #report
77 77 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
78 78 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
79 79 get "report/login"
80 80 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
81 81 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
82 82
83 83
84 84 #
85 85 get 'tasks/view/:file.:ext' => 'tasks#view'
86 86 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
87 87 get 'heartbeat/:id/edit' => 'heartbeat#edit'
88 88
89 89 #grader
90 90 get 'graders/list', to: 'graders#list', as: 'grader_list'
91 -
92 91
93 - get 'heartbeat/:id/edit' => 'heartbeat#edit'
94 92
95 93 # See how all your routes lay out with "rake routes"
96 94
97 95 # This is a legacy wild controller route that's not recommended for RESTful applications.
98 96 # Note: This route will make all actions in every controller accessible via GET requests.
99 97 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
100 98 end
@@ -1,283 +1,283
1 1 # encoding: UTF-8
2 2 # This file is auto-generated from the current state of the database. Instead
3 3 # of editing this file, please use the migrations feature of Active Record to
4 4 # incrementally modify your database, and then regenerate this schema definition.
5 5 #
6 6 # Note that this schema.rb definition is the authoritative source for your
7 7 # database schema. If you need to create the application database on another
8 8 # system, you should be using db:schema:load, not running all the migrations
9 9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 11 #
12 12 # It's strongly recommended that you check this file into your version control system.
13 13
14 - ActiveRecord::Schema.define(version: 20170310110146) do
14 + ActiveRecord::Schema.define(version: 20170427070345) do
15 15
16 16 create_table "announcements", force: :cascade do |t|
17 17 t.string "author", limit: 255
18 18 t.text "body", limit: 65535
19 19 t.boolean "published"
20 20 t.datetime "created_at", null: false
21 21 t.datetime "updated_at", null: false
22 22 t.boolean "frontpage", default: false
23 23 t.boolean "contest_only", default: false
24 24 t.string "title", limit: 255
25 25 t.string "notes", limit: 255
26 26 end
27 27
28 28 create_table "contests", force: :cascade do |t|
29 29 t.string "title", limit: 255
30 30 t.boolean "enabled"
31 31 t.datetime "created_at", null: false
32 32 t.datetime "updated_at", null: false
33 33 t.string "name", limit: 255
34 34 end
35 35
36 36 create_table "contests_problems", id: false, force: :cascade do |t|
37 37 t.integer "contest_id", limit: 4
38 38 t.integer "problem_id", limit: 4
39 39 end
40 40
41 41 create_table "contests_users", id: false, force: :cascade do |t|
42 42 t.integer "contest_id", limit: 4
43 43 t.integer "user_id", limit: 4
44 44 end
45 45
46 46 create_table "countries", force: :cascade do |t|
47 47 t.string "name", limit: 255
48 48 t.datetime "created_at", null: false
49 49 t.datetime "updated_at", null: false
50 50 end
51 51
52 52 create_table "descriptions", force: :cascade do |t|
53 53 t.text "body", limit: 65535
54 54 t.boolean "markdowned"
55 55 t.datetime "created_at", null: false
56 56 t.datetime "updated_at", null: false
57 57 end
58 58
59 59 create_table "grader_configurations", force: :cascade do |t|
60 60 t.string "key", limit: 255
61 61 t.string "value_type", limit: 255
62 62 t.string "value", limit: 255
63 63 t.datetime "created_at", null: false
64 64 t.datetime "updated_at", null: false
65 65 t.text "description", limit: 65535
66 66 end
67 67
68 68 create_table "grader_processes", force: :cascade do |t|
69 69 t.string "host", limit: 255
70 70 t.integer "pid", limit: 4
71 71 t.string "mode", limit: 255
72 72 t.boolean "active"
73 73 t.datetime "created_at", null: false
74 74 t.datetime "updated_at", null: false
75 75 t.integer "task_id", limit: 4
76 76 t.string "task_type", limit: 255
77 77 t.boolean "terminated"
78 78 end
79 79
80 80 add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
81 81
82 82 create_table "heart_beats", force: :cascade do |t|
83 83 t.integer "user_id", limit: 4
84 84 t.string "ip_address", limit: 255
85 85 t.datetime "created_at", null: false
86 86 t.datetime "updated_at", null: false
87 87 t.string "status", limit: 255
88 88 end
89 89
90 90 add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
91 91
92 92 create_table "languages", force: :cascade do |t|
93 93 t.string "name", limit: 10
94 94 t.string "pretty_name", limit: 255
95 95 t.string "ext", limit: 10
96 96 t.string "common_ext", limit: 255
97 97 end
98 98
99 99 create_table "logins", force: :cascade do |t|
100 100 t.integer "user_id", limit: 4
101 101 t.string "ip_address", limit: 255
102 102 t.datetime "created_at", null: false
103 103 t.datetime "updated_at", null: false
104 104 end
105 105
106 106 create_table "messages", force: :cascade do |t|
107 107 t.integer "sender_id", limit: 4
108 108 t.integer "receiver_id", limit: 4
109 109 t.integer "replying_message_id", limit: 4
110 110 t.text "body", limit: 65535
111 111 t.boolean "replied"
112 112 t.datetime "created_at", null: false
113 113 t.datetime "updated_at", null: false
114 114 end
115 115
116 116 create_table "problems", force: :cascade do |t|
117 117 t.string "name", limit: 30
118 118 t.string "full_name", limit: 255
119 119 t.integer "full_score", limit: 4
120 120 t.date "date_added"
121 121 t.boolean "available"
122 122 t.string "url", limit: 255
123 123 t.integer "description_id", limit: 4
124 124 t.boolean "test_allowed"
125 125 t.boolean "output_only"
126 126 t.string "description_filename", limit: 255
127 127 t.boolean "view_testcase"
128 128 end
129 129
130 130 create_table "rights", force: :cascade do |t|
131 131 t.string "name", limit: 255
132 132 t.string "controller", limit: 255
133 133 t.string "action", limit: 255
134 134 end
135 135
136 136 create_table "rights_roles", id: false, force: :cascade do |t|
137 137 t.integer "right_id", limit: 4
138 138 t.integer "role_id", limit: 4
139 139 end
140 140
141 141 add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
142 142
143 143 create_table "roles", force: :cascade do |t|
144 144 t.string "name", limit: 255
145 145 end
146 146
147 147 create_table "roles_users", id: false, force: :cascade do |t|
148 148 t.integer "role_id", limit: 4
149 149 t.integer "user_id", limit: 4
150 150 end
151 151
152 152 add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
153 153
154 154 create_table "sessions", force: :cascade do |t|
155 155 t.string "session_id", limit: 255
156 156 t.text "data", limit: 65535
157 157 t.datetime "updated_at"
158 158 end
159 159
160 160 add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
161 161 add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
162 162
163 163 create_table "sites", force: :cascade do |t|
164 164 t.string "name", limit: 255
165 165 t.boolean "started"
166 166 t.datetime "start_time"
167 167 t.datetime "created_at", null: false
168 168 t.datetime "updated_at", null: false
169 169 t.integer "country_id", limit: 4
170 170 t.string "password", limit: 255
171 171 end
172 172
173 173 create_table "submission_view_logs", force: :cascade do |t|
174 174 t.integer "user_id", limit: 4
175 175 t.integer "submission_id", limit: 4
176 176 t.datetime "created_at", null: false
177 177 t.datetime "updated_at", null: false
178 178 end
179 179
180 180 create_table "submissions", force: :cascade do |t|
181 181 t.integer "user_id", limit: 4
182 182 t.integer "problem_id", limit: 4
183 183 t.integer "language_id", limit: 4
184 184 t.text "source", limit: 65535
185 185 t.binary "binary", limit: 65535
186 186 t.datetime "submitted_at"
187 187 t.datetime "compiled_at"
188 188 t.text "compiler_message", limit: 65535
189 189 t.datetime "graded_at"
190 190 t.integer "points", limit: 4
191 191 t.text "grader_comment", limit: 65535
192 192 t.integer "number", limit: 4
193 193 t.string "source_filename", limit: 255
194 194 t.float "max_runtime", limit: 24
195 195 t.integer "peak_memory", limit: 4
196 196 t.integer "effective_code_length", limit: 4
197 197 t.string "ip_address", limit: 255
198 198 end
199 199
200 200 add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
201 201 add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
202 202
203 203 create_table "tasks", force: :cascade do |t|
204 204 t.integer "submission_id", limit: 4
205 205 t.datetime "created_at"
206 206 t.integer "status", limit: 4
207 207 t.datetime "updated_at"
208 208 end
209 209
210 210 add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
211 211
212 212 create_table "test_pairs", force: :cascade do |t|
213 213 t.integer "problem_id", limit: 4
214 214 t.text "input", limit: 16777215
215 215 t.text "solution", limit: 16777215
216 216 t.datetime "created_at", null: false
217 217 t.datetime "updated_at", null: false
218 218 end
219 219
220 220 create_table "test_requests", force: :cascade do |t|
221 221 t.integer "user_id", limit: 4
222 222 t.integer "problem_id", limit: 4
223 223 t.integer "submission_id", limit: 4
224 224 t.string "input_file_name", limit: 255
225 225 t.string "output_file_name", limit: 255
226 226 t.string "running_stat", limit: 255
227 227 t.integer "status", limit: 4
228 228 t.datetime "updated_at", null: false
229 229 t.datetime "submitted_at"
230 230 t.datetime "compiled_at"
231 231 t.text "compiler_message", limit: 65535
232 232 t.datetime "graded_at"
233 233 t.string "grader_comment", limit: 255
234 234 t.datetime "created_at", null: false
235 235 t.float "running_time", limit: 24
236 236 t.string "exit_status", limit: 255
237 237 t.integer "memory_usage", limit: 4
238 238 end
239 239
240 240 add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
241 241
242 242 create_table "testcases", force: :cascade do |t|
243 243 t.integer "problem_id", limit: 4
244 244 t.integer "num", limit: 4
245 245 t.integer "group", limit: 4
246 246 t.integer "score", limit: 4
247 247 t.text "input", limit: 4294967295
248 248 t.text "sol", limit: 4294967295
249 249 t.datetime "created_at"
250 250 t.datetime "updated_at"
251 251 end
252 252
253 253 add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
254 254
255 255 create_table "user_contest_stats", force: :cascade do |t|
256 256 t.integer "user_id", limit: 4
257 257 t.datetime "started_at"
258 258 t.datetime "created_at", null: false
259 259 t.datetime "updated_at", null: false
260 260 t.boolean "forced_logout"
261 261 end
262 262
263 263 create_table "users", force: :cascade do |t|
264 264 t.string "login", limit: 50
265 265 t.string "full_name", limit: 255
266 266 t.string "hashed_password", limit: 255
267 267 t.string "salt", limit: 5
268 268 t.string "alias", limit: 255
269 269 t.string "email", limit: 255
270 270 t.integer "site_id", limit: 4
271 271 t.integer "country_id", limit: 4
272 272 t.boolean "activated", default: false
273 273 t.datetime "created_at"
274 274 t.datetime "updated_at"
275 275 t.boolean "enabled", default: true
276 276 t.string "remark", limit: 255
277 277 t.string "last_ip", limit: 255
278 278 t.string "section", limit: 255
279 279 end
280 280
281 281 add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
282 282
283 283 end
@@ -1,251 +1,258
1 1 CONFIGURATIONS =
2 2 [
3 3 {
4 4 :key => 'system.single_user_mode',
5 5 :value_type => 'boolean',
6 6 :default_value => 'false',
7 7 :description => 'Only admins can log in to the system when running under single user mode.'
8 8 },
9 9
10 10 {
11 11 :key => 'ui.front.title',
12 12 :value_type => 'string',
13 13 :default_value => 'Grader'
14 14 },
15 15
16 16 {
17 17 :key => 'ui.front.welcome_message',
18 18 :value_type => 'string',
19 19 :default_value => 'Welcome!'
20 20 },
21 21
22 22 {
23 23 :key => 'ui.show_score',
24 24 :value_type => 'boolean',
25 25 :default_value => 'true'
26 26 },
27 27
28 28 {
29 29 :key => 'contest.time_limit',
30 30 :value_type => 'string',
31 31 :default_value => 'unlimited',
32 32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 33 },
34 34
35 35 {
36 36 :key => 'system.mode',
37 37 :value_type => 'string',
38 38 :default_value => 'standard',
39 39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 40 },
41 41
42 42 {
43 43 :key => 'contest.name',
44 44 :value_type => 'string',
45 45 :default_value => 'Grader',
46 46 :description => 'This name will be shown on the user header bar.'
47 47 },
48 48
49 49 {
50 50 :key => 'contest.multisites',
51 51 :value_type => 'boolean',
52 52 :default_value => 'false',
53 53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 54 },
55 55
56 56 #---------------------------- right --------------------------------
57 57 {
58 58 :key => 'right.user_hall_of_fame',
59 59 :value_type => 'boolean',
60 60 :default_value => 'false',
61 61 :description => 'If true, any user can access hall of fame page.'
62 62 },
63 63
64 64 {
65 65 :key => 'right.multiple_ip_login',
66 66 :value_type => 'boolean',
67 67 :default_value => 'true',
68 68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
69 69 },
70 70
71 71 {
72 72 :key => 'right.user_view_submission',
73 73 :value_type => 'boolean',
74 74 :default_value => 'false',
75 75 :description => 'If true, any user can view submissions of every one.'
76 76 },
77 77
78 78 {
79 79 :key => 'right.bypass_agreement',
80 80 :value_type => 'boolean',
81 81 :default_value => 'true',
82 82 :description => 'When false, a user must accept usage agreement before login'
83 83 },
84 84
85 85 {
86 86 :key => 'right.heartbeat_response',
87 87 :value_type => 'string',
88 88 :default_value => 'OK',
89 89 :description => 'Heart beat response text'
90 90 },
91 91
92 92 {
93 + :key => 'right.heartbeat_response_full',
94 + :value_type => 'string',
95 + :default_value => 'OK',
96 + :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
97 + },
98 +
99 + {
93 100 :key => 'right.view_testcase',
94 101 :value_type => 'boolean',
95 102 :default_value => 'false',
96 103 :description => 'When true, any user can view/download test data'
97 104 },
98 105 # If Configuration['system.online_registration'] is true, the
99 106 # system allows online registration, and will use these
100 107 # information for sending confirmation emails.
101 108 {
102 109 :key => 'system.online_registration.smtp',
103 110 :value_type => 'string',
104 111 :default_value => 'smtp.somehost.com'
105 112 },
106 113
107 114 {
108 115 :key => 'system.online_registration.from',
109 116 :value_type => 'string',
110 117 :default_value => 'your.email@address'
111 118 },
112 119
113 120 {
114 121 :key => 'system.admin_email',
115 122 :value_type => 'string',
116 123 :default_value => 'admin@admin.email'
117 124 },
118 125
119 126 {
120 127 :key => 'system.user_setting_enabled',
121 128 :value_type => 'boolean',
122 129 :default_value => 'true',
123 130 :description => 'If this option is true, users can change their settings'
124 131 },
125 132
126 133 {
127 134 :key => 'system.user_setting_enabled',
128 135 :value_type => 'boolean',
129 136 :default_value => 'true',
130 137 :description => 'If this option is true, users can change their settings'
131 138 },
132 139
133 140 # If Configuration['contest.test_request.early_timeout'] is true
134 141 # the user will not be able to use test request at 30 minutes
135 142 # before the contest ends.
136 143 {
137 144 :key => 'contest.test_request.early_timeout',
138 145 :value_type => 'boolean',
139 146 :default_value => 'false'
140 147 },
141 148
142 149 {
143 150 :key => 'system.multicontests',
144 151 :value_type => 'boolean',
145 152 :default_value => 'false'
146 153 },
147 154
148 155 {
149 156 :key => 'contest.confirm_indv_contest_start',
150 157 :value_type => 'boolean',
151 158 :default_value => 'false'
152 159 },
153 160
154 161 {
155 162 :key => 'contest.default_contest_name',
156 163 :value_type => 'string',
157 164 :default_value => 'none',
158 165 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
159 166 }
160 167
161 168 ]
162 169
163 170
164 171 def create_configuration_key(key,
165 172 value_type,
166 173 default_value,
167 174 description='')
168 175 conf = (GraderConfiguration.find_by_key(key) ||
169 176 GraderConfiguration.new(:key => key,
170 177 :value_type => value_type,
171 178 :value => default_value))
172 179 conf.description = description
173 180 conf.save
174 181 end
175 182
176 183 def seed_config
177 184 CONFIGURATIONS.each do |conf|
178 185 if conf.has_key? :description
179 186 desc = conf[:description]
180 187 else
181 188 desc = ''
182 189 end
183 190 create_configuration_key(conf[:key],
184 191 conf[:value_type],
185 192 conf[:default_value],
186 193 desc)
187 194 end
188 195 end
189 196
190 197 def seed_roles
191 198 return if Role.find_by_name('admin')
192 199
193 200 role = Role.create(:name => 'admin')
194 201 user_admin_right = Right.create(:name => 'user_admin',
195 202 :controller => 'user_admin',
196 203 :action => 'all')
197 204 problem_admin_right = Right.create(:name=> 'problem_admin',
198 205 :controller => 'problems',
199 206 :action => 'all')
200 207
201 208 graders_right = Right.create(:name => 'graders_admin',
202 209 :controller => 'graders',
203 210 :action => 'all')
204 211
205 212 role.rights << user_admin_right;
206 213 role.rights << problem_admin_right;
207 214 role.rights << graders_right;
208 215 role.save
209 216 end
210 217
211 218 def seed_root
212 219 return if User.find_by_login('root')
213 220
214 221 root = User.new(:login => 'root',
215 222 :full_name => 'Administrator',
216 223 :alias => 'root')
217 224 root.password = 'ioionrails';
218 225
219 226 class << root
220 227 public :encrypt_new_password
221 228 def valid?(context=nil)
222 229 true
223 230 end
224 231 end
225 232
226 233 root.encrypt_new_password
227 234
228 235 root.roles << Role.find_by_name('admin')
229 236
230 237 root.activated = true
231 238 root.save
232 239 end
233 240
234 241 def seed_users_and_roles
235 242 seed_roles
236 243 seed_root
237 244 end
238 245
239 246 def seed_more_languages
240 247 Language.delete_all
241 248 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
242 249 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
243 250 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
244 251 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
245 252 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
246 253 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
247 254 end
248 255
249 256 seed_config
250 257 seed_users_and_roles
251 258 seed_more_languages
You need to be logged in to leave comments. Login now