Description:
Merge pull request #26 from cafe-grader-team/master merge edit from upstream
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r777:e61e522c673f - - 8 files changed: 79 inserted, 5 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,22 +1,24
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
@@ -51,13 +53,33
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
65 + def self.add_authenticator(authenticator)
66 + @@authenticators << authenticator
63 end
67 end
68 +
69 + protected
70 +
71 + def get_authenticated_user(login, password)
72 + if @@authenticators.empty?
73 + return User.authenticate(login, password)
74 + else
75 + user = User.authenticate(login, password)
76 + @@authenticators.each do |authenticator|
77 + if not user
78 + user = authenticator.authenticate(login, password)
79 + end
80 + end
81 + return user
82 + end
83 + end
84 +
85 + end
@@ -20,25 +20,25
20
20
21 def show
21 def show
22 @problem = Problem.find(params[:id])
22 @problem = Problem.find(params[:id])
23 end
23 end
24
24
25 def new
25 def new
26 @problem = Problem.new
26 @problem = Problem.new
27 @description = nil
27 @description = nil
28 end
28 end
29
29
30 def create
30 def create
31 @problem = Problem.new(problem_params)
31 @problem = Problem.new(problem_params)
32 - @description = Description.new(params[:description])
32 + @description = Description.new(description_params)
33 if @description.body!=''
33 if @description.body!=''
34 if !@description.save
34 if !@description.save
35 render :action => new and return
35 render :action => new and return
36 end
36 end
37 else
37 else
38 @description = nil
38 @description = nil
39 end
39 end
40 @problem.description = @description
40 @problem.description = @description
41 if @problem.save
41 if @problem.save
42 flash[:notice] = 'Problem was successfully created.'
42 flash[:notice] = 'Problem was successfully created.'
43 redirect_to action: :index
43 redirect_to action: :index
44 else
44 else
@@ -243,24 +243,28
243 def remove_contest
243 def remove_contest
244 problem = Problem.find(params[:id])
244 problem = Problem.find(params[:id])
245 contest = Contest.find(params[:contest_id])
245 contest = Contest.find(params[:contest_id])
246 if problem!=nil and contest!=nil
246 if problem!=nil and contest!=nil
247 problem.contests.delete(contest)
247 problem.contests.delete(contest)
248 end
248 end
249 redirect_to :action => 'manage'
249 redirect_to :action => 'manage'
250 end
250 end
251
251
252 ##################################
252 ##################################
253 protected
253 protected
254
254
255 + def description_params
256 + params.require(:description).permit(:body, :markdowned)
257 + end
258 +
255 def allow_test_pair_import?
259 def allow_test_pair_import?
256 if defined? ALLOW_TEST_PAIR_IMPORT
260 if defined? ALLOW_TEST_PAIR_IMPORT
257 return ALLOW_TEST_PAIR_IMPORT
261 return ALLOW_TEST_PAIR_IMPORT
258 else
262 else
259 return false
263 return false
260 end
264 end
261 end
265 end
262
266
263 def change_date_added
267 def change_date_added
264 problems = get_problems_from_params
268 problems = get_problems_from_params
265 date = Date.parse(params[:date_added])
269 date = Date.parse(params[:date_added])
266 problems.each do |p|
270 problems.each do |p|
@@ -118,37 +118,39
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
@@ -31,25 +31,25
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
@@ -50,25 +50,27
50 .col-md-12
50 .col-md-12
51 %h2 Console
51 %h2 Console
52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
52 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
53
53
54 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
54 .modal.fade#compiler{tabindex: -1,role: 'dialog'}
55 .modal-dialog.modal-lg{role:'document'}
55 .modal-dialog.modal-lg{role:'document'}
56 .modal-content
56 .modal-content
57 .modal-header
57 .modal-header
58 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
58 %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
59 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
59 %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
60 %h4 Compiler message
60 %h4 Compiler message
61 .modal-body
61 .modal-body
62 - %pre#compiler_msg= @submission.compiler_message
62 + %pre#compiler_msg
63 + - if @submission
64 + = @submission.compiler_message
63 .modal-footer
65 .modal-footer
64 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
66 %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
65
67
66 :javascript
68 :javascript
67 $(document).ready(function() {
69 $(document).ready(function() {
68 e = ace.edit("editor")
70 e = ace.edit("editor")
69 e.setValue($("#text_sourcecode").val());
71 e.setValue($("#text_sourcecode").val());
70 e.gotoLine(1);
72 e.gotoLine(1);
71 $("#language_id").trigger('change');
73 $("#language_id").trigger('change');
72
74
73 $("#load_file").on('change',function(evt) {
75 $("#load_file").on('change',function(evt) {
74 var file = evt.target.files[0];
76 var file = evt.target.files[0];
@@ -19,12 +19,15
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)
@@ -93,24 +93,32
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',
You need to be logged in to leave comments. Login now