Description:
use uuid cookie
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r852:41c96ab8e589 - - 3 files changed: 20 inserted, 2 deleted

@@ -1,243 +1,251
1 require 'ipaddr'
1 require 'ipaddr'
2 + require "securerandom"
2
3
3 class ApplicationController < ActionController::Base
4 class ApplicationController < ActionController::Base
4 protect_from_forgery
5 protect_from_forgery
5
6
6 before_action :current_user
7 before_action :current_user
7 before_action :nav_announcement
8 before_action :nav_announcement
9 + before_action :unique_visitor_id
8
10
9 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
11 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
10 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
12 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
11 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
13 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
12 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
14 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
13
15
14 #report and redirect for unauthorized activities
16 #report and redirect for unauthorized activities
15 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
17 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
16 flash[:notice] = notice
18 flash[:notice] = notice
17 redirect_to login_main_path
19 redirect_to login_main_path
18 end
20 end
19
21
20 # Returns the current logged-in user (if any).
22 # Returns the current logged-in user (if any).
21 def current_user
23 def current_user
22 return nil unless session[:user_id]
24 return nil unless session[:user_id]
23 @current_user ||= User.find(session[:user_id])
25 @current_user ||= User.find(session[:user_id])
24 end
26 end
25
27
26 def nav_announcement
28 def nav_announcement
27 @nav_announcement = Announcement.where(on_nav_bar: true)
29 @nav_announcement = Announcement.where(on_nav_bar: true)
28 end
30 end
29
31
30 def admin_authorization
32 def admin_authorization
31 return false unless check_valid_login
33 return false unless check_valid_login
32 user = User.includes(:roles).find(session[:user_id])
34 user = User.includes(:roles).find(session[:user_id])
33 unless user.admin?
35 unless user.admin?
34 unauthorized_redirect
36 unauthorized_redirect
35 return false
37 return false
36 end
38 end
37 return true
39 return true
38 end
40 end
39
41
40 def authorization_by_roles(allowed_roles)
42 def authorization_by_roles(allowed_roles)
41 return false unless check_valid_login
43 return false unless check_valid_login
42 unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
44 unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) }
43 unauthorized_redirect
45 unauthorized_redirect
44 return false
46 return false
45 end
47 end
46 end
48 end
47
49
48 def testcase_authorization
50 def testcase_authorization
49 #admin always has privileged
51 #admin always has privileged
50 if @current_user.admin?
52 if @current_user.admin?
51 return true
53 return true
52 end
54 end
53
55
54 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
56 unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
55 end
57 end
56
58
59 + def unique_visitor_id
60 + unless cookies[:uuid]
61 + value = SecureRandom.uuid
62 + cookies[:uuid] = { value: value, expires: 20.year }
63 + end
64 + end
57
65
58 protected
66 protected
59
67
60 #redirect to root (and also force logout)
68 #redirect to root (and also force logout)
61 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
69 #if the user is not logged_in or the system is in "ADMIN ONLY" mode
62 def check_valid_login
70 def check_valid_login
63 #check if logged in
71 #check if logged in
64 unless session[:user_id]
72 unless session[:user_id]
65 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
73 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
66 unauthorized_redirect('You need to login but you cannot log in at this time')
74 unauthorized_redirect('You need to login but you cannot log in at this time')
67 else
75 else
68 unauthorized_redirect('You need to login')
76 unauthorized_redirect('You need to login')
69 end
77 end
70 return false
78 return false
71 end
79 end
72
80
73 # check if run in single user mode
81 # check if run in single user mode
74 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
82 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
75 if @current_user==nil || (!@current_user.admin?)
83 if @current_user==nil || (!@current_user.admin?)
76 unauthorized_redirect('You cannot log in at this time')
84 unauthorized_redirect('You cannot log in at this time')
77 return false
85 return false
78 end
86 end
79 end
87 end
80
88
81 # check if the user is enabled
89 # check if the user is enabled
82 unless @current_user.enabled? || @current_user.admin?
90 unless @current_user.enabled? || @current_user.admin?
83 unauthorized_redirect 'Your account is disabled'
91 unauthorized_redirect 'Your account is disabled'
84 return false
92 return false
85 end
93 end
86
94
87 # check if user ip is allowed
95 # check if user ip is allowed
88 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
96 unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
89 unless is_request_ip_allowed?
97 unless is_request_ip_allowed?
90 unauthorized_redirect 'Your IP is not allowed to login at this time.'
98 unauthorized_redirect 'Your IP is not allowed to login at this time.'
91 return false
99 return false
92 end
100 end
93 end
101 end
94
102
95 if GraderConfiguration.multicontests?
103 if GraderConfiguration.multicontests?
96 return true if @current_user.admin?
104 return true if @current_user.admin?
97 begin
105 begin
98 if @current_user.contest_stat(true).forced_logout
106 if @current_user.contest_stat(true).forced_logout
99 flash[:notice] = 'You have been automatically logged out.'
107 flash[:notice] = 'You have been automatically logged out.'
100 redirect_to :controller => 'main', :action => 'index'
108 redirect_to :controller => 'main', :action => 'index'
101 end
109 end
102 rescue
110 rescue
103 end
111 end
104 end
112 end
105 return true
113 return true
106 end
114 end
107
115
108 #redirect to root (and also force logout)
116 #redirect to root (and also force logout)
109 #if the user use different ip from the previous connection
117 #if the user use different ip from the previous connection
110 # only applicable when MULTIPLE_IP_LOGIN options is false only
118 # only applicable when MULTIPLE_IP_LOGIN options is false only
111 def authenticate_by_ip_address
119 def authenticate_by_ip_address
112 #this assume that we have already authenticate normally
120 #this assume that we have already authenticate normally
113 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
121 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
114 user = User.find(session[:user_id])
122 user = User.find(session[:user_id])
115 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
123 if (!user.admin? && user.last_ip && user.last_ip != request.remote_ip)
116 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
124 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
117 redirect_to :controller => 'main', :action => 'login'
125 redirect_to :controller => 'main', :action => 'login'
118 return false
126 return false
119 end
127 end
120 unless user.last_ip
128 unless user.last_ip
121 user.last_ip = request.remote_ip
129 user.last_ip = request.remote_ip
122 user.save
130 user.save
123 end
131 end
124 end
132 end
125 return true
133 return true
126 end
134 end
127
135
128 def authorization
136 def authorization
129 return false unless check_valid_login
137 return false unless check_valid_login
130 user = User.find(session[:user_id])
138 user = User.find(session[:user_id])
131 unless user.roles.detect { |role|
139 unless user.roles.detect { |role|
132 role.rights.detect{ |right|
140 role.rights.detect{ |right|
133 right.controller == self.class.controller_name and
141 right.controller == self.class.controller_name and
134 (right.action == 'all' || right.action == action_name)
142 (right.action == 'all' || right.action == action_name)
135 }
143 }
136 }
144 }
137 flash[:notice] = 'You are not authorized to view the page you requested'
145 flash[:notice] = 'You are not authorized to view the page you requested'
138 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
146 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
139 redirect_to :controller => 'main', :action => 'login'
147 redirect_to :controller => 'main', :action => 'login'
140 return false
148 return false
141 end
149 end
142 end
150 end
143
151
144 def verify_time_limit
152 def verify_time_limit
145 return true if session[:user_id]==nil
153 return true if session[:user_id]==nil
146 user = User.find(session[:user_id], :include => :site)
154 user = User.find(session[:user_id], :include => :site)
147 return true if user==nil || user.site == nil
155 return true if user==nil || user.site == nil
148 if user.contest_finished?
156 if user.contest_finished?
149 flash[:notice] = 'Error: the contest you are participating is over.'
157 flash[:notice] = 'Error: the contest you are participating is over.'
150 redirect_to :back
158 redirect_to :back
151 return false
159 return false
152 end
160 end
153 return true
161 return true
154 end
162 end
155
163
156 def is_request_ip_allowed?
164 def is_request_ip_allowed?
157 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
165 unless GraderConfiguration[WHITELIST_IGNORE_CONF_KEY]
158 user_ip = IPAddr.new(request.remote_ip)
166 user_ip = IPAddr.new(request.remote_ip)
159 allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
167 allowed = GraderConfiguration[WHITELIST_IP_CONF_KEY] || ''
160
168
161 allowed.delete(' ').split(',').each do |ips|
169 allowed.delete(' ').split(',').each do |ips|
162 allow_ips = IPAddr.new(ips)
170 allow_ips = IPAddr.new(ips)
163 if allow_ips.include?(user_ip)
171 if allow_ips.include?(user_ip)
164 return true
172 return true
165 end
173 end
166 end
174 end
167 return false
175 return false
168 end
176 end
169 return true
177 return true
170 end
178 end
171
179
172 #function for datatable ajax query
180 #function for datatable ajax query
173 #return record,total_count,filter_count
181 #return record,total_count,filter_count
174 def process_query_record(record,
182 def process_query_record(record,
175 total_count: nil,
183 total_count: nil,
176 select: '',
184 select: '',
177 global_search: [],
185 global_search: [],
178 no_search: false,
186 no_search: false,
179 force_order: '',
187 force_order: '',
180 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
188 date_filter: '', date_param_since: 'date_since',date_param_until: 'date_until',
181 hard_limit: nil)
189 hard_limit: nil)
182 arel_table = record.model.arel_table
190 arel_table = record.model.arel_table
183
191
184 if !no_search && params['search']
192 if !no_search && params['search']
185 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
193 global_value = record.model.sanitize_sql(params['search']['value'].strip.downcase)
186 if !global_value.blank?
194 if !global_value.blank?
187 global_value.split.each do |value|
195 global_value.split.each do |value|
188 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
196 global_where = global_search.map{|f| "LOWER(#{f}) like '%#{value}%'"}.join(' OR ')
189 record = record.where(global_where)
197 record = record.where(global_where)
190 end
198 end
191 end
199 end
192
200
193 params['columns'].each do |i, col|
201 params['columns'].each do |i, col|
194 if !col['search']['value'].blank?
202 if !col['search']['value'].blank?
195 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
203 record = record.where(arel_table[col['name']].lower.matches("%#{col['search']['value'].strip.downcase}%"))
196 end
204 end
197 end
205 end
198 end
206 end
199
207
200 if !date_filter.blank?
208 if !date_filter.blank?
201 param_since = params[date_param_since]
209 param_since = params[date_param_since]
202 param_until = params[date_param_until]
210 param_until = params[date_param_until]
203 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
211 date_since = Time.zone.parse( param_since ) || Time.new(1,1,1) rescue Time.new(1,1,1)
204 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
212 date_until = Time.zone.parse( param_until ) || Time.zone.now() rescue Time.zone.now()
205 date_range = date_since..(date_until.end_of_day)
213 date_range = date_since..(date_until.end_of_day)
206 record = record.where(date_filter.to_sym => date_range)
214 record = record.where(date_filter.to_sym => date_range)
207 end
215 end
208
216
209 if force_order.blank?
217 if force_order.blank?
210 if params['order']
218 if params['order']
211 params['order'].each do |i, o|
219 params['order'].each do |i, o|
212 colName = params['columns'][o['column']]['name']
220 colName = params['columns'][o['column']]['name']
213 colName = "#{record.model.table_name}.#{colName}" if colName.upcase == 'ID'
221 colName = "#{record.model.table_name}.#{colName}" if colName.upcase == 'ID'
214 record = record.order("#{colName} #{o['dir'].casecmp('desc') != 0 ? 'ASC' : 'DESC'}") unless colName.blank?
222 record = record.order("#{colName} #{o['dir'].casecmp('desc') != 0 ? 'ASC' : 'DESC'}") unless colName.blank?
215 end
223 end
216 end
224 end
217 else
225 else
218 record = record.order(force_order)
226 record = record.order(force_order)
219 end
227 end
220
228
221 filterCount = record.count(record.model.primary_key)
229 filterCount = record.count(record.model.primary_key)
222 # if .group() is used, filterCount might be like {id_1: count_1, id_2: count_2, ...}
230 # if .group() is used, filterCount might be like {id_1: count_1, id_2: count_2, ...}
223 # so we should count the result again..
231 # so we should count the result again..
224 if filterCount.is_a? Hash
232 if filterCount.is_a? Hash
225 filterCount = filterCount.count
233 filterCount = filterCount.count
226 end
234 end
227
235
228
236
229 record = record.offset(params['start'] || 0)
237 record = record.offset(params['start'] || 0)
230 record = record.limit(hard_limit)
238 record = record.limit(hard_limit)
231 if (params['length'])
239 if (params['length'])
232 limit = params['length'].to_i
240 limit = params['length'].to_i
233 limit == hard_limit if (hard_limit && hard_limit < limit)
241 limit == hard_limit if (hard_limit && hard_limit < limit)
234 record = record.limit(limit)
242 record = record.limit(limit)
235 end
243 end
236 if (!select.blank?)
244 if (!select.blank?)
237 record = record.select(select)
245 record = record.select(select)
238 end
246 end
239
247
240 return record, total_count || record.model.count, filterCount
248 return record, total_count || record.model.count, filterCount
241 end
249 end
242
250
243 end
251 end
@@ -1,89 +1,99
1 class LoginController < ApplicationController
1 class LoginController < ApplicationController
2
2
3 @@authenticators = []
3 @@authenticators = []
4
4
5 def index
5 def index
6 # show login screen
6 # show login screen
7 reset_session
7 reset_session
8 redirect_to :controller => 'main', :action => 'login'
8 redirect_to :controller => 'main', :action => 'login'
9 end
9 end
10
10
11 def login
11 def login
12 user = get_authenticated_user(params[:login], params[:password])
12 user = get_authenticated_user(params[:login], params[:password])
13 unless user
13 unless user
14 flash[:notice] = 'Wrong password'
14 flash[:notice] = 'Wrong password'
15 redirect_to :controller => 'main', :action => 'login'
15 redirect_to :controller => 'main', :action => 'login'
16 return
16 return
17 end
17 end
18
18
19 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?
20 flash[:notice] = 'You must accept the agreement before logging in'
20 flash[:notice] = 'You must accept the agreement before logging in'
21 redirect_to :controller => 'main', :action => 'login'
21 redirect_to :controller => 'main', :action => 'login'
22 return
22 return
23 end
23 end
24
24
25 + #store uuid when login
26 + if user.last_ip.nil?
27 + user.last_ip = cookies[:uuid]
28 + else
29 + if user.last_ip != cookies[:uuid]
30 + user.last_ip =cookies[:uuid]
31 + #log different login
32 + end
33 + end
34 +
25 #process logging in
35 #process logging in
26 session[:user_id] = user.id
36 session[:user_id] = user.id
27 session[:admin] = user.admin?
37 session[:admin] = user.admin?
28
38
29 # clear forced logout flag for multicontests contest change
39 # clear forced logout flag for multicontests contest change
30 if GraderConfiguration.multicontests?
40 if GraderConfiguration.multicontests?
31 contest_stat = user.contest_stat
41 contest_stat = user.contest_stat
32 if contest_stat.respond_to? :forced_logout
42 if contest_stat.respond_to? :forced_logout
33 if contest_stat.forced_logout
43 if contest_stat.forced_logout
34 contest_stat.forced_logout = false
44 contest_stat.forced_logout = false
35 contest_stat.save
45 contest_stat.save
36 end
46 end
37 end
47 end
38 end
48 end
39
49
40 #save login information
50 #save login information
41 - Login.create(user_id: user.id, ip_address: request.remote_ip)
51 + Login.create(user_id: user.id, ip_address: cookies[:uuid])
42
52
43 redirect_to :controller => 'main', :action => 'list'
53 redirect_to :controller => 'main', :action => 'list'
44 end
54 end
45
55
46 def site_login
56 def site_login
47 begin
57 begin
48 site = Site.find(params[:login][:site_id])
58 site = Site.find(params[:login][:site_id])
49 rescue ActiveRecord::RecordNotFound
59 rescue ActiveRecord::RecordNotFound
50 site = nil
60 site = nil
51 end
61 end
52 if site==nil
62 if site==nil
53 flash[:notice] = 'Wrong site'
63 flash[:notice] = 'Wrong site'
54 redirect_to :controller => 'main', :action => 'login' and return
64 redirect_to :controller => 'main', :action => 'login' and return
55 end
65 end
56 if (site.password) and (site.password == params[:login][:password])
66 if (site.password) and (site.password == params[:login][:password])
57 session[:site_id] = site.id
67 session[:site_id] = site.id
58 redirect_to :controller => 'site', :action => 'index'
68 redirect_to :controller => 'site', :action => 'index'
59 else
69 else
60 flash[:notice] = 'Wrong site password'
70 flash[:notice] = 'Wrong site password'
61 redirect_to :controller => 'site', :action => 'login'
71 redirect_to :controller => 'site', :action => 'login'
62 end
72 end
63 end
73 end
64
74
65 def logout
75 def logout
66 redirect_to root_path
76 redirect_to root_path
67 end
77 end
68
78
69 def self.add_authenticator(authenticator)
79 def self.add_authenticator(authenticator)
70 @@authenticators << authenticator
80 @@authenticators << authenticator
71 end
81 end
72
82
73 protected
83 protected
74
84
75 def get_authenticated_user(login, password)
85 def get_authenticated_user(login, password)
76 if @@authenticators.empty?
86 if @@authenticators.empty?
77 return User.authenticate(login, password)
87 return User.authenticate(login, password)
78 else
88 else
79 user = User.authenticate(login, password)
89 user = User.authenticate(login, password)
80 @@authenticators.each do |authenticator|
90 @@authenticators.each do |authenticator|
81 if not user
91 if not user
82 user = authenticator.authenticate(login, password)
92 user = authenticator.authenticate(login, password)
83 end
93 end
84 end
94 end
85 return user
95 return user
86 end
96 end
87 end
97 end
88
98
89 end
99 end
@@ -1,461 +1,461
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10
10
11 #has_and_belongs_to_many :groups
11 #has_and_belongs_to_many :groups
12 has_many :groups_users, class_name: 'GroupUser'
12 has_many :groups_users, class_name: 'GroupUser'
13 has_many :groups, :through => :groups_users
13 has_many :groups, :through => :groups_users
14
14
15 has_many :test_requests, -> {order(submitted_at: :desc)}
15 has_many :test_requests, -> {order(submitted_at: :desc)}
16
16
17 has_many :messages, -> { order(created_at: :desc) },
17 has_many :messages, -> { order(created_at: :desc) },
18 :class_name => "Message",
18 :class_name => "Message",
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_many :logins
25 has_many :logins
26
26
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
28
28
29 belongs_to :site
29 belongs_to :site
30 belongs_to :country
30 belongs_to :country
31
31
32 has_and_belongs_to_many :contests, -> { order(:name)}
32 has_and_belongs_to_many :contests, -> { order(:name)}
33
33
34 scope :activated_users, -> {where activated: true}
34 scope :activated_users, -> {where activated: true}
35
35
36 validates_presence_of :login
36 validates_presence_of :login
37 validates_uniqueness_of :login
37 validates_uniqueness_of :login
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
39 validates_length_of :login, :within => 3..30
39 validates_length_of :login, :within => 3..30
40
40
41 validates_presence_of :full_name
41 validates_presence_of :full_name
42 validates_length_of :full_name, :minimum => 1
42 validates_length_of :full_name, :minimum => 1
43 -
43 +
44 validates_presence_of :password, :if => :password_required?
44 validates_presence_of :password, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
45 validates_length_of :password, :within => 4..50, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
46 validates_confirmation_of :password, :if => :password_required?
47
47
48 validates_format_of :email,
48 validates_format_of :email,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :uniqueness_of_email_from_activated_users,
51 validate :uniqueness_of_email_from_activated_users,
52 :if => :email_validation?
52 :if => :email_validation?
53 validate :enough_time_interval_between_same_email_registrations,
53 validate :enough_time_interval_between_same_email_registrations,
54 :if => :email_validation?
54 :if => :email_validation?
55
55
56 # these are for ytopc
56 # these are for ytopc
57 # disable for now
57 # disable for now
58 #validates_presence_of :province
58 #validates_presence_of :province
59
59
60 attr_accessor :password
60 attr_accessor :password
61
61
62 before_save :encrypt_new_password
62 before_save :encrypt_new_password
63 before_save :assign_default_site
63 before_save :assign_default_site
64 before_save :assign_default_contest
64 before_save :assign_default_contest
65
65
66 # this is for will_paginate
66 # this is for will_paginate
67 cattr_reader :per_page
67 cattr_reader :per_page
68 @@per_page = 50
68 @@per_page = 50
69
69
70 def self.authenticate(login, password)
70 def self.authenticate(login, password)
71 user = find_by_login(login)
71 user = find_by_login(login)
72 if user
72 if user
73 return user if user.authenticated?(password)
73 return user if user.authenticated?(password)
74 end
74 end
75 end
75 end
76
76
77 def authenticated?(password)
77 def authenticated?(password)
78 if self.activated
78 if self.activated
79 hashed_password == User.encrypt(password,self.salt)
79 hashed_password == User.encrypt(password,self.salt)
80 else
80 else
81 false
81 false
82 end
82 end
83 end
83 end
84
84
85 def login_with_name
85 def login_with_name
86 "[#{login}] #{full_name}"
86 "[#{login}] #{full_name}"
87 end
87 end
88
88
89 def admin?
89 def admin?
90 has_role?('admin')
90 has_role?('admin')
91 end
91 end
92
92
93 def has_role?(role)
93 def has_role?(role)
94 self.roles.where(name: role).count > 0
94 self.roles.where(name: role).count > 0
95 end
95 end
96
96
97 def email_for_editing
97 def email_for_editing
98 if self.email==nil
98 if self.email==nil
99 "(unknown)"
99 "(unknown)"
100 elsif self.email==''
100 elsif self.email==''
101 "(blank)"
101 "(blank)"
102 else
102 else
103 self.email
103 self.email
104 end
104 end
105 end
105 end
106
106
107 def email_for_editing=(e)
107 def email_for_editing=(e)
108 self.email=e
108 self.email=e
109 end
109 end
110
110
111 def alias_for_editing
111 def alias_for_editing
112 if self.alias==nil
112 if self.alias==nil
113 "(unknown)"
113 "(unknown)"
114 elsif self.alias==''
114 elsif self.alias==''
115 "(blank)"
115 "(blank)"
116 else
116 else
117 self.alias
117 self.alias
118 end
118 end
119 end
119 end
120
120
121 def alias_for_editing=(e)
121 def alias_for_editing=(e)
122 self.alias=e
122 self.alias=e
123 end
123 end
124
124
125 def activation_key
125 def activation_key
126 if self.hashed_password==nil
126 if self.hashed_password==nil
127 encrypt_new_password
127 encrypt_new_password
128 end
128 end
129 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
129 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
130 end
130 end
131
131
132 def verify_activation_key(key)
132 def verify_activation_key(key)
133 key == activation_key
133 key == activation_key
134 end
134 end
135
135
136 def self.random_password(length=5)
136 def self.random_password(length=5)
137 chars = 'abcdefghjkmnopqrstuvwxyz'
137 chars = 'abcdefghjkmnopqrstuvwxyz'
138 password = ''
138 password = ''
139 length.times { password << chars[rand(chars.length - 1)] }
139 length.times { password << chars[rand(chars.length - 1)] }
140 password
140 password
141 end
141 end
142
142
143
143
144 # Contest information
144 # Contest information
145
145
146 def self.find_users_with_no_contest()
146 def self.find_users_with_no_contest()
147 users = User.all
147 users = User.all
148 return users.find_all { |u| u.contests.length == 0 }
148 return users.find_all { |u| u.contests.length == 0 }
149 end
149 end
150
150
151
151
152 def contest_time_left
152 def contest_time_left
153 if GraderConfiguration.contest_mode?
153 if GraderConfiguration.contest_mode?
154 return nil if site==nil
154 return nil if site==nil
155 return site.time_left
155 return site.time_left
156 elsif GraderConfiguration.indv_contest_mode?
156 elsif GraderConfiguration.indv_contest_mode?
157 time_limit = GraderConfiguration.contest_time_limit
157 time_limit = GraderConfiguration.contest_time_limit
158 if time_limit == nil
158 if time_limit == nil
159 return nil
159 return nil
160 end
160 end
161 if contest_stat==nil or contest_stat.started_at==nil
161 if contest_stat==nil or contest_stat.started_at==nil
162 return (Time.now.gmtime + time_limit) - Time.now.gmtime
162 return (Time.now.gmtime + time_limit) - Time.now.gmtime
163 else
163 else
164 finish_time = contest_stat.started_at + time_limit
164 finish_time = contest_stat.started_at + time_limit
165 current_time = Time.now.gmtime
165 current_time = Time.now.gmtime
166 if current_time > finish_time
166 if current_time > finish_time
167 return 0
167 return 0
168 else
168 else
169 return finish_time - current_time
169 return finish_time - current_time
170 end
170 end
171 end
171 end
172 else
172 else
173 return nil
173 return nil
174 end
174 end
175 end
175 end
176
176
177 def contest_finished?
177 def contest_finished?
178 if GraderConfiguration.contest_mode?
178 if GraderConfiguration.contest_mode?
179 return false if site==nil
179 return false if site==nil
180 return site.finished?
180 return site.finished?
181 elsif GraderConfiguration.indv_contest_mode?
181 elsif GraderConfiguration.indv_contest_mode?
182 return false if self.contest_stat==nil
182 return false if self.contest_stat==nil
183 return contest_time_left == 0
183 return contest_time_left == 0
184 else
184 else
185 return false
185 return false
186 end
186 end
187 end
187 end
188
188
189 def contest_started?
189 def contest_started?
190 if GraderConfiguration.indv_contest_mode?
190 if GraderConfiguration.indv_contest_mode?
191 stat = self.contest_stat
191 stat = self.contest_stat
192 return ((stat != nil) and (stat.started_at != nil))
192 return ((stat != nil) and (stat.started_at != nil))
193 elsif GraderConfiguration.contest_mode?
193 elsif GraderConfiguration.contest_mode?
194 return true if site==nil
194 return true if site==nil
195 return site.started
195 return site.started
196 else
196 else
197 return true
197 return true
198 end
198 end
199 end
199 end
200
200
201 def update_start_time
201 def update_start_time
202 stat = self.contest_stat
202 stat = self.contest_stat
203 if stat.nil? or stat.started_at.nil?
203 if stat.nil? or stat.started_at.nil?
204 stat ||= UserContestStat.new(:user => self)
204 stat ||= UserContestStat.new(:user => self)
205 stat.started_at = Time.now.gmtime
205 stat.started_at = Time.now.gmtime
206 stat.save
206 stat.save
207 end
207 end
208 end
208 end
209
209
210 def problem_in_user_contests?(problem)
210 def problem_in_user_contests?(problem)
211 problem_contests = problem.contests.all
211 problem_contests = problem.contests.all
212
212
213 if problem_contests.length == 0 # this is public contest
213 if problem_contests.length == 0 # this is public contest
214 return true
214 return true
215 end
215 end
216
216
217 contests.each do |contest|
217 contests.each do |contest|
218 if problem_contests.find {|c| c.id == contest.id }
218 if problem_contests.find {|c| c.id == contest.id }
219 return true
219 return true
220 end
220 end
221 end
221 end
222 return false
222 return false
223 end
223 end
224
224
225 def available_problems_group_by_contests
225 def available_problems_group_by_contests
226 contest_problems = []
226 contest_problems = []
227 pin = {}
227 pin = {}
228 contests.enabled.each do |contest|
228 contests.enabled.each do |contest|
229 available_problems = contest.problems.available
229 available_problems = contest.problems.available
230 contest_problems << {
230 contest_problems << {
231 :contest => contest,
231 :contest => contest,
232 :problems => available_problems
232 :problems => available_problems
233 }
233 }
234 available_problems.each {|p| pin[p.id] = true}
234 available_problems.each {|p| pin[p.id] = true}
235 end
235 end
236 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
236 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
237 contest_problems << {
237 contest_problems << {
238 :contest => nil,
238 :contest => nil,
239 :problems => other_avaiable_problems
239 :problems => other_avaiable_problems
240 }
240 }
241 return contest_problems
241 return contest_problems
242 end
242 end
243
243
244 def solve_all_available_problems?
244 def solve_all_available_problems?
245 available_problems.each do |p|
245 available_problems.each do |p|
246 u = self
246 u = self
247 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
247 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
248 return false if !p or !sub or sub.points < p.full_score
248 return false if !p or !sub or sub.points < p.full_score
249 end
249 end
250 return true
250 return true
251 end
251 end
252
252
253 #get a list of available problem
253 #get a list of available problem
254 def available_problems
254 def available_problems
255 # first, we check if this is normal mode
255 # first, we check if this is normal mode
256 if not GraderConfiguration.multicontests?
256 if not GraderConfiguration.multicontests?
257
257
258 #if this is a normal mode
258 #if this is a normal mode
259 #we show problem based on problem_group, if the config said so
259 #we show problem based on problem_group, if the config said so
260 if GraderConfiguration.use_problem_group?
260 if GraderConfiguration.use_problem_group?
261 return available_problems_in_group
261 return available_problems_in_group
262 else
262 else
263 return Problem.available_problems
263 return Problem.available_problems
264 end
264 end
265 else
265 else
266 #this is multi contest mode
266 #this is multi contest mode
267 contest_problems = []
267 contest_problems = []
268 pin = {}
268 pin = {}
269 contests.enabled.each do |contest|
269 contests.enabled.each do |contest|
270 contest.problems.available.each do |problem|
270 contest.problems.available.each do |problem|
271 if not pin.has_key? problem.id
271 if not pin.has_key? problem.id
272 contest_problems << problem
272 contest_problems << problem
273 end
273 end
274 pin[problem.id] = true
274 pin[problem.id] = true
275 end
275 end
276 end
276 end
277 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
277 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
278 return contest_problems + other_avaiable_problems
278 return contest_problems + other_avaiable_problems
279 end
279 end
280 end
280 end
281
281
282 # new feature, get list of available problem in all enabled group that the user belongs to
282 # new feature, get list of available problem in all enabled group that the user belongs to
283 def available_problems_in_group
283 def available_problems_in_group
284 problem = []
284 problem = []
285 self.groups.where(enabled: true).each do |group|
285 self.groups.where(enabled: true).each do |group|
286 group.problems.where(available: true).each { |p| problem << p }
286 group.problems.where(available: true).each { |p| problem << p }
287 end
287 end
288 problem.uniq!
288 problem.uniq!
289 if problem
289 if problem
290 problem.sort! do |a,b|
290 problem.sort! do |a,b|
291 case
291 case
292 when a.date_added < b.date_added
292 when a.date_added < b.date_added
293 1
293 1
294 when a.date_added > b.date_added
294 when a.date_added > b.date_added
295 -1
295 -1
296 else
296 else
297 a.name <=> b.name
297 a.name <=> b.name
298 end
298 end
299 end
299 end
300 return problem
300 return problem
301 else
301 else
302 return []
302 return []
303 end
303 end
304 end
304 end
305
305
306 #check if the user has the right to view that problem
306 #check if the user has the right to view that problem
307 #this also consider group based problem policy
307 #this also consider group based problem policy
308 def can_view_problem?(problem)
308 def can_view_problem?(problem)
309 return true if admin?
309 return true if admin?
310 return available_problems.include? problem
310 return available_problems.include? problem
311 end
311 end
312
312
313 def self.clear_last_login
313 def self.clear_last_login
314 User.update_all(:last_ip => nil)
314 User.update_all(:last_ip => nil)
315 end
315 end
316
316
317 #create multiple user, one per lines of input
317 #create multiple user, one per lines of input
318 def self.create_from_list(lines)
318 def self.create_from_list(lines)
319 error_logins = []
319 error_logins = []
320 first_error = nil
320 first_error = nil
321 created_users = []
321 created_users = []
322
322
323 lines.split("\n").each do |line|
323 lines.split("\n").each do |line|
324 #split with large limit, this will cause consecutive ',' to be result in a blank
324 #split with large limit, this will cause consecutive ',' to be result in a blank
325 items = line.chomp.split(',',1000)
325 items = line.chomp.split(',',1000)
326 if items.length>=2
326 if items.length>=2
327 login = items[0]
327 login = items[0]
328 full_name = items[1]
328 full_name = items[1]
329 remark =''
329 remark =''
330 user_alias = ''
330 user_alias = ''
331
331
332 added_random_password = false
332 added_random_password = false
333 added_password = false
333 added_password = false
334
334
335 #given password?
335 #given password?
336 if items.length >= 3
336 if items.length >= 3
337 if items[2].chomp(" ").length > 0
337 if items[2].chomp(" ").length > 0
338 password = items[2].chomp(" ")
338 password = items[2].chomp(" ")
339 added_password = true
339 added_password = true
340 end
340 end
341 else
341 else
342 password = random_password
342 password = random_password
343 added_random_password=true;
343 added_random_password=true;
344 end
344 end
345
345
346 #given alias?
346 #given alias?
347 if items.length>= 4 and items[3].chomp(" ").length > 0;
347 if items.length>= 4 and items[3].chomp(" ").length > 0;
348 user_alias = items[3].chomp(" ")
348 user_alias = items[3].chomp(" ")
349 else
349 else
350 user_alias = login
350 user_alias = login
351 end
351 end
352
352
353 #given remark?
353 #given remark?
354 has_remark = false
354 has_remark = false
355 if items.length>=5
355 if items.length>=5
356 remark = items[4].strip;
356 remark = items[4].strip;
357 has_remark = true
357 has_remark = true
358 end
358 end
359
359
360 user = User.find_by_login(login)
360 user = User.find_by_login(login)
361 if (user)
361 if (user)
362 user.full_name = full_name
362 user.full_name = full_name
363 user.remark = remark if has_remark
363 user.remark = remark if has_remark
364 user.password = password if added_password || added_random_password
364 user.password = password if added_password || added_random_password
365 else
365 else
366 #create a random password if none are given
366 #create a random password if none are given
367 password = random_password unless password
367 password = random_password unless password
368 user = User.new({:login => login,
368 user = User.new({:login => login,
369 :full_name => full_name,
369 :full_name => full_name,
370 :password => password,
370 :password => password,
371 :password_confirmation => password,
371 :password_confirmation => password,
372 :alias => user_alias,
372 :alias => user_alias,
373 :remark => remark})
373 :remark => remark})
374 end
374 end
375 user.activated = true
375 user.activated = true
376
376
377 if user.save
377 if user.save
378 created_users << user
378 created_users << user
379 else
379 else
380 error_logins << "'#{login}'"
380 error_logins << "'#{login}'"
381 first_error = user.errors.full_messages.to_sentence unless first_error
381 first_error = user.errors.full_messages.to_sentence unless first_error
382 end
382 end
383 end
383 end
384 end
384 end
385
385
386 return {error_logins: error_logins, first_error: first_error, created_users: created_users}
386 return {error_logins: error_logins, first_error: first_error, created_users: created_users}
387
387
388 end
388 end
389
389
390 def self.find_non_admin_with_prefix(prefix='')
390 def self.find_non_admin_with_prefix(prefix='')
391 users = User.all
391 users = User.all
392 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
392 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
393 end
393 end
394
394
395 protected
395 protected
396 def encrypt_new_password
396 def encrypt_new_password
397 return if password.blank?
397 return if password.blank?
398 self.salt = (10+rand(90)).to_s
398 self.salt = (10+rand(90)).to_s
399 self.hashed_password = User.encrypt(self.password,self.salt)
399 self.hashed_password = User.encrypt(self.password,self.salt)
400 end
400 end
401
401
402 def assign_default_site
402 def assign_default_site
403 # have to catch error when migrating (because self.site is not available).
403 # have to catch error when migrating (because self.site is not available).
404 begin
404 begin
405 if self.site==nil
405 if self.site==nil
406 self.site = Site.find_by_name('default')
406 self.site = Site.find_by_name('default')
407 if self.site==nil
407 if self.site==nil
408 self.site = Site.find(1) # when 'default has be renamed'
408 self.site = Site.find(1) # when 'default has be renamed'
409 end
409 end
410 end
410 end
411 rescue
411 rescue
412 end
412 end
413 end
413 end
414
414
415 def assign_default_contest
415 def assign_default_contest
416 # have to catch error when migrating (because self.site is not available).
416 # have to catch error when migrating (because self.site is not available).
417 begin
417 begin
418 if self.contests.length == 0
418 if self.contests.length == 0
419 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
419 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
420 if default_contest
420 if default_contest
421 self.contests = [default_contest]
421 self.contests = [default_contest]
422 end
422 end
423 end
423 end
424 rescue
424 rescue
425 end
425 end
426 end
426 end
427
427
428 def password_required?
428 def password_required?
429 self.hashed_password.blank? || !self.password.blank?
429 self.hashed_password.blank? || !self.password.blank?
430 end
430 end
431
431
432 def self.encrypt(string,salt)
432 def self.encrypt(string,salt)
433 Digest::SHA1.hexdigest(salt + string)
433 Digest::SHA1.hexdigest(salt + string)
434 end
434 end
435
435
436 def uniqueness_of_email_from_activated_users
436 def uniqueness_of_email_from_activated_users
437 user = User.activated_users.find_by_email(self.email)
437 user = User.activated_users.find_by_email(self.email)
438 if user and (user.login != self.login)
438 if user and (user.login != self.login)
439 self.errors.add(:base,"Email has already been taken")
439 self.errors.add(:base,"Email has already been taken")
440 end
440 end
441 end
441 end
442
442
443 def enough_time_interval_between_same_email_registrations
443 def enough_time_interval_between_same_email_registrations
444 return if !self.new_record?
444 return if !self.new_record?
445 return if self.activated
445 return if self.activated
446 open_user = User.find_by_email(self.email,
446 open_user = User.find_by_email(self.email,
447 :order => 'created_at DESC')
447 :order => 'created_at DESC')
448 if open_user and open_user.created_at and
448 if open_user and open_user.created_at and
449 (open_user.created_at > Time.now.gmtime - 5.minutes)
449 (open_user.created_at > Time.now.gmtime - 5.minutes)
450 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
450 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
451 end
451 end
452 end
452 end
453
453
454 def email_validation?
454 def email_validation?
455 begin
455 begin
456 return VALIDATE_USER_EMAILS
456 return VALIDATE_USER_EMAILS
457 rescue
457 rescue
458 return false
458 return false
459 end
459 end
460 end
460 end
461 end
461 end
You need to be logged in to leave comments. Login now