Description:
merge with algo-bm, take cheat report
Commit status:
[Not Reviewed]
References:
merge java
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r526:f7b4a30e2f5d - - 12 files changed: 252 inserted, 6 deleted

@@ -0,0 +1,77
1 + - content_for :header do
2 + = stylesheet_link_tag 'tablesorter-theme.cafe'
3 + = javascript_include_tag 'local_jquery'
4 +
5 + %script{:type=>"text/javascript"}
6 + $(function () {
7 + $('#since_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
8 + $('#until_datetime').datetimepicker({ showButtonPanel: true, dateFormat: "yy-mm-dd", controlType: "slider"} );
9 + $('#my_table').tablesorter({widthFixed: true, widgets: ['zebra']});
10 + $('#my_table2').tablesorter({widthFixed: true, widgets: ['zebra']});
11 + $('#sub_table').tablesorter({widthFixed: true, widgets: ['zebra']});
12 + });
13 +
14 + %h1 Login status
15 +
16 + =render partial: 'report_menu'
17 + =render partial: 'date_range', locals: {param_text: 'Login date range:', title: 'Query login stat in the range' }
18 +
19 + %h2 Suspect
20 +
21 + %table.tablesorter-cafe#my_table
22 + %thead
23 + %tr
24 + %th login
25 + %th full name
26 + %th login count
27 + %tbody
28 + - @ml.each do |l|
29 + %tr{class: cycle('info-even','info-odd')}
30 + %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
31 + %td= l[:full_name]
32 + %td= l[:count]
33 +
34 +
35 + %h2 Multiple Logins Report
36 + This section reports all logins record that have either multiple ip per login or multiple login per ip.
37 +
38 + %table.tablesorter-cafe#my_table2
39 + %thead
40 + %tr
41 + %th login
42 + %th full name
43 + %th IP
44 + %th time
45 + %tbody
46 + - @mld.each do |l|
47 + %tr{class: cycle('info-even','info-odd')}
48 + %td= link_to l.user[:login], controller: 'users', action: 'profile', id: l[:user_id]
49 + %td= l.user[:full_name]
50 + %td= l[:ip_address]
51 + %td= l[:created_at]
52 +
53 + %h2 Multiple IP Submissions Report
54 + This section reports all submission records that have USER_ID matchs ID that logins on multiple IP
55 + and that have IP_ADDRESS that has multiple ID logins
56 +
57 + Be noted that when submission IP address is not available, this might exclude
58 + submissions that come from ID that login on multiple-login IP
59 +
60 + %table.tablesorter-cafe#sub_table
61 + %thead
62 + %tr
63 + %th login
64 + %th full name
65 + %th IP
66 + %th problem
67 + %th Submission
68 + %th time
69 + %tbody
70 + - @subs.each do |s|
71 + %tr{class: cycle('info-even','info-odd')}
72 + %td= link_to s.user[:login], controller: 'users', action: 'profile', id: s[:user_id]
73 + %td= s.user[:full_name]
74 + %td= s[:ip_address]
75 + %td= s.problem.name
76 + %td= link_to(s.id, controller: 'graders' , action: 'submission', id: s.id)
77 + %td= s[:submitted_at]
@@ -0,0 +1,9
1 + class ChangeUseridOnLogin < ActiveRecord::Migration
2 + def up
3 + change_column :logins, :user_id, :integer
4 + end
5 +
6 + def down
7 + change_column :logins, :user_id, :string
8 + end
9 + end
@@ -1,92 +1,110
1 class ApplicationController < ActionController::Base
1 class ApplicationController < ActionController::Base
2 protect_from_forgery
2 protect_from_forgery
3
3
4 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
4 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
5 + MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
5
6
6 def admin_authorization
7 def admin_authorization
7 return false unless authenticate
8 return false unless authenticate
8 user = User.find(session[:user_id], :include => ['roles'])
9 user = User.find(session[:user_id], :include => ['roles'])
9 unless user.admin?
10 unless user.admin?
10 flash[:notice] = 'You are not authorized to view the page you requested'
11 flash[:notice] = 'You are not authorized to view the page you requested'
11 redirect_to :controller => 'main', :action => 'login' unless user.admin?
12 redirect_to :controller => 'main', :action => 'login' unless user.admin?
12 return false
13 return false
13 end
14 end
14 return true
15 return true
15 end
16 end
16
17
17 def authorization_by_roles(allowed_roles)
18 def authorization_by_roles(allowed_roles)
18 return false unless authenticate
19 return false unless authenticate
19 user = User.find(session[:user_id])
20 user = User.find(session[:user_id])
20 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
21 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
21 flash[:notice] = 'You are not authorized to view the page you requested'
22 flash[:notice] = 'You are not authorized to view the page you requested'
22 redirect_to :controller => 'main', :action => 'login'
23 redirect_to :controller => 'main', :action => 'login'
23 return false
24 return false
24 end
25 end
25 end
26 end
26
27
27 protected
28 protected
28
29
29 def authenticate
30 def authenticate
30 unless session[:user_id]
31 unless session[:user_id]
31 flash[:notice] = 'You need to login'
32 flash[:notice] = 'You need to login'
32 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
33 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
33 flash[:notice] = 'You need to login but you cannot log in at this time'
34 flash[:notice] = 'You need to login but you cannot log in at this time'
34 end
35 end
35 redirect_to :controller => 'main', :action => 'login'
36 redirect_to :controller => 'main', :action => 'login'
36 return false
37 return false
37 end
38 end
38
39
39 # check if run in single user mode
40 # check if run in single user mode
40 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
41 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
41 user = User.find(session[:user_id])
42 user = User.find(session[:user_id])
42 if user==nil or (not user.admin?)
43 if user==nil or (not user.admin?)
43 flash[:notice] = 'You cannot log in at this time'
44 flash[:notice] = 'You cannot log in at this time'
44 redirect_to :controller => 'main', :action => 'login'
45 redirect_to :controller => 'main', :action => 'login'
45 return false
46 return false
46 end
47 end
47 return true
48 return true
48 end
49 end
49
50
50 if GraderConfiguration.multicontests?
51 if GraderConfiguration.multicontests?
51 user = User.find(session[:user_id])
52 user = User.find(session[:user_id])
52 return true if user.admin?
53 return true if user.admin?
53 begin
54 begin
54 if user.contest_stat(true).forced_logout
55 if user.contest_stat(true).forced_logout
55 flash[:notice] = 'You have been automatically logged out.'
56 flash[:notice] = 'You have been automatically logged out.'
56 redirect_to :controller => 'main', :action => 'index'
57 redirect_to :controller => 'main', :action => 'index'
57 end
58 end
58 rescue
59 rescue
59 end
60 end
60 end
61 end
61 return true
62 return true
62 end
63 end
63
64
65 + def authenticate_by_ip_address
66 + #this assume that we have already authenticate normally
67 + unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
68 + user = User.find(session[:user_id])
69 + if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
70 + flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
71 + redirect_to :controller => 'main', :action => 'login'
72 + return false
73 + end
74 + unless user.last_ip
75 + user.last_ip = request.remote_ip
76 + user.save
77 + end
78 + end
79 + return true
80 + end
81 +
64 def authorization
82 def authorization
65 return false unless authenticate
83 return false unless authenticate
66 user = User.find(session[:user_id])
84 user = User.find(session[:user_id])
67 unless user.roles.detect { |role|
85 unless user.roles.detect { |role|
68 role.rights.detect{ |right|
86 role.rights.detect{ |right|
69 right.controller == self.class.controller_name and
87 right.controller == self.class.controller_name and
70 (right.action == 'all' or right.action == action_name)
88 (right.action == 'all' or right.action == action_name)
71 }
89 }
72 }
90 }
73 flash[:notice] = 'You are not authorized to view the page you requested'
91 flash[:notice] = 'You are not authorized to view the page you requested'
74 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
92 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
75 redirect_to :controller => 'main', :action => 'login'
93 redirect_to :controller => 'main', :action => 'login'
76 return false
94 return false
77 end
95 end
78 end
96 end
79
97
80 def verify_time_limit
98 def verify_time_limit
81 return true if session[:user_id]==nil
99 return true if session[:user_id]==nil
82 user = User.find(session[:user_id], :include => :site)
100 user = User.find(session[:user_id], :include => :site)
83 return true if user==nil or user.site == nil
101 return true if user==nil or user.site == nil
84 if user.contest_finished?
102 if user.contest_finished?
85 flash[:notice] = 'Error: the contest you are participating is over.'
103 flash[:notice] = 'Error: the contest you are participating is over.'
86 redirect_to :back
104 redirect_to :back
87 return false
105 return false
88 end
106 end
89 return true
107 return true
90 end
108 end
91
109
92 end
110 end
@@ -1,28 +1,29
1 class ConfigurationsController < ApplicationController
1 class ConfigurationsController < ApplicationController
2
2
3 before_filter :authenticate
3 before_filter :authenticate
4 before_filter { |controller| controller.authorization_by_roles(['admin'])}
4 before_filter { |controller| controller.authorization_by_roles(['admin'])}
5
5
6
6
7 def index
7 def index
8 @configurations = GraderConfiguration.find(:all,
8 @configurations = GraderConfiguration.find(:all,
9 :order => '`key`')
9 :order => '`key`')
10 end
10 end
11
11
12 def reload
12 def reload
13 GraderConfiguration.reload
13 GraderConfiguration.reload
14 redirect_to :action => 'index'
14 redirect_to :action => 'index'
15 end
15 end
16
16
17 def update
17 def update
18 @config = GraderConfiguration.find(params[:id])
18 @config = GraderConfiguration.find(params[:id])
19 + User.clear_last_login if @config.key = 'multiple_ip_login' and @config.value == 'true' and params[:grader_configuration][:value] == 'false'
19 respond_to do |format|
20 respond_to do |format|
20 if @config.update_attributes(params[:grader_configuration])
21 if @config.update_attributes(params[:grader_configuration])
21 format.json { head :ok }
22 format.json { head :ok }
22 else
23 else
23 format.json { respond_with_bip(@config) }
24 format.json { respond_with_bip(@config) }
24 end
25 end
25 end
26 end
26 end
27 end
27
28
28 end
29 end
@@ -1,207 +1,209
1 class MainController < ApplicationController
1 class MainController < ApplicationController
2
2
3 before_filter :authenticate, :except => [:index, :login]
3 before_filter :authenticate, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
4 before_filter :check_viewability, :except => [:index, :login]
5
5
6 append_before_filter :confirm_and_update_start_time,
6 append_before_filter :confirm_and_update_start_time,
7 :except => [:index,
7 :except => [:index,
8 :login,
8 :login,
9 :confirm_contest_start]
9 :confirm_contest_start]
10
10
11 # to prevent log in box to be shown when user logged out of the
11 # to prevent log in box to be shown when user logged out of the
12 # system only in some tab
12 # system only in some tab
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
13 prepend_before_filter :reject_announcement_refresh_when_logged_out,
14 :only => [:announcements]
14 :only => [:announcements]
15
15
16 + before_filter :authenticate_by_ip_address, :only => [:list]
17 +
16 # COMMENTED OUT: filter in each action instead
18 # COMMENTED OUT: filter in each action instead
17 # before_filter :verify_time_limit, :only => [:submit]
19 # before_filter :verify_time_limit, :only => [:submit]
18
20
19 verify :method => :post, :only => [:submit],
21 verify :method => :post, :only => [:submit],
20 :redirect_to => { :action => :index }
22 :redirect_to => { :action => :index }
21
23
22 # COMMENT OUT: only need when having high load
24 # COMMENT OUT: only need when having high load
23 # caches_action :index, :login
25 # caches_action :index, :login
24
26
25 # NOTE: This method is not actually needed, 'config/routes.rb' has
27 # NOTE: This method is not actually needed, 'config/routes.rb' has
26 # assigned action login as a default action.
28 # assigned action login as a default action.
27 def index
29 def index
28 redirect_to :action => 'login'
30 redirect_to :action => 'login'
29 end
31 end
30
32
31 def login
33 def login
32 saved_notice = flash[:notice]
34 saved_notice = flash[:notice]
33 reset_session
35 reset_session
34 flash.now[:notice] = saved_notice
36 flash.now[:notice] = saved_notice
35
37
36 # EXPERIMENT:
38 # EXPERIMENT:
37 # Hide login if in single user mode and the url does not
39 # Hide login if in single user mode and the url does not
38 # explicitly specify /login
40 # explicitly specify /login
39 #
41 #
40 # logger.info "PATH: #{request.path}"
42 # logger.info "PATH: #{request.path}"
41 # if GraderConfiguration['system.single_user_mode'] and
43 # if GraderConfiguration['system.single_user_mode'] and
42 # request.path!='/main/login'
44 # request.path!='/main/login'
43 # @hidelogin = true
45 # @hidelogin = true
44 # end
46 # end
45
47
46 @announcements = Announcement.find_for_frontpage
48 @announcements = Announcement.find_for_frontpage
47 render :action => 'login', :layout => 'empty'
49 render :action => 'login', :layout => 'empty'
48 end
50 end
49
51
50 def list
52 def list
51 prepare_list_information
53 prepare_list_information
52 end
54 end
53
55
54 def help
56 def help
55 @user = User.find(session[:user_id])
57 @user = User.find(session[:user_id])
56 end
58 end
57
59
58 def submit
60 def submit
59 user = User.find(session[:user_id])
61 user = User.find(session[:user_id])
60
62
61 @submission = Submission.new
63 @submission = Submission.new
62 @submission.problem_id = params[:submission][:problem_id]
64 @submission.problem_id = params[:submission][:problem_id]
63 @submission.user = user
65 @submission.user = user
64 @submission.language_id = 0
66 @submission.language_id = 0
65 if (params['file']) and (params['file']!='')
67 if (params['file']) and (params['file']!='')
66 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
67 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
68 @submission.source_filename = params['file'].original_filename
70 @submission.source_filename = params['file'].original_filename
69 end
71 end
70 @submission.submitted_at = Time.new.gmtime
72 @submission.submitted_at = Time.new.gmtime
71 @submission.ip_address = request.remote_ip
73 @submission.ip_address = request.remote_ip
72
74
73 if GraderConfiguration.time_limit_mode? and user.contest_finished?
75 if GraderConfiguration.time_limit_mode? and user.contest_finished?
74 @submission.errors.add(:base,"The contest is over.")
76 @submission.errors.add(:base,"The contest is over.")
75 prepare_list_information
77 prepare_list_information
76 render :action => 'list' and return
78 render :action => 'list' and return
77 end
79 end
78
80
79 if @submission.valid?
81 if @submission.valid?
80 if @submission.save == false
82 if @submission.save == false
81 flash[:notice] = 'Error saving your submission'
83 flash[:notice] = 'Error saving your submission'
82 elsif Task.create(:submission_id => @submission.id,
84 elsif Task.create(:submission_id => @submission.id,
83 :status => Task::STATUS_INQUEUE) == false
85 :status => Task::STATUS_INQUEUE) == false
84 flash[:notice] = 'Error adding your submission to task queue'
86 flash[:notice] = 'Error adding your submission to task queue'
85 end
87 end
86 else
88 else
87 prepare_list_information
89 prepare_list_information
88 render :action => 'list' and return
90 render :action => 'list' and return
89 end
91 end
90 redirect_to :action => 'list'
92 redirect_to :action => 'list'
91 end
93 end
92
94
93 def source
95 def source
94 submission = Submission.find(params[:id])
96 submission = Submission.find(params[:id])
95 if ((submission.user_id == session[:user_id]) and
97 if ((submission.user_id == session[:user_id]) and
96 (submission.problem != nil) and
98 (submission.problem != nil) and
97 (submission.problem.available))
99 (submission.problem.available))
98 send_data(submission.source,
100 send_data(submission.source,
99 {:filename => submission.download_filename,
101 {:filename => submission.download_filename,
100 :type => 'text/plain'})
102 :type => 'text/plain'})
101 else
103 else
102 flash[:notice] = 'Error viewing source'
104 flash[:notice] = 'Error viewing source'
103 redirect_to :action => 'list'
105 redirect_to :action => 'list'
104 end
106 end
105 end
107 end
106
108
107 def compiler_msg
109 def compiler_msg
108 @submission = Submission.find(params[:id])
110 @submission = Submission.find(params[:id])
109 if @submission.user_id == session[:user_id]
111 if @submission.user_id == session[:user_id]
110 render :action => 'compiler_msg', :layout => 'empty'
112 render :action => 'compiler_msg', :layout => 'empty'
111 else
113 else
112 flash[:notice] = 'Error viewing source'
114 flash[:notice] = 'Error viewing source'
113 redirect_to :action => 'list'
115 redirect_to :action => 'list'
114 end
116 end
115 end
117 end
116
118
117 def submission
119 def submission
118 @user = User.find(session[:user_id])
120 @user = User.find(session[:user_id])
119 @problems = @user.available_problems
121 @problems = @user.available_problems
120 if params[:id]==nil
122 if params[:id]==nil
121 @problem = nil
123 @problem = nil
122 @submissions = nil
124 @submissions = nil
123 else
125 else
124 @problem = Problem.find_by_name(params[:id])
126 @problem = Problem.find_by_name(params[:id])
125 if not @problem.available
127 if not @problem.available
126 redirect_to :action => 'list'
128 redirect_to :action => 'list'
127 flash[:notice] = 'Error: submissions for that problem are not viewable.'
129 flash[:notice] = 'Error: submissions for that problem are not viewable.'
128 return
130 return
129 end
131 end
130 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
132 @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
131 end
133 end
132 end
134 end
133
135
134 def result
136 def result
135 if !GraderConfiguration.show_grading_result
137 if !GraderConfiguration.show_grading_result
136 redirect_to :action => 'list' and return
138 redirect_to :action => 'list' and return
137 end
139 end
138 @user = User.find(session[:user_id])
140 @user = User.find(session[:user_id])
139 @submission = Submission.find(params[:id])
141 @submission = Submission.find(params[:id])
140 if @submission.user!=@user
142 if @submission.user!=@user
141 flash[:notice] = 'You are not allowed to view result of other users.'
143 flash[:notice] = 'You are not allowed to view result of other users.'
142 redirect_to :action => 'list' and return
144 redirect_to :action => 'list' and return
143 end
145 end
144 prepare_grading_result(@submission)
146 prepare_grading_result(@submission)
145 end
147 end
146
148
147 def load_output
149 def load_output
148 if !GraderConfiguration.show_grading_result or params[:num]==nil
150 if !GraderConfiguration.show_grading_result or params[:num]==nil
149 redirect_to :action => 'list' and return
151 redirect_to :action => 'list' and return
150 end
152 end
151 @user = User.find(session[:user_id])
153 @user = User.find(session[:user_id])
152 @submission = Submission.find(params[:id])
154 @submission = Submission.find(params[:id])
153 if @submission.user!=@user
155 if @submission.user!=@user
154 flash[:notice] = 'You are not allowed to view result of other users.'
156 flash[:notice] = 'You are not allowed to view result of other users.'
155 redirect_to :action => 'list' and return
157 redirect_to :action => 'list' and return
156 end
158 end
157 case_num = params[:num].to_i
159 case_num = params[:num].to_i
158 out_filename = output_filename(@user.login,
160 out_filename = output_filename(@user.login,
159 @submission.problem.name,
161 @submission.problem.name,
160 @submission.id,
162 @submission.id,
161 case_num)
163 case_num)
162 if !FileTest.exists?(out_filename)
164 if !FileTest.exists?(out_filename)
163 flash[:notice] = 'Output not found.'
165 flash[:notice] = 'Output not found.'
164 redirect_to :action => 'list' and return
166 redirect_to :action => 'list' and return
165 end
167 end
166
168
167 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
169 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
168 response.headers['Content-Type'] = "application/force-download"
170 response.headers['Content-Type'] = "application/force-download"
169 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
171 response.headers['Content-Disposition'] = "attachment; filename=\"output-#{case_num}.txt\""
170 response.headers["X-Sendfile"] = out_filename
172 response.headers["X-Sendfile"] = out_filename
171 response.headers['Content-length'] = File.size(out_filename)
173 response.headers['Content-length'] = File.size(out_filename)
172 render :nothing => true
174 render :nothing => true
173 else
175 else
174 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
176 send_file out_filename, :stream => false, :filename => "output-#{case_num}.txt", :type => "text/plain"
175 end
177 end
176 end
178 end
177
179
178 def error
180 def error
179 @user = User.find(session[:user_id])
181 @user = User.find(session[:user_id])
180 end
182 end
181
183
182 # announcement refreshing and hiding methods
184 # announcement refreshing and hiding methods
183
185
184 def announcements
186 def announcements
185 if params.has_key? 'recent'
187 if params.has_key? 'recent'
186 prepare_announcements(params[:recent])
188 prepare_announcements(params[:recent])
187 else
189 else
188 prepare_announcements
190 prepare_announcements
189 end
191 end
190 render(:partial => 'announcement',
192 render(:partial => 'announcement',
191 :collection => @announcements,
193 :collection => @announcements,
192 :locals => {:announcement_effect => true})
194 :locals => {:announcement_effect => true})
193 end
195 end
194
196
195 def confirm_contest_start
197 def confirm_contest_start
196 user = User.find(session[:user_id])
198 user = User.find(session[:user_id])
197 if request.method == 'POST'
199 if request.method == 'POST'
198 user.update_start_time
200 user.update_start_time
199 redirect_to :action => 'list'
201 redirect_to :action => 'list'
200 else
202 else
201 @contests = user.contests
203 @contests = user.contests
202 @user = user
204 @user = user
203 end
205 end
204 end
206 end
205
207
206 protected
208 protected
207
209
@@ -1,255 +1,379
1 class ReportController < ApplicationController
1 class ReportController < ApplicationController
2
2
3 - before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck]
3 + before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize]
4 +
4 before_filter(only: [:problem_hof]) { |c|
5 before_filter(only: [:problem_hof]) { |c|
5 return false unless authenticate
6 return false unless authenticate
6
7
7 if GraderConfiguration["right.user_view_submission"]
8 if GraderConfiguration["right.user_view_submission"]
8 return true;
9 return true;
9 end
10 end
10
11
11 admin_authorization
12 admin_authorization
12 }
13 }
13
14
14 def login_stat
15 def login_stat
15 @logins = Array.new
16 @logins = Array.new
16
17
17 date_and_time = '%Y-%m-%d %H:%M'
18 date_and_time = '%Y-%m-%d %H:%M'
18 begin
19 begin
19 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
20 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
21 @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
21 rescue
22 rescue
22 @since_time = DateTime.new(1000,1,1)
23 @since_time = DateTime.new(1000,1,1)
23 end
24 end
24 begin
25 begin
25 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
26 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
27 @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
27 rescue
28 rescue
28 @until_time = DateTime.new(3000,1,1)
29 @until_time = DateTime.new(3000,1,1)
29 end
30 end
30
31
31 User.all.each do |user|
32 User.all.each do |user|
32 @logins << { id: user.id,
33 @logins << { id: user.id,
33 login: user.login,
34 login: user.login,
34 full_name: user.full_name,
35 full_name: user.full_name,
35 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
36 user.id,@since_time,@until_time)
37 user.id,@since_time,@until_time)
37 .count(:id),
38 .count(:id),
38 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
39 user.id,@since_time,@until_time)
40 user.id,@since_time,@until_time)
40 .minimum(:created_at),
41 .minimum(:created_at),
41 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
42 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
42 user.id,@since_time,@until_time)
43 user.id,@since_time,@until_time)
43 .maximum(:created_at),
44 .maximum(:created_at),
44 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
45 user.id,@since_time,@until_time)
46 user.id,@since_time,@until_time)
46 .select(:ip_address).uniq
47 .select(:ip_address).uniq
47
48
48 }
49 }
49 end
50 end
50 end
51 end
51
52
52 def submission_stat
53 def submission_stat
53
54
54 date_and_time = '%Y-%m-%d %H:%M'
55 date_and_time = '%Y-%m-%d %H:%M'
55 begin
56 begin
56 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
57 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
57 rescue
58 rescue
58 @since_time = DateTime.new(1000,1,1)
59 @since_time = DateTime.new(1000,1,1)
59 end
60 end
60 begin
61 begin
61 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
62 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
62 rescue
63 rescue
63 @until_time = DateTime.new(3000,1,1)
64 @until_time = DateTime.new(3000,1,1)
64 end
65 end
65
66
66 @submissions = {}
67 @submissions = {}
67
68
68 User.find_each do |user|
69 User.find_each do |user|
69 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
70 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
70 end
71 end
71
72
72 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
73 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
73 if @submissions[s.user_id]
74 if @submissions[s.user_id]
74 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
75 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
75 a = nil
76 a = nil
76 begin
77 begin
77 a = Problem.find(s.problem_id)
78 a = Problem.find(s.problem_id)
78 rescue
79 rescue
79 a = nil
80 a = nil
80 end
81 end
81 @submissions[s.user_id][:sub][s.problem_id] =
82 @submissions[s.user_id][:sub][s.problem_id] =
82 { prob_name: (a ? a.full_name : '(NULL)'),
83 { prob_name: (a ? a.full_name : '(NULL)'),
83 sub_ids: [s.id] }
84 sub_ids: [s.id] }
84 else
85 else
85 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
86 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
86 end
87 end
87 @submissions[s.user_id][:count] += 1
88 @submissions[s.user_id][:count] += 1
88 end
89 end
89 end
90 end
90 end
91 end
91
92
92 def problem_hof
93 def problem_hof
93 # gen problem list
94 # gen problem list
94 @user = User.find(session[:user_id])
95 @user = User.find(session[:user_id])
95 @problems = @user.available_problems
96 @problems = @user.available_problems
96
97
97 # get selected problems or the default
98 # get selected problems or the default
98 if params[:id]
99 if params[:id]
99 begin
100 begin
100 @problem = Problem.available.find(params[:id])
101 @problem = Problem.available.find(params[:id])
101 rescue
102 rescue
102 redirect_to action: :problem_hof
103 redirect_to action: :problem_hof
103 flash[:notice] = 'Error: submissions for that problem are not viewable.'
104 flash[:notice] = 'Error: submissions for that problem are not viewable.'
104 return
105 return
105 end
106 end
106 end
107 end
107
108
108 return unless @problem
109 return unless @problem
109
110
110 @by_lang = {} #aggregrate by language
111 @by_lang = {} #aggregrate by language
111
112
112 range =65
113 range =65
113 @histogram = { data: Array.new(range,0), summary: {} }
114 @histogram = { data: Array.new(range,0), summary: {} }
114 @summary = {count: 0, solve: 0, attempt: 0}
115 @summary = {count: 0, solve: 0, attempt: 0}
115 user = Hash.new(0)
116 user = Hash.new(0)
116 Submission.where(problem_id: @problem.id).find_each do |sub|
117 Submission.where(problem_id: @problem.id).find_each do |sub|
117 #histogram
118 #histogram
118 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
119 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
119 @histogram[:data][d.to_i] += 1 if d < range
120 @histogram[:data][d.to_i] += 1 if d < range
120
121
121 next unless sub.points
122 next unless sub.points
122 @summary[:count] += 1
123 @summary[:count] += 1
123 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
124 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
124
125
125 lang = Language.find_by_id(sub.language_id)
126 lang = Language.find_by_id(sub.language_id)
126 next unless lang
127 next unless lang
127 next unless sub.points >= @problem.full_score
128 next unless sub.points >= @problem.full_score
128
129
129 #initialize
130 #initialize
130 unless @by_lang.has_key?(lang.pretty_name)
131 unless @by_lang.has_key?(lang.pretty_name)
131 @by_lang[lang.pretty_name] = {
132 @by_lang[lang.pretty_name] = {
132 runtime: { avail: false, value: 2**30-1 },
133 runtime: { avail: false, value: 2**30-1 },
133 memory: { avail: false, value: 2**30-1 },
134 memory: { avail: false, value: 2**30-1 },
134 length: { avail: false, value: 2**30-1 },
135 length: { avail: false, value: 2**30-1 },
135 first: { avail: false, value: DateTime.new(3000,1,1) }
136 first: { avail: false, value: DateTime.new(3000,1,1) }
136 }
137 }
137 end
138 end
138
139
139 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
140 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
140 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
141 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
141 end
142 end
142
143
143 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
144 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
144 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
145 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
145 end
146 end
146
147
147 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
148 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
148 !sub.user.admin?
149 !sub.user.admin?
149 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
150 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
150 end
151 end
151
152
152 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
153 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
153 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
154 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
154 end
155 end
155 end
156 end
156
157
157 #process user_id
158 #process user_id
158 @by_lang.each do |lang,prop|
159 @by_lang.each do |lang,prop|
159 prop.each do |k,v|
160 prop.each do |k,v|
160 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
161 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
161 end
162 end
162 end
163 end
163
164
164 #sum into best
165 #sum into best
165 if @by_lang and @by_lang.first
166 if @by_lang and @by_lang.first
166 @best = @by_lang.first[1].clone
167 @best = @by_lang.first[1].clone
167 @by_lang.each do |lang,prop|
168 @by_lang.each do |lang,prop|
168 if @best[:runtime][:value] >= prop[:runtime][:value]
169 if @best[:runtime][:value] >= prop[:runtime][:value]
169 @best[:runtime] = prop[:runtime]
170 @best[:runtime] = prop[:runtime]
170 @best[:runtime][:lang] = lang
171 @best[:runtime][:lang] = lang
171 end
172 end
172 if @best[:memory][:value] >= prop[:memory][:value]
173 if @best[:memory][:value] >= prop[:memory][:value]
173 @best[:memory] = prop[:memory]
174 @best[:memory] = prop[:memory]
174 @best[:memory][:lang] = lang
175 @best[:memory][:lang] = lang
175 end
176 end
176 if @best[:length][:value] >= prop[:length][:value]
177 if @best[:length][:value] >= prop[:length][:value]
177 @best[:length] = prop[:length]
178 @best[:length] = prop[:length]
178 @best[:length][:lang] = lang
179 @best[:length][:lang] = lang
179 end
180 end
180 if @best[:first][:value] >= prop[:first][:value]
181 if @best[:first][:value] >= prop[:first][:value]
181 @best[:first] = prop[:first]
182 @best[:first] = prop[:first]
182 @best[:first][:lang] = lang
183 @best[:first][:lang] = lang
183 end
184 end
184 end
185 end
185 end
186 end
186
187
187 @histogram[:summary][:max] = [@histogram[:data].max,1].max
188 @histogram[:summary][:max] = [@histogram[:data].max,1].max
188 @summary[:attempt] = user.count
189 @summary[:attempt] = user.count
189 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
190 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
190 end
191 end
191
192
192 def stuck #report struggling user,problem
193 def stuck #report struggling user,problem
193 # init
194 # init
194 user,problem = nil
195 user,problem = nil
195 solve = true
196 solve = true
196 tries = 0
197 tries = 0
197 @struggle = Array.new
198 @struggle = Array.new
198 record = {}
199 record = {}
199 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
200 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
200 next unless sub.problem and sub.user
201 next unless sub.problem and sub.user
201 if user != sub.user_id or problem != sub.problem_id
202 if user != sub.user_id or problem != sub.problem_id
202 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
203 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
203 record = {user: sub.user, problem: sub.problem}
204 record = {user: sub.user, problem: sub.problem}
204 user,problem = sub.user_id, sub.problem_id
205 user,problem = sub.user_id, sub.problem_id
205 solve = false
206 solve = false
206 tries = 0
207 tries = 0
207 end
208 end
208 if sub.points >= sub.problem.full_score
209 if sub.points >= sub.problem.full_score
209 solve = true
210 solve = true
210 else
211 else
211 tries += 1
212 tries += 1
212 end
213 end
213 end
214 end
214 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
215 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
215 @struggle = @struggle[0..50]
216 @struggle = @struggle[0..50]
216 end
217 end
217
218
218
219
219 def multiple_login
220 def multiple_login
220 #user with multiple IP
221 #user with multiple IP
221 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
222 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
222 last,count = 0,0
223 last,count = 0,0
223 first = 0
224 first = 0
224 @users = []
225 @users = []
225 raw.each do |r|
226 raw.each do |r|
226 if last != r.user.login
227 if last != r.user.login
227 count = 1
228 count = 1
228 last = r.user.login
229 last = r.user.login
229 first = r
230 first = r
230 else
231 else
231 @users << first if count == 1
232 @users << first if count == 1
232 @users << r
233 @users << r
233 count += 1
234 count += 1
234 end
235 end
235 end
236 end
236
237
237 #IP with multiple user
238 #IP with multiple user
238 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
239 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
239 last,count = 0,0
240 last,count = 0,0
240 first = 0
241 first = 0
241 @ip = []
242 @ip = []
242 raw.each do |r|
243 raw.each do |r|
243 if last != r.ip_address
244 if last != r.ip_address
244 count = 1
245 count = 1
245 last = r.ip_address
246 last = r.ip_address
246 first = r
247 first = r
247 else
248 else
248 @ip << first if count == 1
249 @ip << first if count == 1
249 @ip << r
250 @ip << r
250 count += 1
251 count += 1
251 end
252 end
252 end
253 end
253 end
254 end
254
255
256 + def cheat_report
257 + date_and_time = '%Y-%m-%d %H:%M'
258 + begin
259 + md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
260 + @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
261 + rescue
262 + @since_time = Time.zone.now.ago( 90.minutes)
255 end
263 end
264 + begin
265 + md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
266 + @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
267 + rescue
268 + @until_time = Time.zone.now
269 + end
270 +
271 + #multi login
272 + @ml = Login.joins(:user).where("logins.created_at >= ? and logins.created_at <= ?",@since_time,@until_time).select('users.login,count(distinct ip_address) as count,users.full_name').group("users.id").having("count > 1")
273 +
274 + st = <<-SQL
275 + SELECT l2.*
276 + FROM logins l2 INNER JOIN
277 + (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
278 + FROM logins l
279 + INNER JOIN users u ON l.user_id = u.id
280 + WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
281 + GROUP BY u.id
282 + HAVING count > 1
283 + ) ml ON l2.user_id = ml.id
284 + WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
285 + UNION
286 + SELECT l2.*
287 + FROM logins l2 INNER JOIN
288 + (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
289 + FROM logins l
290 + INNER JOIN users u ON l.user_id = u.id
291 + WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
292 + GROUP BY l.ip_address
293 + HAVING count > 1
294 + ) ml on ml.ip_address = l2.ip_address
295 + INNER JOIN users u ON l2.user_id = u.id
296 + WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
297 + ORDER BY ip_address,created_at
298 + SQL
299 + @mld = Login.find_by_sql(st)
300 +
301 + st = <<-SQL
302 + SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
303 + FROM submissions s INNER JOIN
304 + (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
305 + FROM logins l
306 + INNER JOIN users u ON l.user_id = u.id
307 + WHERE l.created_at >= ? and l.created_at <= ?
308 + GROUP BY u.id
309 + HAVING count > 1
310 + ) ml ON s.user_id = ml.id
311 + WHERE s.submitted_at >= ? and s.submitted_at <= ?
312 + UNION
313 + SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
314 + FROM submissions s INNER JOIN
315 + (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
316 + FROM logins l
317 + INNER JOIN users u ON l.user_id = u.id
318 + WHERE l.created_at >= ? and l.created_at <= ?
319 + GROUP BY l.ip_address
320 + HAVING count > 1
321 + ) ml on ml.ip_address = s.ip_address
322 + WHERE s.submitted_at >= ? and s.submitted_at <= ?
323 + ORDER BY ip_address,submitted_at
324 + SQL
325 + @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
326 + @since_time,@until_time,
327 + @since_time,@until_time,
328 + @since_time,@until_time])
329 +
330 + end
331 +
332 + def cheat_scruntinize
333 + #convert date & time
334 + date_and_time = '%Y-%m-%d %H:%M'
335 + begin
336 + md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
337 + @since_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
338 + rescue
339 + @since_time = Time.zone.now.ago( 90.minutes)
340 + end
341 + begin
342 + md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
343 + @until_time = Time.zone.local(md[1].to_i,md[2].to_i,md[3].to_i,md[4].to_i,md[5].to_i)
344 + rescue
345 + @until_time = Time.zone.now
346 + end
347 +
348 + #convert sid
349 + @sid = params[:SID].split(/[,\s]/) if params[:SID]
350 + unless @sid and @sid.size > 0
351 + return
352 + redirect_to actoin: :cheat_scruntinize
353 + flash[:notice] = 'Please enter at least 1 student id'
354 + end
355 + mark = Array.new(@sid.size,'?')
356 + condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
357 +
358 + @st = <<-SQL
359 + SELECT l.created_at as submitted_at ,-1 as id,u.login,u.full_name,l.ip_address,"" as problem_id,"" as points,l.user_id
360 + FROM logins l INNER JOIN users u on l.user_id = u.id
361 + WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
362 + UNION
363 + SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
364 + FROM submissions s INNER JOIN users u ON s.user_id = u.id
365 + WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
366 + ORDER BY submitted_at
367 + SQL
368 +
369 + p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
370 + @logs = Submission.joins(:problem).find_by_sql(p)
371 +
372 +
373 +
374 +
375 +
376 + end
377 +
378 +
379 + end
@@ -1,3 +1,5
1 class Login < ActiveRecord::Base
1 class Login < ActiveRecord::Base
2 + belongs_to :user
3 +
2 attr_accessible :ip_address, :logged_in_at, :user_id
4 attr_accessible :ip_address, :logged_in_at, :user_id
3 end
5 end
@@ -118,259 +118,263
118 resp = http.request(req,param)
118 resp = http.request(req,param)
119 result = JSON.parse resp.body
119 result = JSON.parse resp.body
120 end
120 end
121 return true if result["type"] == "beanStudent"
121 return true if result["type"] == "beanStudent"
122 rescue
122 rescue
123 return false
123 return false
124 end
124 end
125 return false
125 return false
126 end
126 end
127
127
128 def admin?
128 def admin?
129 self.roles.detect {|r| r.name == 'admin' }
129 self.roles.detect {|r| r.name == 'admin' }
130 end
130 end
131
131
132 def email_for_editing
132 def email_for_editing
133 if self.email==nil
133 if self.email==nil
134 "(unknown)"
134 "(unknown)"
135 elsif self.email==''
135 elsif self.email==''
136 "(blank)"
136 "(blank)"
137 else
137 else
138 self.email
138 self.email
139 end
139 end
140 end
140 end
141
141
142 def email_for_editing=(e)
142 def email_for_editing=(e)
143 self.email=e
143 self.email=e
144 end
144 end
145
145
146 def alias_for_editing
146 def alias_for_editing
147 if self.alias==nil
147 if self.alias==nil
148 "(unknown)"
148 "(unknown)"
149 elsif self.alias==''
149 elsif self.alias==''
150 "(blank)"
150 "(blank)"
151 else
151 else
152 self.alias
152 self.alias
153 end
153 end
154 end
154 end
155
155
156 def alias_for_editing=(e)
156 def alias_for_editing=(e)
157 self.alias=e
157 self.alias=e
158 end
158 end
159
159
160 def activation_key
160 def activation_key
161 if self.hashed_password==nil
161 if self.hashed_password==nil
162 encrypt_new_password
162 encrypt_new_password
163 end
163 end
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
165 end
165 end
166
166
167 def verify_activation_key(key)
167 def verify_activation_key(key)
168 key == activation_key
168 key == activation_key
169 end
169 end
170
170
171 def self.random_password(length=5)
171 def self.random_password(length=5)
172 chars = 'abcdefghjkmnopqrstuvwxyz'
172 chars = 'abcdefghjkmnopqrstuvwxyz'
173 password = ''
173 password = ''
174 length.times { password << chars[rand(chars.length - 1)] }
174 length.times { password << chars[rand(chars.length - 1)] }
175 password
175 password
176 end
176 end
177
177
178 def self.find_non_admin_with_prefix(prefix='')
178 def self.find_non_admin_with_prefix(prefix='')
179 users = User.find(:all)
179 users = User.find(:all)
180 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
180 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
181 end
181 end
182
182
183 # Contest information
183 # Contest information
184
184
185 def self.find_users_with_no_contest()
185 def self.find_users_with_no_contest()
186 users = User.find(:all)
186 users = User.find(:all)
187 return users.find_all { |u| u.contests.length == 0 }
187 return users.find_all { |u| u.contests.length == 0 }
188 end
188 end
189
189
190
190
191 def contest_time_left
191 def contest_time_left
192 if GraderConfiguration.contest_mode?
192 if GraderConfiguration.contest_mode?
193 return nil if site==nil
193 return nil if site==nil
194 return site.time_left
194 return site.time_left
195 elsif GraderConfiguration.indv_contest_mode?
195 elsif GraderConfiguration.indv_contest_mode?
196 time_limit = GraderConfiguration.contest_time_limit
196 time_limit = GraderConfiguration.contest_time_limit
197 if time_limit == nil
197 if time_limit == nil
198 return nil
198 return nil
199 end
199 end
200 if contest_stat==nil or contest_stat.started_at==nil
200 if contest_stat==nil or contest_stat.started_at==nil
201 return (Time.now.gmtime + time_limit) - Time.now.gmtime
201 return (Time.now.gmtime + time_limit) - Time.now.gmtime
202 else
202 else
203 finish_time = contest_stat.started_at + time_limit
203 finish_time = contest_stat.started_at + time_limit
204 current_time = Time.now.gmtime
204 current_time = Time.now.gmtime
205 if current_time > finish_time
205 if current_time > finish_time
206 return 0
206 return 0
207 else
207 else
208 return finish_time - current_time
208 return finish_time - current_time
209 end
209 end
210 end
210 end
211 else
211 else
212 return nil
212 return nil
213 end
213 end
214 end
214 end
215
215
216 def contest_finished?
216 def contest_finished?
217 if GraderConfiguration.contest_mode?
217 if GraderConfiguration.contest_mode?
218 return false if site==nil
218 return false if site==nil
219 return site.finished?
219 return site.finished?
220 elsif GraderConfiguration.indv_contest_mode?
220 elsif GraderConfiguration.indv_contest_mode?
221 return false if self.contest_stat(true)==nil
221 return false if self.contest_stat(true)==nil
222 return contest_time_left == 0
222 return contest_time_left == 0
223 else
223 else
224 return false
224 return false
225 end
225 end
226 end
226 end
227
227
228 def contest_started?
228 def contest_started?
229 if GraderConfiguration.indv_contest_mode?
229 if GraderConfiguration.indv_contest_mode?
230 stat = self.contest_stat
230 stat = self.contest_stat
231 return ((stat != nil) and (stat.started_at != nil))
231 return ((stat != nil) and (stat.started_at != nil))
232 elsif GraderConfiguration.contest_mode?
232 elsif GraderConfiguration.contest_mode?
233 return true if site==nil
233 return true if site==nil
234 return site.started
234 return site.started
235 else
235 else
236 return true
236 return true
237 end
237 end
238 end
238 end
239
239
240 def update_start_time
240 def update_start_time
241 stat = self.contest_stat
241 stat = self.contest_stat
242 if stat == nil or stat.started_at == nil
242 if stat == nil or stat.started_at == nil
243 stat ||= UserContestStat.new(:user => self)
243 stat ||= UserContestStat.new(:user => self)
244 stat.started_at = Time.now.gmtime
244 stat.started_at = Time.now.gmtime
245 stat.save
245 stat.save
246 end
246 end
247 end
247 end
248
248
249 def problem_in_user_contests?(problem)
249 def problem_in_user_contests?(problem)
250 problem_contests = problem.contests.all
250 problem_contests = problem.contests.all
251
251
252 if problem_contests.length == 0 # this is public contest
252 if problem_contests.length == 0 # this is public contest
253 return true
253 return true
254 end
254 end
255
255
256 contests.each do |contest|
256 contests.each do |contest|
257 if problem_contests.find {|c| c.id == contest.id }
257 if problem_contests.find {|c| c.id == contest.id }
258 return true
258 return true
259 end
259 end
260 end
260 end
261 return false
261 return false
262 end
262 end
263
263
264 def available_problems_group_by_contests
264 def available_problems_group_by_contests
265 contest_problems = []
265 contest_problems = []
266 pin = {}
266 pin = {}
267 contests.enabled.each do |contest|
267 contests.enabled.each do |contest|
268 available_problems = contest.problems.available
268 available_problems = contest.problems.available
269 contest_problems << {
269 contest_problems << {
270 :contest => contest,
270 :contest => contest,
271 :problems => available_problems
271 :problems => available_problems
272 }
272 }
273 available_problems.each {|p| pin[p.id] = true}
273 available_problems.each {|p| pin[p.id] = true}
274 end
274 end
275 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
275 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
276 contest_problems << {
276 contest_problems << {
277 :contest => nil,
277 :contest => nil,
278 :problems => other_avaiable_problems
278 :problems => other_avaiable_problems
279 }
279 }
280 return contest_problems
280 return contest_problems
281 end
281 end
282
282
283 def available_problems
283 def available_problems
284 if not GraderConfiguration.multicontests?
284 if not GraderConfiguration.multicontests?
285 return Problem.find_available_problems
285 return Problem.find_available_problems
286 else
286 else
287 contest_problems = []
287 contest_problems = []
288 pin = {}
288 pin = {}
289 contests.enabled.each do |contest|
289 contests.enabled.each do |contest|
290 contest.problems.available.each do |problem|
290 contest.problems.available.each do |problem|
291 if not pin.has_key? problem.id
291 if not pin.has_key? problem.id
292 contest_problems << problem
292 contest_problems << problem
293 end
293 end
294 pin[problem.id] = true
294 pin[problem.id] = true
295 end
295 end
296 end
296 end
297 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
297 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
298 return contest_problems + other_avaiable_problems
298 return contest_problems + other_avaiable_problems
299 end
299 end
300 end
300 end
301
301
302 def can_view_problem?(problem)
302 def can_view_problem?(problem)
303 if not GraderConfiguration.multicontests?
303 if not GraderConfiguration.multicontests?
304 return problem.available
304 return problem.available
305 else
305 else
306 return problem_in_user_contests? problem
306 return problem_in_user_contests? problem
307 end
307 end
308 end
308 end
309
309
310 + def self.clear_last_login
311 + User.update_all(:last_ip => nil)
312 + end
313 +
310 protected
314 protected
311 def encrypt_new_password
315 def encrypt_new_password
312 return if password.blank?
316 return if password.blank?
313 self.salt = (10+rand(90)).to_s
317 self.salt = (10+rand(90)).to_s
314 self.hashed_password = User.encrypt(self.password,self.salt)
318 self.hashed_password = User.encrypt(self.password,self.salt)
315 end
319 end
316
320
317 def assign_default_site
321 def assign_default_site
318 # have to catch error when migrating (because self.site is not available).
322 # have to catch error when migrating (because self.site is not available).
319 begin
323 begin
320 if self.site==nil
324 if self.site==nil
321 self.site = Site.find_by_name('default')
325 self.site = Site.find_by_name('default')
322 if self.site==nil
326 if self.site==nil
323 self.site = Site.find(1) # when 'default has be renamed'
327 self.site = Site.find(1) # when 'default has be renamed'
324 end
328 end
325 end
329 end
326 rescue
330 rescue
327 end
331 end
328 end
332 end
329
333
330 def assign_default_contest
334 def assign_default_contest
331 # have to catch error when migrating (because self.site is not available).
335 # have to catch error when migrating (because self.site is not available).
332 begin
336 begin
333 if self.contests.length == 0
337 if self.contests.length == 0
334 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
338 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
335 if default_contest
339 if default_contest
336 self.contests = [default_contest]
340 self.contests = [default_contest]
337 end
341 end
338 end
342 end
339 rescue
343 rescue
340 end
344 end
341 end
345 end
342
346
343 def password_required?
347 def password_required?
344 self.hashed_password.blank? || !self.password.blank?
348 self.hashed_password.blank? || !self.password.blank?
345 end
349 end
346
350
347 def self.encrypt(string,salt)
351 def self.encrypt(string,salt)
348 Digest::SHA1.hexdigest(salt + string)
352 Digest::SHA1.hexdigest(salt + string)
349 end
353 end
350
354
351 def uniqueness_of_email_from_activated_users
355 def uniqueness_of_email_from_activated_users
352 user = User.activated_users.find_by_email(self.email)
356 user = User.activated_users.find_by_email(self.email)
353 if user and (user.login != self.login)
357 if user and (user.login != self.login)
354 self.errors.add(:base,"Email has already been taken")
358 self.errors.add(:base,"Email has already been taken")
355 end
359 end
356 end
360 end
357
361
358 def enough_time_interval_between_same_email_registrations
362 def enough_time_interval_between_same_email_registrations
359 return if !self.new_record?
363 return if !self.new_record?
360 return if self.activated
364 return if self.activated
361 open_user = User.find_by_email(self.email,
365 open_user = User.find_by_email(self.email,
362 :order => 'created_at DESC')
366 :order => 'created_at DESC')
363 if open_user and open_user.created_at and
367 if open_user and open_user.created_at and
364 (open_user.created_at > Time.now.gmtime - 5.minutes)
368 (open_user.created_at > Time.now.gmtime - 5.minutes)
365 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
369 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
366 end
370 end
367 end
371 end
368
372
369 def email_validation?
373 def email_validation?
370 begin
374 begin
371 return VALIDATE_USER_EMAILS
375 return VALIDATE_USER_EMAILS
372 rescue
376 rescue
373 return false
377 return false
374 end
378 end
375 end
379 end
376 end
380 end
@@ -1,23 +1,23
1
1
2 = form_tag({session: :url }) do
2 = form_tag({session: :url }) do
3 .submitbox
3 .submitbox
4 %table
4 %table
5 %tr
5 %tr
6 %td{colspan: 6, style: 'font-weight: bold'}= title
6 %td{colspan: 6, style: 'font-weight: bold'}= title
7 %tr
7 %tr
8 %td{style: 'width: 120px; font-weight: bold'}= param_text
8 %td{style: 'width: 120px; font-weight: bold'}= param_text
9 %td{align: 'right'} since:
9 %td{align: 'right'} since:
10 - %td= text_field_tag 'since_datetime'
10 + %td= text_field_tag 'since_datetime', @since_time
11 %tr
11 %tr
12 %td
12 %td
13 %td{align: 'right'} until:
13 %td{align: 'right'} until:
14 - %td= text_field_tag 'until_datetime'
14 + %td= text_field_tag 'until_datetime', @until_time
15 %tr
15 %tr
16 %td
16 %td
17 %td
17 %td
18 %td Blank mean no condition
18 %td Blank mean no condition
19 %tr
19 %tr
20 %td
20 %td
21 %td
21 %td
22 %td= submit_tag 'query'
22 %td= submit_tag 'query'
23
23
@@ -1,8 +1,9
1
1
2 .task-menu
2 .task-menu
3 Reports
3 Reports
4 %br/
4 %br/
5 = link_to '[Hall of Fame]', :action => 'problem_hof'
5 = link_to '[Hall of Fame]', :action => 'problem_hof'
6 = link_to '[Struggle]', :action => 'stuck'
6 = link_to '[Struggle]', :action => 'stuck'
7 - = link_to '[Login]', :action => 'login_stat'
7 + = link_to '[Cheat Detection]', :action => 'cheat_report'
8 + = link_to '[Cheat Detail]', :action => 'cheat_scruntinize'
8 = link_to '[Multiple Login]', :action => 'multiple_login'
9 = link_to '[Multiple Login]', :action => 'multiple_login'
@@ -1,249 +1,250
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended to check this file into your version control system.
12 # It's strongly recommended to check this file into your version control system.
13
13
14 - ActiveRecord::Schema.define(:version => 20150203153534) do
14 + ActiveRecord::Schema.define(:version => 20150618085823) do
15
15
16 create_table "announcements", :force => true do |t|
16 create_table "announcements", :force => true do |t|
17 t.string "author"
17 t.string "author"
18 t.text "body", :limit => 16777215
18 t.text "body", :limit => 16777215
19 t.boolean "published"
19 t.boolean "published"
20 t.datetime "created_at", :null => false
20 t.datetime "created_at", :null => false
21 t.datetime "updated_at", :null => false
21 t.datetime "updated_at", :null => false
22 t.boolean "frontpage", :default => false
22 t.boolean "frontpage", :default => false
23 t.boolean "contest_only", :default => false
23 t.boolean "contest_only", :default => false
24 t.string "title"
24 t.string "title"
25 t.string "notes"
25 t.string "notes"
26 end
26 end
27
27
28 create_table "contests", :force => true do |t|
28 create_table "contests", :force => true do |t|
29 t.string "title"
29 t.string "title"
30 t.boolean "enabled"
30 t.boolean "enabled"
31 t.datetime "created_at", :null => false
31 t.datetime "created_at", :null => false
32 t.datetime "updated_at", :null => false
32 t.datetime "updated_at", :null => false
33 t.string "name"
33 t.string "name"
34 end
34 end
35
35
36 create_table "contests_problems", :id => false, :force => true do |t|
36 create_table "contests_problems", :id => false, :force => true do |t|
37 t.integer "contest_id"
37 t.integer "contest_id"
38 t.integer "problem_id"
38 t.integer "problem_id"
39 end
39 end
40
40
41 create_table "contests_users", :id => false, :force => true do |t|
41 create_table "contests_users", :id => false, :force => true do |t|
42 t.integer "contest_id"
42 t.integer "contest_id"
43 t.integer "user_id"
43 t.integer "user_id"
44 end
44 end
45
45
46 create_table "countries", :force => true do |t|
46 create_table "countries", :force => true do |t|
47 t.string "name"
47 t.string "name"
48 t.datetime "created_at", :null => false
48 t.datetime "created_at", :null => false
49 t.datetime "updated_at", :null => false
49 t.datetime "updated_at", :null => false
50 end
50 end
51
51
52 create_table "descriptions", :force => true do |t|
52 create_table "descriptions", :force => true do |t|
53 t.text "body", :limit => 16777215
53 t.text "body", :limit => 16777215
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 t.datetime "created_at", :null => false
55 t.datetime "created_at", :null => false
56 t.datetime "updated_at", :null => false
56 t.datetime "updated_at", :null => false
57 end
57 end
58
58
59 create_table "grader_configurations", :force => true do |t|
59 create_table "grader_configurations", :force => true do |t|
60 t.string "key"
60 t.string "key"
61 t.string "value_type"
61 t.string "value_type"
62 t.string "value"
62 t.string "value"
63 t.datetime "created_at", :null => false
63 t.datetime "created_at", :null => false
64 t.datetime "updated_at", :null => false
64 t.datetime "updated_at", :null => false
65 t.text "description", :limit => 16777215
65 t.text "description", :limit => 16777215
66 end
66 end
67
67
68 create_table "grader_processes", :force => true do |t|
68 create_table "grader_processes", :force => true do |t|
69 t.string "host", :limit => 20
69 t.string "host", :limit => 20
70 t.integer "pid"
70 t.integer "pid"
71 t.string "mode"
71 t.string "mode"
72 t.boolean "active"
72 t.boolean "active"
73 t.datetime "created_at", :null => false
73 t.datetime "created_at", :null => false
74 t.datetime "updated_at", :null => false
74 t.datetime "updated_at", :null => false
75 t.integer "task_id"
75 t.integer "task_id"
76 t.string "task_type"
76 t.string "task_type"
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
80 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
81
81
82 create_table "languages", :force => true do |t|
82 create_table "languages", :force => true do |t|
83 t.string "name", :limit => 10
83 t.string "name", :limit => 10
84 t.string "pretty_name"
84 t.string "pretty_name"
85 t.string "ext", :limit => 10
85 t.string "ext", :limit => 10
86 t.string "common_ext"
86 t.string "common_ext"
87 end
87 end
88
88
89 create_table "logins", :force => true do |t|
89 create_table "logins", :force => true do |t|
90 - t.string "user_id"
90 + t.integer "user_id"
91 t.string "ip_address"
91 t.string "ip_address"
92 t.datetime "created_at", :null => false
92 t.datetime "created_at", :null => false
93 t.datetime "updated_at", :null => false
93 t.datetime "updated_at", :null => false
94 end
94 end
95
95
96 create_table "messages", :force => true do |t|
96 create_table "messages", :force => true do |t|
97 t.integer "sender_id"
97 t.integer "sender_id"
98 t.integer "receiver_id"
98 t.integer "receiver_id"
99 t.integer "replying_message_id"
99 t.integer "replying_message_id"
100 t.text "body", :limit => 16777215
100 t.text "body", :limit => 16777215
101 t.boolean "replied"
101 t.boolean "replied"
102 t.datetime "created_at", :null => false
102 t.datetime "created_at", :null => false
103 t.datetime "updated_at", :null => false
103 t.datetime "updated_at", :null => false
104 end
104 end
105
105
106 create_table "problems", :force => true do |t|
106 create_table "problems", :force => true do |t|
107 t.string "name", :limit => 30
107 t.string "name", :limit => 30
108 t.string "full_name"
108 t.string "full_name"
109 t.integer "full_score"
109 t.integer "full_score"
110 t.date "date_added"
110 t.date "date_added"
111 t.boolean "available"
111 t.boolean "available"
112 t.string "url"
112 t.string "url"
113 t.integer "description_id"
113 t.integer "description_id"
114 t.boolean "test_allowed"
114 t.boolean "test_allowed"
115 t.boolean "output_only"
115 t.boolean "output_only"
116 t.string "description_filename"
116 t.string "description_filename"
117 end
117 end
118
118
119 create_table "rights", :force => true do |t|
119 create_table "rights", :force => true do |t|
120 t.string "name"
120 t.string "name"
121 t.string "controller"
121 t.string "controller"
122 t.string "action"
122 t.string "action"
123 end
123 end
124
124
125 create_table "rights_roles", :id => false, :force => true do |t|
125 create_table "rights_roles", :id => false, :force => true do |t|
126 t.integer "right_id"
126 t.integer "right_id"
127 t.integer "role_id"
127 t.integer "role_id"
128 end
128 end
129
129
130 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
130 add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
131
131
132 create_table "roles", :force => true do |t|
132 create_table "roles", :force => true do |t|
133 t.string "name"
133 t.string "name"
134 end
134 end
135
135
136 create_table "roles_users", :id => false, :force => true do |t|
136 create_table "roles_users", :id => false, :force => true do |t|
137 t.integer "role_id"
137 t.integer "role_id"
138 t.integer "user_id"
138 t.integer "user_id"
139 end
139 end
140
140
141 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
141 add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
142
142
143 create_table "sessions", :force => true do |t|
143 create_table "sessions", :force => true do |t|
144 t.string "session_id"
144 t.string "session_id"
145 t.text "data", :limit => 16777215
145 t.text "data", :limit => 16777215
146 t.datetime "updated_at"
146 t.datetime "updated_at"
147 end
147 end
148
148
149 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
149 add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
150 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
150 add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
151
151
152 create_table "sites", :force => true do |t|
152 create_table "sites", :force => true do |t|
153 t.string "name"
153 t.string "name"
154 t.boolean "started"
154 t.boolean "started"
155 t.datetime "start_time"
155 t.datetime "start_time"
156 t.datetime "created_at", :null => false
156 t.datetime "created_at", :null => false
157 t.datetime "updated_at", :null => false
157 t.datetime "updated_at", :null => false
158 t.integer "country_id"
158 t.integer "country_id"
159 t.string "password"
159 t.string "password"
160 end
160 end
161
161
162 create_table "submissions", :force => true do |t|
162 create_table "submissions", :force => true do |t|
163 t.integer "user_id"
163 t.integer "user_id"
164 t.integer "problem_id"
164 t.integer "problem_id"
165 t.integer "language_id"
165 t.integer "language_id"
166 t.text "source", :limit => 16777215
166 t.text "source", :limit => 16777215
167 t.binary "binary"
167 t.binary "binary"
168 t.datetime "submitted_at"
168 t.datetime "submitted_at"
169 t.datetime "compiled_at"
169 t.datetime "compiled_at"
170 t.text "compiler_message", :limit => 16777215
170 t.text "compiler_message", :limit => 16777215
171 t.datetime "graded_at"
171 t.datetime "graded_at"
172 t.integer "points"
172 t.integer "points"
173 t.text "grader_comment", :limit => 16777215
173 t.text "grader_comment", :limit => 16777215
174 t.integer "number"
174 t.integer "number"
175 t.string "source_filename"
175 t.string "source_filename"
176 t.float "max_runtime"
176 t.float "max_runtime"
177 t.integer "peak_memory"
177 t.integer "peak_memory"
178 t.integer "effective_code_length"
178 t.integer "effective_code_length"
179 t.string "ip_address"
179 t.string "ip_address"
180 end
180 end
181
181
182 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
182 add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
183 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
183 add_index "submissions", ["user_id", "problem_id"], :name => "index_submissions_on_user_id_and_problem_id"
184
184
185 create_table "tasks", :force => true do |t|
185 create_table "tasks", :force => true do |t|
186 t.integer "submission_id"
186 t.integer "submission_id"
187 t.datetime "created_at"
187 t.datetime "created_at"
188 t.integer "status"
188 t.integer "status"
189 t.datetime "updated_at"
189 t.datetime "updated_at"
190 end
190 end
191
191
192 create_table "test_pairs", :force => true do |t|
192 create_table "test_pairs", :force => true do |t|
193 t.integer "problem_id"
193 t.integer "problem_id"
194 t.text "input", :limit => 2147483647
194 t.text "input", :limit => 2147483647
195 t.text "solution", :limit => 2147483647
195 t.text "solution", :limit => 2147483647
196 t.datetime "created_at", :null => false
196 t.datetime "created_at", :null => false
197 t.datetime "updated_at", :null => false
197 t.datetime "updated_at", :null => false
198 end
198 end
199
199
200 create_table "test_requests", :force => true do |t|
200 create_table "test_requests", :force => true do |t|
201 t.integer "user_id"
201 t.integer "user_id"
202 t.integer "problem_id"
202 t.integer "problem_id"
203 t.integer "submission_id"
203 t.integer "submission_id"
204 t.string "input_file_name"
204 t.string "input_file_name"
205 t.string "output_file_name"
205 t.string "output_file_name"
206 t.string "running_stat"
206 t.string "running_stat"
207 t.integer "status"
207 t.integer "status"
208 t.datetime "updated_at", :null => false
208 t.datetime "updated_at", :null => false
209 t.datetime "submitted_at"
209 t.datetime "submitted_at"
210 t.datetime "compiled_at"
210 t.datetime "compiled_at"
211 t.text "compiler_message", :limit => 16777215
211 t.text "compiler_message", :limit => 16777215
212 t.datetime "graded_at"
212 t.datetime "graded_at"
213 t.string "grader_comment"
213 t.string "grader_comment"
214 t.datetime "created_at", :null => false
214 t.datetime "created_at", :null => false
215 t.float "running_time"
215 t.float "running_time"
216 t.string "exit_status"
216 t.string "exit_status"
217 t.integer "memory_usage"
217 t.integer "memory_usage"
218 end
218 end
219
219
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
220 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
221
221
222 create_table "user_contest_stats", :force => true do |t|
222 create_table "user_contest_stats", :force => true do |t|
223 t.integer "user_id"
223 t.integer "user_id"
224 t.datetime "started_at"
224 t.datetime "started_at"
225 t.datetime "created_at", :null => false
225 t.datetime "created_at", :null => false
226 t.datetime "updated_at", :null => false
226 t.datetime "updated_at", :null => false
227 t.boolean "forced_logout"
227 t.boolean "forced_logout"
228 end
228 end
229
229
230 create_table "users", :force => true do |t|
230 create_table "users", :force => true do |t|
231 t.string "login", :limit => 50
231 t.string "login", :limit => 50
232 t.string "full_name"
232 t.string "full_name"
233 t.string "hashed_password"
233 t.string "hashed_password"
234 t.string "salt", :limit => 5
234 t.string "salt", :limit => 5
235 t.string "alias"
235 t.string "alias"
236 t.string "email"
236 t.string "email"
237 t.integer "site_id"
237 t.integer "site_id"
238 t.integer "country_id"
238 t.integer "country_id"
239 t.boolean "activated", :default => false
239 t.boolean "activated", :default => false
240 t.datetime "created_at"
240 t.datetime "created_at"
241 t.datetime "updated_at"
241 t.datetime "updated_at"
242 t.string "section"
242 t.string "section"
243 t.boolean "enabled", :default => true
243 t.boolean "enabled", :default => true
244 t.string "remark"
244 t.string "remark"
245 + t.string "last_ip"
245 end
246 end
246
247
247 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
248 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
248
249
249 end
250 end
@@ -1,223 +1,230
1 CONFIGURATIONS =
1 CONFIGURATIONS =
2 [
2 [
3 {
3 {
4 :key => 'system.single_user_mode',
4 :key => 'system.single_user_mode',
5 :value_type => 'boolean',
5 :value_type => 'boolean',
6 :default_value => 'false',
6 :default_value => 'false',
7 :description => 'Only admins can log in to the system when running under single user mode.'
7 :description => 'Only admins can log in to the system when running under single user mode.'
8 },
8 },
9
9
10 {
10 {
11 :key => 'ui.front.title',
11 :key => 'ui.front.title',
12 :value_type => 'string',
12 :value_type => 'string',
13 :default_value => 'Grader'
13 :default_value => 'Grader'
14 },
14 },
15
15
16 {
16 {
17 :key => 'ui.front.welcome_message',
17 :key => 'ui.front.welcome_message',
18 :value_type => 'string',
18 :value_type => 'string',
19 :default_value => 'Welcome!'
19 :default_value => 'Welcome!'
20 },
20 },
21
21
22 {
22 {
23 :key => 'ui.show_score',
23 :key => 'ui.show_score',
24 :value_type => 'boolean',
24 :value_type => 'boolean',
25 :default_value => 'true'
25 :default_value => 'true'
26 },
26 },
27
27
28 {
28 {
29 :key => 'contest.time_limit',
29 :key => 'contest.time_limit',
30 :value_type => 'string',
30 :value_type => 'string',
31 :default_value => 'unlimited',
31 :default_value => 'unlimited',
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.'
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 :key => 'system.mode',
36 :key => 'system.mode',
37 :value_type => 'string',
37 :value_type => 'string',
38 :default_value => 'standard',
38 :default_value => 'standard',
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 },
40 },
41
41
42 {
42 {
43 :key => 'contest.name',
43 :key => 'contest.name',
44 :value_type => 'string',
44 :value_type => 'string',
45 :default_value => 'Grader',
45 :default_value => 'Grader',
46 :description => 'This name will be shown on the user header bar.'
46 :description => 'This name will be shown on the user header bar.'
47 },
47 },
48
48
49 {
49 {
50 :key => 'contest.multisites',
50 :key => 'contest.multisites',
51 :value_type => 'boolean',
51 :value_type => 'boolean',
52 :default_value => 'false',
52 :default_value => 'false',
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.'
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 {
57 :key => 'right.user_hall_of_fame',
57 :key => 'right.user_hall_of_fame',
58 :value_type => 'boolean',
58 :value_type => 'boolean',
59 :default_value => 'false',
59 :default_value => 'false',
60 :description => 'If true, any user can access hall of fame page.'
60 :description => 'If true, any user can access hall of fame page.'
61 },
61 },
62
62
63 {
63 {
64 + :key => 'right.multiple_ip_login',
65 + :value_type => 'boolean',
66 + :default_value => 'true',
67 + :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
68 + },
69 +
70 + {
64 :key => 'right.user_view_submission',
71 :key => 'right.user_view_submission',
65 :value_type => 'boolean',
72 :value_type => 'boolean',
66 :default_value => 'false',
73 :default_value => 'false',
67 :description => 'If true, any user can view submissions of every one.'
74 :description => 'If true, any user can view submissions of every one.'
68 },
75 },
69
76
70 # If Configuration['system.online_registration'] is true, the
77 # If Configuration['system.online_registration'] is true, the
71 # system allows online registration, and will use these
78 # system allows online registration, and will use these
72 # information for sending confirmation emails.
79 # information for sending confirmation emails.
73 {
80 {
74 :key => 'system.online_registration.smtp',
81 :key => 'system.online_registration.smtp',
75 :value_type => 'string',
82 :value_type => 'string',
76 :default_value => 'smtp.somehost.com'
83 :default_value => 'smtp.somehost.com'
77 },
84 },
78
85
79 {
86 {
80 :key => 'system.online_registration.from',
87 :key => 'system.online_registration.from',
81 :value_type => 'string',
88 :value_type => 'string',
82 :default_value => 'your.email@address'
89 :default_value => 'your.email@address'
83 },
90 },
84
91
85 {
92 {
86 :key => 'system.admin_email',
93 :key => 'system.admin_email',
87 :value_type => 'string',
94 :value_type => 'string',
88 :default_value => 'admin@admin.email'
95 :default_value => 'admin@admin.email'
89 },
96 },
90
97
91 {
98 {
92 :key => 'system.user_setting_enabled',
99 :key => 'system.user_setting_enabled',
93 :value_type => 'boolean',
100 :value_type => 'boolean',
94 :default_value => 'true',
101 :default_value => 'true',
95 :description => 'If this option is true, users can change their settings'
102 :description => 'If this option is true, users can change their settings'
96 },
103 },
97
104
98 {
105 {
99 :key => 'system.user_setting_enabled',
106 :key => 'system.user_setting_enabled',
100 :value_type => 'boolean',
107 :value_type => 'boolean',
101 :default_value => 'true',
108 :default_value => 'true',
102 :description => 'If this option is true, users can change their settings'
109 :description => 'If this option is true, users can change their settings'
103 },
110 },
104
111
105 # If Configuration['contest.test_request.early_timeout'] is true
112 # If Configuration['contest.test_request.early_timeout'] is true
106 # the user will not be able to use test request at 30 minutes
113 # the user will not be able to use test request at 30 minutes
107 # before the contest ends.
114 # before the contest ends.
108 {
115 {
109 :key => 'contest.test_request.early_timeout',
116 :key => 'contest.test_request.early_timeout',
110 :value_type => 'boolean',
117 :value_type => 'boolean',
111 :default_value => 'false'
118 :default_value => 'false'
112 },
119 },
113
120
114 {
121 {
115 :key => 'system.multicontests',
122 :key => 'system.multicontests',
116 :value_type => 'boolean',
123 :value_type => 'boolean',
117 :default_value => 'false'
124 :default_value => 'false'
118 },
125 },
119
126
120 {
127 {
121 :key => 'contest.confirm_indv_contest_start',
128 :key => 'contest.confirm_indv_contest_start',
122 :value_type => 'boolean',
129 :value_type => 'boolean',
123 :default_value => 'false'
130 :default_value => 'false'
124 },
131 },
125
132
126 {
133 {
127 :key => 'contest.default_contest_name',
134 :key => 'contest.default_contest_name',
128 :value_type => 'string',
135 :value_type => 'string',
129 :default_value => 'none',
136 :default_value => 'none',
130 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
137 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
131 }
138 }
132
139
133 ]
140 ]
134
141
135
142
136 def create_configuration_key(key,
143 def create_configuration_key(key,
137 value_type,
144 value_type,
138 default_value,
145 default_value,
139 description='')
146 description='')
140 conf = (GraderConfiguration.find_by_key(key) ||
147 conf = (GraderConfiguration.find_by_key(key) ||
141 GraderConfiguration.new(:key => key,
148 GraderConfiguration.new(:key => key,
142 :value_type => value_type,
149 :value_type => value_type,
143 :value => default_value))
150 :value => default_value))
144 conf.description = description
151 conf.description = description
145 conf.save
152 conf.save
146 end
153 end
147
154
148 def seed_config
155 def seed_config
149 CONFIGURATIONS.each do |conf|
156 CONFIGURATIONS.each do |conf|
150 if conf.has_key? :description
157 if conf.has_key? :description
151 desc = conf[:description]
158 desc = conf[:description]
152 else
159 else
153 desc = ''
160 desc = ''
154 end
161 end
155 create_configuration_key(conf[:key],
162 create_configuration_key(conf[:key],
156 conf[:value_type],
163 conf[:value_type],
157 conf[:default_value],
164 conf[:default_value],
158 desc)
165 desc)
159 end
166 end
160 end
167 end
161
168
162 def seed_roles
169 def seed_roles
163 return if Role.find_by_name('admin')
170 return if Role.find_by_name('admin')
164
171
165 role = Role.create(:name => 'admin')
172 role = Role.create(:name => 'admin')
166 user_admin_right = Right.create(:name => 'user_admin',
173 user_admin_right = Right.create(:name => 'user_admin',
167 :controller => 'user_admin',
174 :controller => 'user_admin',
168 :action => 'all')
175 :action => 'all')
169 problem_admin_right = Right.create(:name=> 'problem_admin',
176 problem_admin_right = Right.create(:name=> 'problem_admin',
170 :controller => 'problems',
177 :controller => 'problems',
171 :action => 'all')
178 :action => 'all')
172
179
173 graders_right = Right.create(:name => 'graders_admin',
180 graders_right = Right.create(:name => 'graders_admin',
174 :controller => 'graders',
181 :controller => 'graders',
175 :action => 'all')
182 :action => 'all')
176
183
177 role.rights << user_admin_right;
184 role.rights << user_admin_right;
178 role.rights << problem_admin_right;
185 role.rights << problem_admin_right;
179 role.rights << graders_right;
186 role.rights << graders_right;
180 role.save
187 role.save
181 end
188 end
182
189
183 def seed_root
190 def seed_root
184 return if User.find_by_login('root')
191 return if User.find_by_login('root')
185
192
186 root = User.new(:login => 'root',
193 root = User.new(:login => 'root',
187 :full_name => 'Administrator',
194 :full_name => 'Administrator',
188 :alias => 'root')
195 :alias => 'root')
189 root.password = 'ioionrails';
196 root.password = 'ioionrails';
190
197
191 class << root
198 class << root
192 public :encrypt_new_password
199 public :encrypt_new_password
193 def valid?(context=nil)
200 def valid?(context=nil)
194 true
201 true
195 end
202 end
196 end
203 end
197
204
198 root.encrypt_new_password
205 root.encrypt_new_password
199
206
200 root.roles << Role.find_by_name('admin')
207 root.roles << Role.find_by_name('admin')
201
208
202 root.activated = true
209 root.activated = true
203 root.save
210 root.save
204 end
211 end
205
212
206 def seed_users_and_roles
213 def seed_users_and_roles
207 seed_roles
214 seed_roles
208 seed_root
215 seed_root
209 end
216 end
210
217
211 def seed_more_languages
218 def seed_more_languages
212 Language.delete_all
219 Language.delete_all
213 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
220 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
214 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
221 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
215 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
222 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
216 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
223 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
217 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
224 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
218 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
225 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
219 end
226 end
220
227
221 seed_config
228 seed_config
222 seed_users_and_roles
229 seed_users_and_roles
223 seed_more_languages
230 seed_more_languages
You need to be logged in to leave comments. Login now