Description:
- fix authorization for viewing submission, only admin can view all problems all the time, normal user depends on right.view_submission and problem.available? - add max score query
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r593:a1d7330b2f43 - - 6 files changed: 106 inserted, 7 deleted

@@ -0,0 +1,43
1 + %h1 Maximum score
2 +
3 + = form_tag report_max_score_path
4 + .row
5 + .col-md-4
6 + .panel.panel-primary
7 + .panel-heading
8 + Problems
9 + .panel-body
10 + = label_tag :problems, "Problems"
11 + = select 'problems', 'problem_id', [[(t 'main.specified_in_header'),'-1']] + Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]}, {:selected => '-1'}, { class: 'select2 form-control' }
12 + .col-md-4
13 + .panel.panel-primary
14 + .panel-heading
15 + Submission range
16 + .panel-body
17 + .form-group
18 + = label_tag :from, "From"
19 + = text_field_tag 'from_id', nil, class: "form-control"
20 + .form-group
21 + = label_tag :from, "To"
22 + = text_field_tag 'to_id', nil, class: "form-control"
23 + .col-md-4
24 + .panel.panel-primary
25 + .panel-heading
26 + Users
27 + .panel-body
28 + .radio
29 + %label
30 + = radio_button_tag 'users', 'all', true
31 + All users
32 + .radio
33 + %label
34 + = radio_button_tag 'users', 'enabled'
35 + Only enabled users
36 + .row
37 + .col-md-12
38 + = button_tag 'Show', class: "btn btn-primary btn-large"
39 + = button_tag 'Download CSV', class: "btn btn-primary btn-large"
40 + /.col-md-4.col-md-offset-1
41 + / = button_tag 'Show', class: "btn btn-primary btn-block"
42 + /.col-md-4.col-md-offset-2
43 + / = button_tag 'Download CSV', class: "btn btn-primary btn-block"
@@ -1,29 +1,33
1 1 # See http://help.github.com/ignore-files/ for more about ignoring files.
2 2 #
3 3 # If you find yourself ignoring temporary files generated by your text editor
4 4 # or operating system, you probably want to add a global ignore instead:
5 5 # git config --global core.excludesfile ~/.gitignore_global
6 6
7 7 # Ignore bundler config
8 8 /.bundle
9 9
10 10 # Ignore the default SQLite database.
11 11 /db/*.sqlite3
12 12
13 13 # Ignore all logfiles and tempfiles.
14 14 /log/*.log
15 15 /tmp
16 16
17 17 *~
18 18
19 19 /vendor/plugins/rails_upgrade
20 20
21 21 #ignore public assets???
22 22 /public/assets
23 23 /public
24 24
25 25 /data
26 26
27 27 #ignore .orig and .swp
28 28 *.orig
29 29 *.swp
30 +
31 + #ignore rvm setting file
32 + .ruby-gemset
33 + .ruby-version
@@ -1,124 +1,128
1 1 class ApplicationController < ActionController::Base
2 2 protect_from_forgery
3 3
4 4 before_filter :current_user
5 5
6 6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8 8
9 + #report and redirect for unauthorized activities
10 + def unauthorized_redirect
11 + flash[:notice] = 'You are not authorized to view the page you requested'
12 + redirect_to :controller => 'main', :action => 'login'
13 + end
14 +
9 15 # Returns the current logged-in user (if any).
10 16 def current_user
11 17 return nil unless session[:user_id]
12 18 @current_user ||= User.find(session[:user_id])
13 19 end
14 20
15 21 def admin_authorization
16 22 return false unless authenticate
17 23 user = User.find(session[:user_id], :include => ['roles'])
18 24 unless user.admin?
19 - flash[:notice] = 'You are not authorized to view the page you requested'
20 - redirect_to :controller => 'main', :action => 'login' unless user.admin?
25 + unauthorized_redirect
21 26 return false
22 27 end
23 28 return true
24 29 end
25 30
26 31 def authorization_by_roles(allowed_roles)
27 32 return false unless authenticate
28 33 user = User.find(session[:user_id])
29 34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
30 - flash[:notice] = 'You are not authorized to view the page you requested'
31 - redirect_to :controller => 'main', :action => 'login'
35 + unauthorized_redirect
32 36 return false
33 37 end
34 38 end
35 39
36 40 protected
37 41
38 42 def authenticate
39 43 unless session[:user_id]
40 44 flash[:notice] = 'You need to login'
41 45 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
42 46 flash[:notice] = 'You need to login but you cannot log in at this time'
43 47 end
44 48 redirect_to :controller => 'main', :action => 'login'
45 49 return false
46 50 end
47 51
48 52 # check if run in single user mode
49 53 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
50 54 user = User.find_by_id(session[:user_id])
51 55 if user==nil or (not user.admin?)
52 56 flash[:notice] = 'You cannot log in at this time'
53 57 redirect_to :controller => 'main', :action => 'login'
54 58 return false
55 59 end
56 60 unless user.enabled?
57 61 flash[:notice] = 'Your account is disabled'
58 62 redirect_to :controller => 'main', :action => 'login'
59 63 return false
60 64 end
61 65 return true
62 66 end
63 67
64 68 if GraderConfiguration.multicontests?
65 69 user = User.find(session[:user_id])
66 70 return true if user.admin?
67 71 begin
68 72 if user.contest_stat(true).forced_logout
69 73 flash[:notice] = 'You have been automatically logged out.'
70 74 redirect_to :controller => 'main', :action => 'index'
71 75 end
72 76 rescue
73 77 end
74 78 end
75 79 return true
76 80 end
77 81
78 82 def authenticate_by_ip_address
79 83 #this assume that we have already authenticate normally
80 84 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
81 85 user = User.find(session[:user_id])
82 86 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
83 87 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
84 88 redirect_to :controller => 'main', :action => 'login'
85 89 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
86 90 return false
87 91 end
88 92 unless user.last_ip
89 93 user.last_ip = request.remote_ip
90 94 user.save
91 95 end
92 96 end
93 97 return true
94 98 end
95 99
96 100 def authorization
97 101 return false unless authenticate
98 102 user = User.find(session[:user_id])
99 103 unless user.roles.detect { |role|
100 104 role.rights.detect{ |right|
101 105 right.controller == self.class.controller_name and
102 106 (right.action == 'all' or right.action == action_name)
103 107 }
104 108 }
105 109 flash[:notice] = 'You are not authorized to view the page you requested'
106 110 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
107 111 redirect_to :controller => 'main', :action => 'login'
108 112 return false
109 113 end
110 114 end
111 115
112 116 def verify_time_limit
113 117 return true if session[:user_id]==nil
114 118 user = User.find(session[:user_id], :include => :site)
115 119 return true if user==nil or user.site == nil
116 120 if user.contest_finished?
117 121 flash[:notice] = 'Error: the contest you are participating is over.'
118 122 redirect_to :back
119 123 return false
120 124 end
121 125 return true
122 126 end
123 127
124 128 end
@@ -1,123 +1,130
1 1 class GradersController < ApplicationController
2 2
3 3 before_filter :admin_authorization, except: [ :submission ]
4 4 before_filter(only: [:submission]) {
5 + #check if authenticated
5 6 return false unless authenticate
6 7
7 - if GraderConfiguration["right.user_view_submission"]
8 - return true;
8 + #admin always has privileged
9 + if @current_user.admin?
10 + return true
9 11 end
10 12
11 - admin_authorization
13 + if GraderConfiguration["right.user_view_submission"] and Submission.find(params[:id]).problem.available?
14 + return true
15 + else
16 + unauthorized_redirect
17 + return false
18 + end
12 19 }
13 20
14 21 verify :method => :post, :only => ['clear_all',
15 22 'start_exam',
16 23 'start_grading',
17 24 'stop_all',
18 25 'clear_terminated'],
19 26 :redirect_to => {:action => 'index'}
20 27
21 28 def index
22 29 redirect_to :action => 'list'
23 30 end
24 31
25 32 def list
26 33 @grader_processes = GraderProcess.find_running_graders
27 34 @stalled_processes = GraderProcess.find_stalled_process
28 35
29 36 @terminated_processes = GraderProcess.find_terminated_graders
30 37
31 38 @last_task = Task.find(:first,
32 39 :order => 'created_at DESC')
33 40 @last_test_request = TestRequest.find(:first,
34 41 :order => 'created_at DESC')
35 42 @submission = Submission.order("id desc").limit(20)
36 43 @backlog_submission = Submission.where('graded_at is null')
37 44 end
38 45
39 46 def clear
40 47 grader_proc = GraderProcess.find(params[:id])
41 48 grader_proc.destroy if grader_proc!=nil
42 49 redirect_to :action => 'list'
43 50 end
44 51
45 52 def clear_terminated
46 53 GraderProcess.find_terminated_graders.each do |p|
47 54 p.destroy
48 55 end
49 56 redirect_to :action => 'list'
50 57 end
51 58
52 59 def clear_all
53 60 GraderProcess.find(:all).each do |p|
54 61 p.destroy
55 62 end
56 63 redirect_to :action => 'list'
57 64 end
58 65
59 66 def view
60 67 if params[:type]=='Task'
61 68 redirect_to :action => 'task', :id => params[:id]
62 69 else
63 70 redirect_to :action => 'test_request', :id => params[:id]
64 71 end
65 72 end
66 73
67 74 def test_request
68 75 @test_request = TestRequest.find(params[:id])
69 76 end
70 77
71 78 def task
72 79 @task = Task.find(params[:id])
73 80 end
74 81
75 82 def submission
76 83 @submission = Submission.find(params[:id])
77 84 formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', line_numbers: true )
78 85 lexer = case @submission.language.name
79 86 when "c" then Rouge::Lexers::C.new
80 87 when "cpp" then Rouge::Lexers::Cpp.new
81 88 when "pas" then Rouge::Lexers::Pas.new
82 89 when "ruby" then Rouge::Lexers::Ruby.new
83 90 when "python" then Rouge::Lexers::Python.new
84 91 when "java" then Rouge::Lexers::Java.new
85 92 when "php" then Rouge::Lexers::PHP.new
86 93 end
87 94 @formatted_code = formatter.format(lexer.lex(@submission.source))
88 95 @css_style = Rouge::Themes::ThankfulEyes.render(scope: '.highlight')
89 96
90 97 user = User.find(session[:user_id])
91 98 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
92 99
93 100 end
94 101
95 102 # various grader controls
96 103
97 104 def stop
98 105 grader_proc = GraderProcess.find(params[:id])
99 106 GraderScript.stop_grader(grader_proc.pid)
100 107 flash[:notice] = 'Grader stopped. It may not disappear now, but it should disappear shortly.'
101 108 redirect_to :action => 'list'
102 109 end
103 110
104 111 def stop_all
105 112 GraderScript.stop_graders(GraderProcess.find_running_graders +
106 113 GraderProcess.find_stalled_process)
107 114 flash[:notice] = 'Graders stopped. They may not disappear now, but they should disappear shortly.'
108 115 redirect_to :action => 'list'
109 116 end
110 117
111 118 def start_grading
112 119 GraderScript.start_grader('grading')
113 120 flash[:notice] = '2 graders in grading env started, one for grading queue tasks, another for grading test request'
114 121 redirect_to :action => 'list'
115 122 end
116 123
117 124 def start_exam
118 125 GraderScript.start_grader('exam')
119 126 flash[:notice] = '2 graders in grading env started, one for grading queue tasks, another for grading test request'
120 127 redirect_to :action => 'list'
121 128 end
122 129
123 130 end
@@ -1,398 +1,437
1 1 class ReportController < ApplicationController
2 2
3 3 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize]
4 4
5 5 before_filter(only: [:problem_hof]) { |c|
6 6 return false unless authenticate
7 7
8 8 if GraderConfiguration["right.user_view_submission"]
9 9 return true;
10 10 end
11 11
12 12 admin_authorization
13 13 }
14 14
15 + def show_max_score
16 + end
17 +
18 + def get_max_score
19 + #process list of problems
20 +
21 + #process submission range
22 + if params[:commit] == 'download csv'
23 + @problems = Problem.all
24 + else
25 + @problems = Problem.find_available_problems
26 + end
27 + @users = User.find(:all, :include => [:contests, :contest_stat])
28 + @scorearray = Array.new
29 + #set up range from param
30 + since_id = params.fetch(:since_id, 0).to_i
31 + until_id = params.fetch(:until_id, 0).to_i
32 + @users.each do |u|
33 + ustat = Array.new
34 + ustat[0] = u
35 + @problems.each do |p|
36 + max_points = 0
37 + Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
38 + max_points = sub.points if sub and sub.points and (sub.points > max_points)
39 + end
40 + ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
41 + end
42 + @scorearray << ustat
43 + end
44 +
45 + if params[:commit] == 'download csv' then
46 + csv = gen_csv_from_scorearray(@scorearray,@problems)
47 + send_data csv, filename: 'max_score.csv'
48 + else
49 + render template: 'user_admin/user_stat'
50 + end
51 +
52 + end
53 +
15 54 def score
16 55 if params[:commit] == 'download csv'
17 56 @problems = Problem.all
18 57 else
19 58 @problems = Problem.find_available_problems
20 59 end
21 60 @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
22 61 @scorearray = Array.new
23 62 @users.each do |u|
24 63 ustat = Array.new
25 64 ustat[0] = u
26 65 @problems.each do |p|
27 66 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
28 67 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
29 68 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
30 69 else
31 70 ustat << [0,false]
32 71 end
33 72 end
34 73 @scorearray << ustat
35 74 end
36 75 if params[:commit] == 'download csv' then
37 76 csv = gen_csv_from_scorearray(@scorearray,@problems)
38 77 send_data csv, filename: 'last_score.csv'
39 78 else
40 79 render template: 'user_admin/user_stat'
41 80 end
42 81
43 82 end
44 83
45 84 def login_stat
46 85 @logins = Array.new
47 86
48 87 date_and_time = '%Y-%m-%d %H:%M'
49 88 begin
50 89 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
51 90 @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)
52 91 rescue
53 92 @since_time = DateTime.new(1000,1,1)
54 93 end
55 94 begin
56 95 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
57 96 @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)
58 97 rescue
59 98 @until_time = DateTime.new(3000,1,1)
60 99 end
61 100
62 101 User.all.each do |user|
63 102 @logins << { id: user.id,
64 103 login: user.login,
65 104 full_name: user.full_name,
66 105 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
67 106 user.id,@since_time,@until_time)
68 107 .count(:id),
69 108 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
70 109 user.id,@since_time,@until_time)
71 110 .minimum(:created_at),
72 111 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
73 112 user.id,@since_time,@until_time)
74 113 .maximum(:created_at),
75 114 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
76 115 user.id,@since_time,@until_time)
77 116 .select(:ip_address).uniq
78 117
79 118 }
80 119 end
81 120 end
82 121
83 122 def submission_stat
84 123
85 124 date_and_time = '%Y-%m-%d %H:%M'
86 125 begin
87 126 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
88 127 rescue
89 128 @since_time = DateTime.new(1000,1,1)
90 129 end
91 130 begin
92 131 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
93 132 rescue
94 133 @until_time = DateTime.new(3000,1,1)
95 134 end
96 135
97 136 @submissions = {}
98 137
99 138 User.find_each do |user|
100 139 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
101 140 end
102 141
103 142 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
104 143 if @submissions[s.user_id]
105 144 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
106 145 a = Problem.find_by_id(s.problem_id)
107 146 @submissions[s.user_id][:sub][s.problem_id] =
108 147 { prob_name: (a ? a.full_name : '(NULL)'),
109 148 sub_ids: [s.id] }
110 149 else
111 150 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
112 151 end
113 152 @submissions[s.user_id][:count] += 1
114 153 end
115 154 end
116 155 end
117 156
118 157 def problem_hof
119 158 # gen problem list
120 159 @user = User.find(session[:user_id])
121 160 @problems = @user.available_problems
122 161
123 162 # get selected problems or the default
124 163 if params[:id]
125 164 begin
126 165 @problem = Problem.available.find(params[:id])
127 166 rescue
128 167 redirect_to action: :problem_hof
129 168 flash[:notice] = 'Error: submissions for that problem are not viewable.'
130 169 return
131 170 end
132 171 end
133 172
134 173 return unless @problem
135 174
136 175 @by_lang = {} #aggregrate by language
137 176
138 177 range =65
139 178 @histogram = { data: Array.new(range,0), summary: {} }
140 179 @summary = {count: 0, solve: 0, attempt: 0}
141 180 user = Hash.new(0)
142 181 Submission.where(problem_id: @problem.id).find_each do |sub|
143 182 #histogram
144 183 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
145 184 @histogram[:data][d.to_i] += 1 if d < range
146 185
147 186 next unless sub.points
148 187 @summary[:count] += 1
149 188 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
150 189
151 190 lang = Language.find_by_id(sub.language_id)
152 191 next unless lang
153 192 next unless sub.points >= @problem.full_score
154 193
155 194 #initialize
156 195 unless @by_lang.has_key?(lang.pretty_name)
157 196 @by_lang[lang.pretty_name] = {
158 197 runtime: { avail: false, value: 2**30-1 },
159 198 memory: { avail: false, value: 2**30-1 },
160 199 length: { avail: false, value: 2**30-1 },
161 200 first: { avail: false, value: DateTime.new(3000,1,1) }
162 201 }
163 202 end
164 203
165 204 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
166 205 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
167 206 end
168 207
169 208 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
170 209 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
171 210 end
172 211
173 212 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
174 213 !sub.user.admin?
175 214 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
176 215 end
177 216
178 217 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
179 218 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
180 219 end
181 220 end
182 221
183 222 #process user_id
184 223 @by_lang.each do |lang,prop|
185 224 prop.each do |k,v|
186 225 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
187 226 end
188 227 end
189 228
190 229 #sum into best
191 230 if @by_lang and @by_lang.first
192 231 @best = @by_lang.first[1].clone
193 232 @by_lang.each do |lang,prop|
194 233 if @best[:runtime][:value] >= prop[:runtime][:value]
195 234 @best[:runtime] = prop[:runtime]
196 235 @best[:runtime][:lang] = lang
197 236 end
198 237 if @best[:memory][:value] >= prop[:memory][:value]
199 238 @best[:memory] = prop[:memory]
200 239 @best[:memory][:lang] = lang
201 240 end
202 241 if @best[:length][:value] >= prop[:length][:value]
203 242 @best[:length] = prop[:length]
204 243 @best[:length][:lang] = lang
205 244 end
206 245 if @best[:first][:value] >= prop[:first][:value]
207 246 @best[:first] = prop[:first]
208 247 @best[:first][:lang] = lang
209 248 end
210 249 end
211 250 end
212 251
213 252 @histogram[:summary][:max] = [@histogram[:data].max,1].max
214 253 @summary[:attempt] = user.count
215 254 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
216 255 end
217 256
218 257 def stuck #report struggling user,problem
219 258 # init
220 259 user,problem = nil
221 260 solve = true
222 261 tries = 0
223 262 @struggle = Array.new
224 263 record = {}
225 264 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
226 265 next unless sub.problem and sub.user
227 266 if user != sub.user_id or problem != sub.problem_id
228 267 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
229 268 record = {user: sub.user, problem: sub.problem}
230 269 user,problem = sub.user_id, sub.problem_id
231 270 solve = false
232 271 tries = 0
233 272 end
234 273 if sub.points >= sub.problem.full_score
235 274 solve = true
236 275 else
237 276 tries += 1
238 277 end
239 278 end
240 279 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
241 280 @struggle = @struggle[0..50]
242 281 end
243 282
244 283
245 284 def multiple_login
246 285 #user with multiple IP
247 286 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
248 287 last,count = 0,0
249 288 first = 0
250 289 @users = []
251 290 raw.each do |r|
252 291 if last != r.user.login
253 292 count = 1
254 293 last = r.user.login
255 294 first = r
256 295 else
257 296 @users << first if count == 1
258 297 @users << r
259 298 count += 1
260 299 end
261 300 end
262 301
263 302 #IP with multiple user
264 303 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
265 304 last,count = 0,0
266 305 first = 0
267 306 @ip = []
268 307 raw.each do |r|
269 308 if last != r.ip_address
270 309 count = 1
271 310 last = r.ip_address
272 311 first = r
273 312 else
274 313 @ip << first if count == 1
275 314 @ip << r
276 315 count += 1
277 316 end
278 317 end
279 318 end
280 319
281 320 def cheat_report
282 321 date_and_time = '%Y-%m-%d %H:%M'
283 322 begin
284 323 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
285 324 @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)
286 325 rescue
287 326 @since_time = Time.zone.now.ago( 90.minutes)
288 327 end
289 328 begin
290 329 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
291 330 @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)
292 331 rescue
293 332 @until_time = Time.zone.now
294 333 end
295 334
296 335 #multi login
297 336 @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")
298 337
299 338 st = <<-SQL
300 339 SELECT l2.*
301 340 FROM logins l2 INNER JOIN
302 341 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
303 342 FROM logins l
304 343 INNER JOIN users u ON l.user_id = u.id
305 344 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
306 345 GROUP BY u.id
307 346 HAVING count > 1
308 347 ) ml ON l2.user_id = ml.id
309 348 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
310 349 UNION
311 350 SELECT l2.*
312 351 FROM logins l2 INNER JOIN
313 352 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
314 353 FROM logins l
315 354 INNER JOIN users u ON l.user_id = u.id
316 355 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
317 356 GROUP BY l.ip_address
318 357 HAVING count > 1
319 358 ) ml on ml.ip_address = l2.ip_address
320 359 INNER JOIN users u ON l2.user_id = u.id
321 360 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
322 361 ORDER BY ip_address,created_at
323 362 SQL
324 363 @mld = Login.find_by_sql(st)
325 364
326 365 st = <<-SQL
327 366 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
328 367 FROM submissions s INNER JOIN
329 368 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
330 369 FROM logins l
331 370 INNER JOIN users u ON l.user_id = u.id
332 371 WHERE l.created_at >= ? and l.created_at <= ?
333 372 GROUP BY u.id
334 373 HAVING count > 1
335 374 ) ml ON s.user_id = ml.id
336 375 WHERE s.submitted_at >= ? and s.submitted_at <= ?
337 376 UNION
338 377 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
339 378 FROM submissions s INNER JOIN
340 379 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
341 380 FROM logins l
342 381 INNER JOIN users u ON l.user_id = u.id
343 382 WHERE l.created_at >= ? and l.created_at <= ?
344 383 GROUP BY l.ip_address
345 384 HAVING count > 1
346 385 ) ml on ml.ip_address = s.ip_address
347 386 WHERE s.submitted_at >= ? and s.submitted_at <= ?
348 387 ORDER BY ip_address,submitted_at
349 388 SQL
350 389 @subs = Submission.joins(:problem).find_by_sql([st,@since_time,@until_time,
351 390 @since_time,@until_time,
352 391 @since_time,@until_time,
353 392 @since_time,@until_time])
354 393
355 394 end
356 395
357 396 def cheat_scruntinize
358 397 #convert date & time
359 398 date_and_time = '%Y-%m-%d %H:%M'
360 399 begin
361 400 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
362 401 @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)
363 402 rescue
364 403 @since_time = Time.zone.now.ago( 90.minutes)
365 404 end
366 405 begin
367 406 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
368 407 @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)
369 408 rescue
370 409 @until_time = Time.zone.now
371 410 end
372 411
373 412 #convert sid
374 413 @sid = params[:SID].split(/[,\s]/) if params[:SID]
375 414 unless @sid and @sid.size > 0
376 415 return
377 416 redirect_to actoin: :cheat_scruntinize
378 417 flash[:notice] = 'Please enter at least 1 student id'
379 418 end
380 419 mark = Array.new(@sid.size,'?')
381 420 condition = "(u.login = " + mark.join(' OR u.login = ') + ')'
382 421
383 422 @st = <<-SQL
384 423 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
385 424 FROM logins l INNER JOIN users u on l.user_id = u.id
386 425 WHERE l.created_at >= ? AND l.created_at <= ? AND #{condition}
387 426 UNION
388 427 SELECT s.submitted_at,s.id,u.login,u.full_name,s.ip_address,s.problem_id,s.points,s.user_id
389 428 FROM submissions s INNER JOIN users u ON s.user_id = u.id
390 429 WHERE s.submitted_at >= ? AND s.submitted_at <= ? AND #{condition}
391 430 ORDER BY submitted_at
392 431 SQL
393 432
394 433 p = [@st,@since_time,@until_time] + @sid + [@since_time,@until_time] + @sid
395 434 @logs = Submission.joins(:problem).find_by_sql(p)
396 435
397 436
398 437
@@ -1,65 +1,67
1 1 CafeGrader::Application.routes.draw do
2 2 get "sources/direct_edit"
3 3
4 4 root :to => 'main#login'
5 5
6 6 resources :contests
7 7
8 8 resources :sites
9 9
10 10 resources :announcements do
11 11 member do
12 12 get 'toggle','toggle_front'
13 13 end
14 14 end
15 15
16 16 resources :problems do
17 17 member do
18 18 get 'toggle'
19 19 get 'toggle_test'
20 20 end
21 21 collection do
22 22 get 'turn_all_off'
23 23 get 'turn_all_on'
24 24 get 'import'
25 25 get 'manage'
26 26 end
27 27 end
28 28
29 29 resources :grader_configuration, controller: 'configurations'
30 30
31 31 resources :users do
32 32 member do
33 33 get 'toggle_activate', 'toggle_enable'
34 34 end
35 35 end
36 36
37 37 #source code edit
38 38 get 'sources/direct_edit/:pid', to: 'sources#direct_edit', as: 'direct_edit'
39 39 get 'sources/direct_edit_submission/:sid', to: 'sources#direct_edit_submission', as: 'direct_edit_submission'
40 40 get 'sources/get_latest_submission_status/:uid/:pid', to: 'sources#get_latest_submission_status', as: 'get_latest_submission_status'
41 41
42 42
43 43 match 'tasks/view/:file.:ext' => 'tasks#view'
44 44 match 'tasks/download/:id/:file.:ext' => 'tasks#download'
45 45 match 'heartbeat/:id/edit' => 'heartbeat#edit'
46 46
47 47 #main
48 48 get "main/list"
49 49 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
50 50
51 51 #report
52 52 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
53 53 get "report/login"
54 + get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
54 55
55 56 #grader
56 57 get 'graders/list', to: 'graders#list', as: 'grader_list'
57 58
59 +
58 60 match 'heartbeat/:id/edit' => 'heartbeat#edit'
59 61
60 62 # See how all your routes lay out with "rake routes"
61 63
62 64 # This is a legacy wild controller route that's not recommended for RESTful applications.
63 65 # Note: This route will make all actions in every controller accessible via GET requests.
64 66 match ':controller(/:action(/:id))(.:format)'
65 67 end
You need to be logged in to leave comments. Login now