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,34 +1,36
1 class LoginController < ApplicationController
1 class LoginController < ApplicationController
2
2
3 + @@authenticators = []
4 +
3 def index
5 def index
4 # show login screen
6 # show login screen
5 reset_session
7 reset_session
6 redirect_to :controller => 'main', :action => 'login'
8 redirect_to :controller => 'main', :action => 'login'
7 end
9 end
8
10
9 def login
11 def login
10 - user = User.authenticate(params[:login], params[:password])
12 + user = get_authenticated_user(params[:login], params[:password])
11 unless user
13 unless user
12 flash[:notice] = 'Wrong password'
14 flash[:notice] = 'Wrong password'
13 redirect_to :controller => 'main', :action => 'login'
15 redirect_to :controller => 'main', :action => 'login'
14 return
16 return
15 end
17 end
16
18
17 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
19 if (!GraderConfiguration['right.bypass_agreement']) and (!params[:accept_agree]) and !user.admin?
18 flash[:notice] = 'You must accept the agreement before logging in'
20 flash[:notice] = 'You must accept the agreement before logging in'
19 redirect_to :controller => 'main', :action => 'login'
21 redirect_to :controller => 'main', :action => 'login'
20 return
22 return
21 end
23 end
22
24
23 #process logging in
25 #process logging in
24 session[:user_id] = user.id
26 session[:user_id] = user.id
25 session[:admin] = user.admin?
27 session[:admin] = user.admin?
26
28
27 # clear forced logout flag for multicontests contest change
29 # clear forced logout flag for multicontests contest change
28 if GraderConfiguration.multicontests?
30 if GraderConfiguration.multicontests?
29 contest_stat = user.contest_stat
31 contest_stat = user.contest_stat
30 if contest_stat.respond_to? :forced_logout
32 if contest_stat.respond_to? :forced_logout
31 if contest_stat.forced_logout
33 if contest_stat.forced_logout
32 contest_stat.forced_logout = false
34 contest_stat.forced_logout = false
33 contest_stat.save
35 contest_stat.save
34 end
36 end
@@ -43,25 +45,45
43
45
44 def site_login
46 def site_login
45 begin
47 begin
46 site = Site.find(params[:login][:site_id])
48 site = Site.find(params[:login][:site_id])
47 rescue ActiveRecord::RecordNotFound
49 rescue ActiveRecord::RecordNotFound
48 site = nil
50 site = nil
49 end
51 end
50 if site==nil
52 if site==nil
51 flash[:notice] = 'Wrong site'
53 flash[:notice] = 'Wrong site'
52 redirect_to :controller => 'main', :action => 'login' and return
54 redirect_to :controller => 'main', :action => 'login' and return
53 end
55 end
54 if (site.password) and (site.password == params[:login][:password])
56 if (site.password) and (site.password == params[:login][:password])
55 session[:site_id] = site.id
57 session[:site_id] = site.id
56 redirect_to :controller => 'site', :action => 'index'
58 redirect_to :controller => 'site', :action => 'index'
57 else
59 else
58 flash[:notice] = 'Wrong site password'
60 flash[:notice] = 'Wrong site password'
59 redirect_to :controller => 'site', :action => 'login'
61 redirect_to :controller => 'site', :action => 'login'
60 end
62 end
61 end
63 end
62
64
63 def logout
65 def logout
64 redirect_to root_path
66 redirect_to root_path
65 end
67 end
66
68
69 + def self.add_authenticator(authenticator)
70 + @@authenticators << authenticator
67 end
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,53 +1,49
1 class ProblemsController < ApplicationController
1 class ProblemsController < ApplicationController
2
2
3 before_action :admin_authorization
3 before_action :admin_authorization
4
4
5 - #NOTE: ghost from the past?
6 - #before_action :testcase_authorization, only: [:show_testcase]
7 -
8 -
9 in_place_edit_for :problem, :name
5 in_place_edit_for :problem, :name
10 in_place_edit_for :problem, :full_name
6 in_place_edit_for :problem, :full_name
11 in_place_edit_for :problem, :full_score
7 in_place_edit_for :problem, :full_score
12
8
13 def index
9 def index
14 @problems = Problem.order(date_added: :desc)
10 @problems = Problem.order(date_added: :desc)
15 end
11 end
16
12
17
13
18 def show
14 def show
19 @problem = Problem.find(params[:id])
15 @problem = Problem.find(params[:id])
20 end
16 end
21
17
22 def new
18 def new
23 @problem = Problem.new
19 @problem = Problem.new
24 @description = nil
20 @description = nil
25 end
21 end
26
22
27 def create
23 def create
28 @problem = Problem.new(problem_params)
24 @problem = Problem.new(problem_params)
29 - @description = Description.new(problem_params[:description])
25 + @description = Description.new(description_params)
30 if @description.body!=''
26 if @description.body!=''
31 if !@description.save
27 if !@description.save
32 render :action => new and return
28 render :action => new and return
33 end
29 end
34 else
30 else
35 @description = nil
31 @description = nil
36 end
32 end
37 @problem.description = @description
33 @problem.description = @description
38 if @problem.save
34 if @problem.save
39 flash[:notice] = 'Problem was successfully created.'
35 flash[:notice] = 'Problem was successfully created.'
40 redirect_to action: :index
36 redirect_to action: :index
41 else
37 else
42 render :action => 'new'
38 render :action => 'new'
43 end
39 end
44 end
40 end
45
41
46 def quick_create
42 def quick_create
47 @problem = Problem.new(problem_params)
43 @problem = Problem.new(problem_params)
48 @problem.full_name = @problem.name if @problem.full_name == ''
44 @problem.full_name = @problem.name if @problem.full_name == ''
49 @problem.full_score = 100
45 @problem.full_score = 100
50 @problem.available = false
46 @problem.available = false
51 @problem.test_allowed = true
47 @problem.test_allowed = true
52 @problem.output_only = false
48 @problem.output_only = false
53 @problem.date_added = Time.new
49 @problem.date_added = Time.new
@@ -284,28 +280,28
284 end
280 end
285 end
281 end
286
282
287 def get_problems_from_params
283 def get_problems_from_params
288 problems = []
284 problems = []
289 params.keys.each do |k|
285 params.keys.each do |k|
290 if k.index('prob-')==0
286 if k.index('prob-')==0
291 name, id, order = k.split('-')
287 name, id, order = k.split('-')
292 problems << Problem.find(id)
288 problems << Problem.find(id)
293 end
289 end
294 end
290 end
295 problems
291 problems
296 end
292 end
297
293
298 def get_problems_stat
294 def get_problems_stat
299 end
295 end
300
296
301 private
297 private
302
298
303 def problem_params
299 def problem_params
304 params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
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 end
301 end
306
302
307 def description_params
303 def description_params
308 - params.require(:description).permit(:body, :markdown)
304 + params.require(:description).permit(:body, :markdowned)
309 end
305 end
310
306
311 end
307 end
@@ -106,61 +106,63
106 return problem
106 return problem
107 else
107 else
108 if source_filename
108 if source_filename
109 return Problem.find_by_name(source_filename.split('.').first)
109 return Problem.find_by_name(source_filename.split('.').first)
110 else
110 else
111 return nil
111 return nil
112 end
112 end
113 end
113 end
114 end
114 end
115
115
116 def assign_problem
116 def assign_problem
117 if self.problem_id!=-1
117 if self.problem_id!=-1
118 begin
118 begin
119 self.problem = Problem.find(self.problem_id)
119 self.problem = Problem.find(self.problem_id)
120 rescue ActiveRecord::RecordNotFound
120 rescue ActiveRecord::RecordNotFound
121 self.problem = nil
121 self.problem = nil
122 end
122 end
123 else
123 else
124 self.problem = Submission.find_problem_in_source(self.source,
124 self.problem = Submission.find_problem_in_source(self.source,
125 self.source_filename)
125 self.source_filename)
126 end
126 end
127 end
127 end
128
128
129 def assign_language
129 def assign_language
130 + if self.language == nil
130 self.language = Submission.find_language_in_source(self.source,
131 self.language = Submission.find_language_in_source(self.source,
131 self.source_filename)
132 self.source_filename)
132 end
133 end
134 + end
133
135
134 # validation codes
136 # validation codes
135 def must_specify_language
137 def must_specify_language
136 return if self.source==nil
138 return if self.source==nil
137
139
138 # for output_only tasks
140 # for output_only tasks
139 return if self.problem!=nil and self.problem.output_only
141 return if self.problem!=nil and self.problem.output_only
140
142
141 if self.language==nil
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 end
145 end
144 end
146 end
145
147
146 def must_have_valid_problem
148 def must_have_valid_problem
147 return if self.source==nil
149 return if self.source==nil
148 if self.problem==nil
150 if self.problem==nil
149 errors.add('problem',"must be specified.")
151 errors.add('problem',"must be specified.")
150 else
152 else
151 #admin always have right
153 #admin always have right
152 return if self.user.admin?
154 return if self.user.admin?
153
155
154 #check if user has the right to submit the problem
156 #check if user has the right to submit the problem
155 errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
157 errors.add('problem',"must be valid.") if (!self.user.available_problems.include?(self.problem)) and (self.new_record?)
156 end
158 end
157 end
159 end
158
160
159 # callbacks
161 # callbacks
160 def assign_latest_number_if_new_recond
162 def assign_latest_number_if_new_recond
161 return if !self.new_record?
163 return if !self.new_record?
162 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
164 latest = Submission.find_last_by_user_and_problem(self.user_id, self.problem_id)
163 self.number = (latest==nil) ? 1 : latest.number + 1;
165 self.number = (latest==nil) ? 1 : latest.number + 1;
164 end
166 end
165
167
166 end
168 end
@@ -19,49 +19,49
19 :foreign_key => "sender_id"
19 :foreign_key => "sender_id"
20
20
21 has_many :replied_messages, -> { order(created_at: :desc) },
21 has_many :replied_messages, -> { order(created_at: :desc) },
22 :class_name => "Message",
22 :class_name => "Message",
23 :foreign_key => "receiver_id"
23 :foreign_key => "receiver_id"
24
24
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26
26
27 belongs_to :site
27 belongs_to :site
28 belongs_to :country
28 belongs_to :country
29
29
30 has_and_belongs_to_many :contests, -> { order(:name)}
30 has_and_belongs_to_many :contests, -> { order(:name)}
31
31
32 scope :activated_users, -> {where activated: true}
32 scope :activated_users, -> {where activated: true}
33
33
34 validates_presence_of :login
34 validates_presence_of :login
35 validates_uniqueness_of :login
35 validates_uniqueness_of :login
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 validates_length_of :login, :within => 3..30
37 validates_length_of :login, :within => 3..30
38
38
39 validates_presence_of :full_name
39 validates_presence_of :full_name
40 validates_length_of :full_name, :minimum => 1
40 validates_length_of :full_name, :minimum => 1
41
41
42 validates_presence_of :password, :if => :password_required?
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 validates_confirmation_of :password, :if => :password_required?
44 validates_confirmation_of :password, :if => :password_required?
45
45
46 validates_format_of :email,
46 validates_format_of :email,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 :if => :email_validation?
48 :if => :email_validation?
49 validate :uniqueness_of_email_from_activated_users,
49 validate :uniqueness_of_email_from_activated_users,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :enough_time_interval_between_same_email_registrations,
51 validate :enough_time_interval_between_same_email_registrations,
52 :if => :email_validation?
52 :if => :email_validation?
53
53
54 # these are for ytopc
54 # these are for ytopc
55 # disable for now
55 # disable for now
56 #validates_presence_of :province
56 #validates_presence_of :province
57
57
58 attr_accessor :password
58 attr_accessor :password
59
59
60 before_save :encrypt_new_password
60 before_save :encrypt_new_password
61 before_save :assign_default_site
61 before_save :assign_default_site
62 before_save :assign_default_contest
62 before_save :assign_default_contest
63
63
64 # this is for will_paginate
64 # this is for will_paginate
65 cattr_reader :per_page
65 cattr_reader :per_page
66 @@per_page = 50
66 @@per_page = 50
67
67
@@ -64,25 +64,24
64 :javascript
64 :javascript
65 $(document).ready(function() {
65 $(document).ready(function() {
66 e = ace.edit("editor")
66 e = ace.edit("editor")
67 e.setValue($("#text_sourcecode").val());
67 e.setValue($("#text_sourcecode").val());
68 e.gotoLine(1);
68 e.gotoLine(1);
69 $("#language_id").trigger('change');
69 $("#language_id").trigger('change');
70
70
71 $("#load_file").on('change',function(evt) {
71 $("#load_file").on('change',function(evt) {
72 var file = evt.target.files[0];
72 var file = evt.target.files[0];
73 var reader = new FileReader();
73 var reader = new FileReader();
74 reader.onload = function(theFile) {
74 reader.onload = function(theFile) {
75 var e = ace.edit("editor")
75 var e = ace.edit("editor")
76 e.setValue(theFile.target.result);
76 e.setValue(theFile.target.result);
77 e.gotoLine(1);
77 e.gotoLine(1);
78 };
78 };
79 reader.readAsText(file)
79 reader.readAsText(file)
80 });
80 });
81
81
82 //brython();
82 //brython();
83 });
83 });
84
84
85
85
86
86
87
87
88 -
@@ -7,24 +7,27
7 # These are where inputs and outputs of test requests are stored
7 # These are where inputs and outputs of test requests are stored
8 TEST_REQUEST_INPUT_FILE_DIR = (Rails.root + 'data/test_request/input').to_s
8 TEST_REQUEST_INPUT_FILE_DIR = (Rails.root + 'data/test_request/input').to_s
9 TEST_REQUEST_OUTPUT_FILE_DIR = (Rails.root + 'data/test_request/output').to_s
9 TEST_REQUEST_OUTPUT_FILE_DIR = (Rails.root + 'data/test_request/output').to_s
10
10
11 # To use ANALYSIS MODE, provide the testcases/testruns breakdown,
11 # To use ANALYSIS MODE, provide the testcases/testruns breakdown,
12 # and the directory of the grading result (usually in judge's dir).
12 # and the directory of the grading result (usually in judge's dir).
13 TASK_GRADING_INFO_FILENAME = Rails.root + 'config/tasks.yml'
13 TASK_GRADING_INFO_FILENAME = Rails.root + 'config/tasks.yml'
14
14
15 # TODO: change this to where results are kept.
15 # TODO: change this to where results are kept.
16 GRADING_RESULT_DIR = 'RESULT-DIR'
16 GRADING_RESULT_DIR = 'RESULT-DIR'
17
17
18 # Change this to allow importing testdata into database as test-pairs.
18 # Change this to allow importing testdata into database as test-pairs.
19 # This is mainly for Code Jom contest.
19 # This is mainly for Code Jom contest.
20 ALLOW_TEST_PAIR_IMPORT = false
20 ALLOW_TEST_PAIR_IMPORT = false
21
21
22 # Uncomment so that the system validates user e-mails
22 # Uncomment so that the system validates user e-mails
23 # VALIDATE_USER_EMAILS = true
23 # VALIDATE_USER_EMAILS = true
24
24
25 # Uncomment so that Apache X-Sendfile is used when delivering files
25 # Uncomment so that Apache X-Sendfile is used when delivering files
26 # (e.g., in /tasks/view).
26 # (e.g., in /tasks/view).
27 # USE_APACHE_XSENDFILE = true
27 # USE_APACHE_XSENDFILE = true
28
28
29 # Uncomment so that configuration is read only once when the server is loaded
29 # Uncomment so that configuration is read only once when the server is loaded
30 # CONFIGURATION_CACHE_ENABLED = true
30 # CONFIGURATION_CACHE_ENABLED = true
31 +
32 + # Uncomment to allow authentication and user import from programming.in.th
33 + # LoginController.add_authenticator(ProgrammingAuthenticator.new)
@@ -81,48 +81,56
81 :default_value => 'true',
81 :default_value => 'true',
82 :description => 'When false, a user must accept usage agreement before login'
82 :description => 'When false, a user must accept usage agreement before login'
83 },
83 },
84
84
85 {
85 {
86 :key => 'right.heartbeat_response',
86 :key => 'right.heartbeat_response',
87 :value_type => 'string',
87 :value_type => 'string',
88 :default_value => 'OK',
88 :default_value => 'OK',
89 :description => 'Heart beat response text'
89 :description => 'Heart beat response text'
90 },
90 },
91
91
92 {
92 {
93 :key => 'right.heartbeat_response_full',
93 :key => 'right.heartbeat_response_full',
94 :value_type => 'string',
94 :value_type => 'string',
95 :default_value => 'OK',
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)'
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 :key => 'right.view_testcase',
100 :key => 'right.view_testcase',
101 :value_type => 'boolean',
101 :value_type => 'boolean',
102 :default_value => 'false',
102 :default_value => 'false',
103 :description => 'When true, any user can view/download test data'
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 # If Configuration['system.online_registration'] is true, the
113 # If Configuration['system.online_registration'] is true, the
106 # system allows online registration, and will use these
114 # system allows online registration, and will use these
107 # information for sending confirmation emails.
115 # information for sending confirmation emails.
108 {
116 {
109 :key => 'system.online_registration.smtp',
117 :key => 'system.online_registration.smtp',
110 :value_type => 'string',
118 :value_type => 'string',
111 :default_value => 'smtp.somehost.com'
119 :default_value => 'smtp.somehost.com'
112 },
120 },
113
121
114 {
122 {
115 :key => 'system.online_registration.from',
123 :key => 'system.online_registration.from',
116 :value_type => 'string',
124 :value_type => 'string',
117 :default_value => 'your.email@address'
125 :default_value => 'your.email@address'
118 },
126 },
119
127
120 {
128 {
121 :key => 'system.admin_email',
129 :key => 'system.admin_email',
122 :value_type => 'string',
130 :value_type => 'string',
123 :default_value => 'admin@admin.email'
131 :default_value => 'admin@admin.email'
124 },
132 },
125
133
126 {
134 {
127 :key => 'system.user_setting_enabled',
135 :key => 'system.user_setting_enabled',
128 :value_type => 'boolean',
136 :value_type => 'boolean',
You need to be logged in to leave comments. Login now