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

r779:df983f8fc960 - - 8 files changed: 73 inserted, 10 deleted

@@ -0,0 +1,33
1 + # Authentication and user imports through programming.in.th web request
2 + require 'net/http'
3 + require 'uri'
4 + require 'json'
5 +
6 + class ProgrammingAuthenticator
7 + PROGRAMMING_AUTHEN_URL = "https://programming.in.th/authen.php"
8 +
9 + def find_or_create_user(result)
10 + user = User.find_by(login: result['username'])
11 + if not user
12 + user = User.new(login: result['username'],
13 + full_name: result['firstname'] + ' ' + result['surname'],
14 + alias: result['display'],
15 + email: result['email'])
16 + user.password = User.random_password
17 + user.save
18 + end
19 + return user
20 + end
21 +
22 + def authenticate(login, password)
23 + uri = URI(PROGRAMMING_AUTHEN_URL)
24 + result = Net::HTTP.post_form(uri, 'username' => login, 'password' => password)
25 + request_result = JSON.parse(result.body)
26 +
27 + if request_result.fetch('status', 'incorrect') == 'OK'
28 + return find_or_create_user(request_result)
29 + else
30 + return nil
31 + end
32 + end
33 + end
@@ -1,67 +1,89
1 1 class LoginController < ApplicationController
2 2
3 + @@authenticators = []
4 +
3 5 def index
4 6 # show login screen
5 7 reset_session
6 8 redirect_to :controller => 'main', :action => 'login'
7 9 end
8 10
9 11 def login
10 - user = User.authenticate(params[:login], params[:password])
12 + user = get_authenticated_user(params[:login], params[:password])
11 13 unless user
12 14 flash[:notice] = 'Wrong password'
13 15 redirect_to :controller => 'main', :action => 'login'
14 16 return
15 17 end
16 18
17 19 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
18 20 flash[:notice] = 'You must accept the agreement before logging in'
19 21 redirect_to :controller => 'main', :action => 'login'
20 22 return
21 23 end
22 24
23 25 #process logging in
24 26 session[:user_id] = user.id
25 27 session[:admin] = user.admin?
26 28
27 29 # clear forced logout flag for multicontests contest change
28 30 if GraderConfiguration.multicontests?
29 31 contest_stat = user.contest_stat
30 32 if contest_stat.respond_to? :forced_logout
31 33 if contest_stat.forced_logout
32 34 contest_stat.forced_logout = false
33 35 contest_stat.save
34 36 end
35 37 end
36 38 end
37 39
38 40 #save login information
39 41 Login.create(user_id: user.id, ip_address: request.remote_ip)
40 42
41 43 redirect_to :controller => 'main', :action => 'list'
42 44 end
43 45
44 46 def site_login
45 47 begin
46 48 site = Site.find(params[:login][:site_id])
47 49 rescue ActiveRecord::RecordNotFound
48 50 site = nil
49 51 end
50 52 if site==nil
51 53 flash[:notice] = 'Wrong site'
52 54 redirect_to :controller => 'main', :action => 'login' and return
53 55 end
54 56 if (site.password) and (site.password == params[:login][:password])
55 57 session[:site_id] = site.id
56 58 redirect_to :controller => 'site', :action => 'index'
57 59 else
58 60 flash[:notice] = 'Wrong site password'
59 61 redirect_to :controller => 'site', :action => 'login'
60 62 end
61 63 end
62 64
63 65 def logout
64 66 redirect_to root_path
65 67 end
66 68
69 + def self.add_authenticator(authenticator)
70 + @@authenticators << authenticator
67 71 end
72 +
73 + protected
74 +
75 + def get_authenticated_user(login, password)
76 + if @@authenticators.empty?
77 + return User.authenticate(login, password)
78 + else
79 + user = User.authenticate(login, password)
80 + @@authenticators.each do |authenticator|
81 + if not user
82 + user = authenticator.authenticate(login, password)
83 + end
84 + end
85 + return user
86 + end
87 + end
88 +
89 + end
@@ -1,125 +1,121
1 1 class ProblemsController < ApplicationController
2 2
3 3 before_action :admin_authorization
4 4
5 - #NOTE: ghost from the past?
6 - #before_action :testcase_authorization, only: [:show_testcase]
7 -
8 -
9 5 in_place_edit_for :problem, :name
10 6 in_place_edit_for :problem, :full_name
11 7 in_place_edit_for :problem, :full_score
12 8
13 9 def index
14 10 @problems = Problem.order(date_added: :desc)
15 11 end
16 12
17 13
18 14 def show
19 15 @problem = Problem.find(params[:id])
20 16 end
21 17
22 18 def new
23 19 @problem = Problem.new
24 20 @description = nil
25 21 end
26 22
27 23 def create
28 24 @problem = Problem.new(problem_params)
29 - @description = Description.new(problem_params[:description])
25 + @description = Description.new(description_params)
30 26 if @description.body!=''
31 27 if !@description.save
32 28 render :action => new and return
33 29 end
34 30 else
35 31 @description = nil
36 32 end
37 33 @problem.description = @description
38 34 if @problem.save
39 35 flash[:notice] = 'Problem was successfully created.'
40 36 redirect_to action: :index
41 37 else
42 38 render :action => 'new'
43 39 end
44 40 end
45 41
46 42 def quick_create
47 43 @problem = Problem.new(problem_params)
48 44 @problem.full_name = @problem.name if @problem.full_name == ''
49 45 @problem.full_score = 100
50 46 @problem.available = false
51 47 @problem.test_allowed = true
52 48 @problem.output_only = false
53 49 @problem.date_added = Time.new
54 50 if @problem.save
55 51 flash[:notice] = 'Problem was successfully created.'
56 52 redirect_to action: :index
57 53 else
58 54 flash[:notice] = 'Error saving problem'
59 55 redirect_to action: :index
60 56 end
61 57 end
62 58
63 59 def edit
64 60 @problem = Problem.find(params[:id])
65 61 @description = @problem.description
66 62 end
67 63
68 64 def update
69 65 @problem = Problem.find(params[:id])
70 66 @description = @problem.description
71 67 if @description.nil? and params[:description][:body]!=''
72 68 @description = Description.new(description_params)
73 69 if !@description.save
74 70 flash[:notice] = 'Error saving description'
75 71 render :action => 'edit' and return
76 72 end
77 73 @problem.description = @description
78 74 elsif @description
79 75 if !@description.update_attributes(description_params)
80 76 flash[:notice] = 'Error saving description'
81 77 render :action => 'edit' and return
82 78 end
83 79 end
84 80 if params[:file] and params[:file].content_type != 'application/pdf'
85 81 flash[:notice] = 'Error: Uploaded file is not PDF'
86 82 render :action => 'edit' and return
87 83 end
88 84 if @problem.update_attributes(problem_params)
89 85 flash[:notice] = 'Problem was successfully updated.'
90 86 unless params[:file] == nil or params[:file] == ''
91 87 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
92 88 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
93 89 if not FileTest.exists? out_dirname
94 90 Dir.mkdir out_dirname
95 91 end
96 92
97 93 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
98 94 if FileTest.exists? out_filename
99 95 File.delete out_filename
100 96 end
101 97
102 98 File.open(out_filename,"wb") do |file|
103 99 file.write(params[:file].read)
104 100 end
105 101 @problem.description_filename = "#{@problem.name}.pdf"
106 102 @problem.save
107 103 end
108 104 redirect_to :action => 'show', :id => @problem
109 105 else
110 106 render :action => 'edit'
111 107 end
112 108 end
113 109
114 110 def destroy
115 111 p = Problem.find(params[:id]).destroy
116 112 redirect_to action: :index
117 113 end
118 114
119 115 def toggle
120 116 @problem = Problem.find(params[:id])
121 117 @problem.update_attributes(available: !(@problem.available) )
122 118 respond_to do |format|
123 119 format.js { }
124 120 end
125 121 end
@@ -212,100 +208,100
212 208 end
213 209 end
214 210
215 211 redirect_to :action => 'manage'
216 212 end
217 213
218 214 def import
219 215 @allow_test_pair_import = allow_test_pair_import?
220 216 end
221 217
222 218 def do_import
223 219 old_problem = Problem.find_by_name(params[:name])
224 220 if !allow_test_pair_import? and params.has_key? :import_to_db
225 221 params.delete :import_to_db
226 222 end
227 223 @problem, import_log = Problem.create_from_import_form_params(params,
228 224 old_problem)
229 225
230 226 if !@problem.errors.empty?
231 227 render :action => 'import' and return
232 228 end
233 229
234 230 if old_problem!=nil
235 231 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
236 232 end
237 233 @log = import_log
238 234 end
239 235
240 236 def remove_contest
241 237 problem = Problem.find(params[:id])
242 238 contest = Contest.find(params[:contest_id])
243 239 if problem!=nil and contest!=nil
244 240 problem.contests.delete(contest)
245 241 end
246 242 redirect_to :action => 'manage'
247 243 end
248 244
249 245 ##################################
250 246 protected
251 247
252 248 def allow_test_pair_import?
253 249 if defined? ALLOW_TEST_PAIR_IMPORT
254 250 return ALLOW_TEST_PAIR_IMPORT
255 251 else
256 252 return false
257 253 end
258 254 end
259 255
260 256 def change_date_added
261 257 problems = get_problems_from_params
262 258 date = Date.parse(params[:date_added])
263 259 problems.each do |p|
264 260 p.date_added = date
265 261 p.save
266 262 end
267 263 end
268 264
269 265 def add_to_contest
270 266 problems = get_problems_from_params
271 267 contest = Contest.find(params[:contest][:id])
272 268 if contest!=nil and contest.enabled
273 269 problems.each do |p|
274 270 p.contests << contest
275 271 end
276 272 end
277 273 end
278 274
279 275 def set_available(avail)
280 276 problems = get_problems_from_params
281 277 problems.each do |p|
282 278 p.available = avail
283 279 p.save
284 280 end
285 281 end
286 282
287 283 def get_problems_from_params
288 284 problems = []
289 285 params.keys.each do |k|
290 286 if k.index('prob-')==0
291 287 name, id, order = k.split('-')
292 288 problems << Problem.find(id)
293 289 end
294 290 end
295 291 problems
296 292 end
297 293
298 294 def get_problems_stat
299 295 end
300 296
301 297 private
302 298
303 299 def problem_params
304 300 params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
305 301 end
306 302
307 303 def description_params
308 - params.require(:description).permit(:body, :markdown)
304 + params.require(:description).permit(:body, :markdowned)
309 305 end
310 306
311 307 end
@@ -34,133 +34,135
34 34
35 35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
36 36 records = Submission.where(problem_id: problem_id,user_id: user_id)
37 37 records = records.where('id >= ?',since_id) if since_id and since_id > 0
38 38 records = records.where('id <= ?',until_id) if until_id and until_id > 0
39 39 records.all
40 40 end
41 41
42 42 def self.find_last_for_all_available_problems(user_id)
43 43 submissions = Array.new
44 44 problems = Problem.available_problems
45 45 problems.each do |problem|
46 46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
47 47 submissions << sub if sub!=nil
48 48 end
49 49 submissions
50 50 end
51 51
52 52 def self.find_by_user_problem_number(user_id, problem_id, number)
53 53 where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
54 54 end
55 55
56 56 def self.find_all_by_user_problem(user_id, problem_id)
57 57 where("user_id = ? AND problem_id = ?",user_id,problem_id)
58 58 end
59 59
60 60 def download_filename
61 61 if self.problem.output_only
62 62 return self.source_filename
63 63 else
64 64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
65 65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
66 66 end
67 67 end
68 68
69 69 protected
70 70
71 71 def self.find_option_in_source(option, source)
72 72 if source==nil
73 73 return nil
74 74 end
75 75 i = 0
76 76 source.each_line do |s|
77 77 if s =~ option
78 78 words = s.split
79 79 return words[1]
80 80 end
81 81 i = i + 1
82 82 if i==10
83 83 return nil
84 84 end
85 85 end
86 86 return nil
87 87 end
88 88
89 89 def self.find_language_in_source(source, source_filename="")
90 90 langopt = find_option_in_source(/^LANG:/,source)
91 91 if langopt
92 92 return (Language.find_by_name(langopt) ||
93 93 Language.find_by_pretty_name(langopt))
94 94 else
95 95 if source_filename
96 96 return Language.find_by_extension(source_filename.split('.').last)
97 97 else
98 98 return nil
99 99 end
100 100 end
101 101 end
102 102
103 103 def self.find_problem_in_source(source, source_filename="")
104 104 prob_opt = find_option_in_source(/^TASK:/,source)
105 105 if problem = Problem.find_by_name(prob_opt)
106 106 return problem
107 107 else
108 108 if source_filename
109 109 return Problem.find_by_name(source_filename.split('.').first)
110 110 else
111 111 return nil
112 112 end
113 113 end
114 114 end
115 115
116 116 def assign_problem
117 117 if self.problem_id!=-1
118 118 begin
119 119 self.problem = Problem.find(self.problem_id)
120 120 rescue ActiveRecord::RecordNotFound
121 121 self.problem = nil
122 122 end
123 123 else
124 124 self.problem = Submission.find_problem_in_source(self.source,
125 125 self.source_filename)
126 126 end
127 127 end
128 128
129 129 def assign_language
130 + if self.language == nil
130 131 self.language = Submission.find_language_in_source(self.source,
131 132 self.source_filename)
132 133 end
134 + end
133 135
134 136 # validation codes
135 137 def must_specify_language
136 138 return if self.source==nil
137 139
138 140 # for output_only tasks
139 141 return if self.problem!=nil and self.problem.output_only
140 142
141 143 if self.language==nil
142 - errors.add('source',"Cannot detect language. Did you submit a correct source file?") unless self.language!=nil
144 + errors.add('source',"Cannot detect language. Did you submit a correct source file?")
143 145 end
144 146 end
145 147
146 148 def must_have_valid_problem
147 149 return if self.source==nil
148 150 if self.problem==nil
149 151 errors.add('problem',"must be specified.")
150 152 else
151 153 #admin always have right
152 154 return if self.user.admin?
153 155
154 156 #check if user has the right to submit the problem
155 157 errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
156 158 end
157 159 end
158 160
159 161 # callbacks
160 162 def assign_latest_number_if_new_recond
161 163 return if !self.new_record?
162 164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
163 165 self.number = (latest==nil) ? 1 : latest.number + 1;
164 166 end
165 167
166 168 end
@@ -1,139 +1,139
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_and_belongs_to_many :groups
12 12 has_many :groups_users, class_name: 'GroupUser'
13 13 has_many :groups, :through => :groups_users
14 14
15 15 has_many :test_requests, -> {order(submitted_at: :desc)}
16 16
17 17 has_many :messages, -> { order(created_at: :desc) },
18 18 :class_name => "Message",
19 19 :foreign_key => "sender_id"
20 20
21 21 has_many :replied_messages, -> { order(created_at: :desc) },
22 22 :class_name => "Message",
23 23 :foreign_key => "receiver_id"
24 24
25 25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26 26
27 27 belongs_to :site
28 28 belongs_to :country
29 29
30 30 has_and_belongs_to_many :contests, -> { order(:name)}
31 31
32 32 scope :activated_users, -> {where activated: true}
33 33
34 34 validates_presence_of :login
35 35 validates_uniqueness_of :login
36 36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 37 validates_length_of :login, :within => 3..30
38 38
39 39 validates_presence_of :full_name
40 40 validates_length_of :full_name, :minimum => 1
41 41
42 42 validates_presence_of :password, :if => :password_required?
43 - validates_length_of :password, :within => 4..20, :if => :password_required?
43 + validates_length_of :password, :within => 4..50, :if => :password_required?
44 44 validates_confirmation_of :password, :if => :password_required?
45 45
46 46 validates_format_of :email,
47 47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 48 :if => :email_validation?
49 49 validate :uniqueness_of_email_from_activated_users,
50 50 :if => :email_validation?
51 51 validate :enough_time_interval_between_same_email_registrations,
52 52 :if => :email_validation?
53 53
54 54 # these are for ytopc
55 55 # disable for now
56 56 #validates_presence_of :province
57 57
58 58 attr_accessor :password
59 59
60 60 before_save :encrypt_new_password
61 61 before_save :assign_default_site
62 62 before_save :assign_default_contest
63 63
64 64 # this is for will_paginate
65 65 cattr_reader :per_page
66 66 @@per_page = 50
67 67
68 68 def self.authenticate(login, password)
69 69 user = find_by_login(login)
70 70 if user
71 71 return user if user.authenticated?(password)
72 72 end
73 73 end
74 74
75 75 def authenticated?(password)
76 76 if self.activated
77 77 hashed_password == User.encrypt(password,self.salt)
78 78 else
79 79 false
80 80 end
81 81 end
82 82
83 83 def admin?
84 84 self.roles.where(name: 'admin').count > 0
85 85 end
86 86
87 87 def email_for_editing
88 88 if self.email==nil
89 89 "(unknown)"
90 90 elsif self.email==''
91 91 "(blank)"
92 92 else
93 93 self.email
94 94 end
95 95 end
96 96
97 97 def email_for_editing=(e)
98 98 self.email=e
99 99 end
100 100
101 101 def alias_for_editing
102 102 if self.alias==nil
103 103 "(unknown)"
104 104 elsif self.alias==''
105 105 "(blank)"
106 106 else
107 107 self.alias
108 108 end
109 109 end
110 110
111 111 def alias_for_editing=(e)
112 112 self.alias=e
113 113 end
114 114
115 115 def activation_key
116 116 if self.hashed_password==nil
117 117 encrypt_new_password
118 118 end
119 119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
120 120 end
121 121
122 122 def verify_activation_key(key)
123 123 key == activation_key
124 124 end
125 125
126 126 def self.random_password(length=5)
127 127 chars = 'abcdefghjkmnopqrstuvwxyz'
128 128 password = ''
129 129 length.times { password << chars[rand(chars.length - 1)] }
130 130 password
131 131 end
132 132
133 133 def self.find_non_admin_with_prefix(prefix='')
134 134 users = User.all
135 135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
136 136 end
137 137
138 138 # Contest information
139 139
@@ -1,88 +1,87
1 1 %textarea#text_sourcecode{style: "display:none"}~ @source
2 2 .container
3 3 .row
4 4 .col-md-12
5 5 %h2 Live submit
6 6
7 7 .row
8 8 .col-md-12
9 9 .alert.alert-info
10 10 Write your code in the following box, choose language, and click submit button when finished
11 11 .row
12 12 .col-md-8
13 13 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
14 14 .col-md-4
15 15 - # submission form
16 16 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
17 17
18 18 = hidden_field_tag 'editor_text', @source
19 19 = hidden_field_tag 'submission[problem_id]', @problem.id
20 20 .form-group
21 21 = label_tag "Task:"
22 22 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
23 23 .form-group
24 24 = label_tag "Description:"
25 25 = link_to_description_if_any "[download] <span class='glyphicon glyphicon-file'></span>".html_safe, @problem
26 26
27 27 .form-group
28 28 = label_tag 'Language:'
29 29 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
30 30 .form-group
31 31 .input-group
32 32 %span.input-group-btn
33 33 %span.btn.btn-default.btn-file
34 34 Browse
35 35 = file_field_tag 'load_file'
36 36 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
37 37 .form-group
38 38 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
39 39 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
40 40 - # latest submission status
41 41 .panel{class: (@submission && @submission.graded_at) ? "panel-info" : "panel-warning"}
42 42 .panel-heading
43 43 Latest Submission Status
44 44 = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
45 45 .panel-body
46 46 %div#latest_status
47 47 - if @submission
48 48 = render :partial => 'submission_short',
49 49 :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
50 50
51 51 - if @submission
52 52 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
53 53 .modal-dialog.modal-lg{role:'document'}
54 54 .modal-content
55 55 .modal-header
56 56 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
57 57 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
58 58 %h4 Compiler message
59 59 .modal-body
60 60 %pre#compiler_msg= @submission.compiler_message
61 61 .modal-footer
62 62 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
63 63
64 64 :javascript
65 65 $(document).ready(function() {
66 66 e = ace.edit("editor")
67 67 e.setValue($("#text_sourcecode").val());
68 68 e.gotoLine(1);
69 69 $("#language_id").trigger('change');
70 70
71 71 $("#load_file").on('change',function(evt) {
72 72 var file = evt.target.files[0];
73 73 var reader = new FileReader();
74 74 reader.onload = function(theFile) {
75 75 var e = ace.edit("editor")
76 76 e.setValue(theFile.target.result);
77 77 e.gotoLine(1);
78 78 };
79 79 reader.readAsText(file)
80 80 });
81 81
82 82 //brython();
83 83 });
84 84
85 85
86 86
87 87
88 -
@@ -1,30 +1,33
1 1 # If you want to manage graders through web interface, set the path to
2 2 # the grader directory below. This dir is where raw, ev, ev-exam,
3 3 # scripts reside. All grader scripts will be in
4 4 # #{GRADER_ROOT_DIR}/scripts.
5 5 GRADER_ROOT_DIR = ''
6 6
7 7 # These are where inputs and outputs of test requests are stored
8 8 TEST_REQUEST_INPUT_FILE_DIR = (Rails.root + 'data/test_request/input').to_s
9 9 TEST_REQUEST_OUTPUT_FILE_DIR = (Rails.root + 'data/test_request/output').to_s
10 10
11 11 # To use ANALYSIS MODE, provide the testcases/testruns breakdown,
12 12 # and the directory of the grading result (usually in judge's dir).
13 13 TASK_GRADING_INFO_FILENAME = Rails.root + 'config/tasks.yml'
14 14
15 15 # TODO: change this to where results are kept.
16 16 GRADING_RESULT_DIR = 'RESULT-DIR'
17 17
18 18 # Change this to allow importing testdata into database as test-pairs.
19 19 # This is mainly for Code Jom contest.
20 20 ALLOW_TEST_PAIR_IMPORT = false
21 21
22 22 # Uncomment so that the system validates user e-mails
23 23 # VALIDATE_USER_EMAILS = true
24 24
25 25 # Uncomment so that Apache X-Sendfile is used when delivering files
26 26 # (e.g., in /tasks/view).
27 27 # USE_APACHE_XSENDFILE = true
28 28
29 29 # Uncomment so that configuration is read only once when the server is loaded
30 30 # CONFIGURATION_CACHE_ENABLED = true
31 +
32 + # Uncomment to allow authentication and user import from programming.in.th
33 + # LoginController.add_authenticator(ProgrammingAuthenticator.new)
@@ -9,192 +9,200
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 93 :key => 'right.heartbeat_response_full',
94 94 :value_type => 'string',
95 95 :default_value => 'OK',
96 96 :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
97 97 },
98 98
99 99 {
100 100 :key => 'right.view_testcase',
101 101 :value_type => 'boolean',
102 102 :default_value => 'false',
103 103 :description => 'When true, any user can view/download test data'
104 104 },
105 +
106 + {
107 + :key => 'system.online_registration',
108 + :value_type => 'boolean',
109 + :default_value => 'false',
110 + :description => 'This option enables online registration.'
111 + },
112 +
105 113 # If Configuration['system.online_registration'] is true, the
106 114 # system allows online registration, and will use these
107 115 # information for sending confirmation emails.
108 116 {
109 117 :key => 'system.online_registration.smtp',
110 118 :value_type => 'string',
111 119 :default_value => 'smtp.somehost.com'
112 120 },
113 121
114 122 {
115 123 :key => 'system.online_registration.from',
116 124 :value_type => 'string',
117 125 :default_value => 'your.email@address'
118 126 },
119 127
120 128 {
121 129 :key => 'system.admin_email',
122 130 :value_type => 'string',
123 131 :default_value => 'admin@admin.email'
124 132 },
125 133
126 134 {
127 135 :key => 'system.user_setting_enabled',
128 136 :value_type => 'boolean',
129 137 :default_value => 'true',
130 138 :description => 'If this option is true, users can change their settings'
131 139 },
132 140
133 141 {
134 142 :key => 'system.user_setting_enabled',
135 143 :value_type => 'boolean',
136 144 :default_value => 'true',
137 145 :description => 'If this option is true, users can change their settings'
138 146 },
139 147
140 148 # If Configuration['contest.test_request.early_timeout'] is true
141 149 # the user will not be able to use test request at 30 minutes
142 150 # before the contest ends.
143 151 {
144 152 :key => 'contest.test_request.early_timeout',
145 153 :value_type => 'boolean',
146 154 :default_value => 'false'
147 155 },
148 156
149 157 {
150 158 :key => 'system.multicontests',
151 159 :value_type => 'boolean',
152 160 :default_value => 'false'
153 161 },
154 162
155 163 {
156 164 :key => 'contest.confirm_indv_contest_start',
157 165 :value_type => 'boolean',
158 166 :default_value => 'false'
159 167 },
160 168
161 169 {
162 170 :key => 'contest.default_contest_name',
163 171 :value_type => 'string',
164 172 :default_value => 'none',
165 173 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
166 174 },
167 175
168 176 {
169 177 :key => 'system.use_problem_group',
170 178 :value_type => 'boolean',
171 179 :default_value => 'false',
172 180 :description => "If true, available problem to the user will be only ones associated with the group of the user."
173 181 },
174 182
175 183
176 184 {
177 185 :key => 'right.whitelist_ip_only',
178 186 :value_type => 'boolean',
179 187 :default_value => 'false',
180 188 :description => "If true, non-admin user will be able to use the system only when their ip is in the 'whitelist_ip'."
181 189 },
182 190
183 191 {
184 192 :key => 'right.whitelist_ip',
185 193 :value_type => 'string',
186 194 :default_value => '0.0.0.0/0',
187 195 :description => "list of whitelist ip, given in comma separated CIDR notation. For example '161.200.92.0/23, 161.200.80.1/32'"
188 196 },
189 197
190 198 ]
191 199
192 200
193 201 def create_configuration_key(key,
194 202 value_type,
195 203 default_value,
196 204 description='')
197 205 conf = (GraderConfiguration.find_by_key(key) ||
198 206 GraderConfiguration.new(:key => key,
199 207 :value_type => value_type,
200 208 :value => default_value))
You need to be logged in to leave comments. Login now