Description:
add current score by group
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r762:c6677423b846 - - 10 files changed: 105 inserted, 24 deleted

@@ -0,0 +1,45
1 + .container-fluid
2 + .row
3 + .col-md-6
4 + %h1 Adding list of users
5 + .row
6 + .col-md-6
7 + .panel.panel-default
8 + .panel-heading
9 + .panel-title Info
10 + .panel-body
11 + %ul
12 + %li
13 + List of user information in this format:
14 + %tt user_id,name(,passwd(,alias(,remark)))
15 + %li
16 + Note that
17 + %tt passwd, alias
18 + and
19 + %tt remark
20 + is optional.
21 + %li
22 + When
23 + %tt passwd
24 + or
25 + %tt alias
26 + is empty, the original value will be used instead.
27 + %li
28 + If the users with the same user_id already exists, existing information will be overwritten.
29 +
30 + .row
31 + .col-md-6
32 + = form_tag :action => 'create_from_list' do
33 + .form-group
34 + = submit_tag 'Create following users',class: 'btn btn-success'
35 + .form-group
36 + .div.checkbox
37 + %label
38 + = check_box_tag :add_to_group
39 + Also add these users to the following group
40 + = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
41 + .form-group
42 + = text_area_tag 'user_list', nil, :rows => 50, :cols => 80
43 + .col-md-6
44 +
45 +
@@ -1,404 +1,409
1 require 'csv'
1 require 'csv'
2
2
3 class ReportController < ApplicationController
3 class ReportController < ApplicationController
4
4
5 before_action :check_valid_login
5 before_action :check_valid_login
6
6
7 before_action :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
7 before_action :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
8
8
9 before_action(only: [:problem_hof]) { |c|
9 before_action(only: [:problem_hof]) { |c|
10 return false unless check_valid_login
10 return false unless check_valid_login
11
11
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
12 admin_authorization unless GraderConfiguration["right.user_view_submission"]
13 }
13 }
14
14
15 def max_score
15 def max_score
16 end
16 end
17
17
18 def current_score
18 def current_score
19 @problems = Problem.available_problems
19 @problems = Problem.available_problems
20 + if params[:group_id]
21 + @group = Group.find(params[:group_id])
22 + @users = @group.users.where(enabled: true)
23 + else
20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
24 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
25 + end
21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
26 @scorearray = calculate_max_score(@problems, @users,0,0,true)
22
27
23 #rencer accordingly
28 #rencer accordingly
24 if params[:button] == 'download' then
29 if params[:button] == 'download' then
25 csv = gen_csv_from_scorearray(@scorearray,@problems)
30 csv = gen_csv_from_scorearray(@scorearray,@problems)
26 send_data csv, filename: 'max_score.csv'
31 send_data csv, filename: 'max_score.csv'
27 else
32 else
28 #render template: 'user_admin/user_stat'
33 #render template: 'user_admin/user_stat'
29 render 'current_score'
34 render 'current_score'
30 end
35 end
31 end
36 end
32
37
33 def show_max_score
38 def show_max_score
34 #process parameters
39 #process parameters
35 #problems
40 #problems
36 @problems = []
41 @problems = []
37 if params[:problem_id]
42 if params[:problem_id]
38 params[:problem_id].each do |id|
43 params[:problem_id].each do |id|
39 next unless id.strip != ""
44 next unless id.strip != ""
40 pid = Problem.find_by_id(id.to_i)
45 pid = Problem.find_by_id(id.to_i)
41 @problems << pid if pid
46 @problems << pid if pid
42 end
47 end
43 end
48 end
44
49
45 #users
50 #users
46 @users = if params[:users] == "all" then
51 @users = if params[:users] == "all" then
47 User.includes(:contests).includes(:contest_stat)
52 User.includes(:contests).includes(:contest_stat)
48 else
53 else
49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
54 User.includes(:contests).includes(:contest_stat).where(enabled: true)
50 end
55 end
51
56
52 #set up range from param
57 #set up range from param
53 @since_id = params.fetch(:from_id, 0).to_i
58 @since_id = params.fetch(:from_id, 0).to_i
54 @until_id = params.fetch(:to_id, 0).to_i
59 @until_id = params.fetch(:to_id, 0).to_i
55 @since_id = nil if @since_id == 0
60 @since_id = nil if @since_id == 0
56 @until_id = nil if @until_id == 0
61 @until_id = nil if @until_id == 0
57
62
58 #calculate the routine
63 #calculate the routine
59 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
64 @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
60
65
61 #rencer accordingly
66 #rencer accordingly
62 if params[:button] == 'download' then
67 if params[:button] == 'download' then
63 csv = gen_csv_from_scorearray(@scorearray,@problems)
68 csv = gen_csv_from_scorearray(@scorearray,@problems)
64 send_data csv, filename: 'max_score.csv'
69 send_data csv, filename: 'max_score.csv'
65 else
70 else
66 #render template: 'user_admin/user_stat'
71 #render template: 'user_admin/user_stat'
67 render 'max_score'
72 render 'max_score'
68 end
73 end
69
74
70 end
75 end
71
76
72 def score
77 def score
73 if params[:commit] == 'download csv'
78 if params[:commit] == 'download csv'
74 @problems = Problem.all
79 @problems = Problem.all
75 else
80 else
76 @problems = Problem.available_problems
81 @problems = Problem.available_problems
77 end
82 end
78 @users = User.includes(:contests, :contest_stat).where(enabled: true)
83 @users = User.includes(:contests, :contest_stat).where(enabled: true)
79 @scorearray = Array.new
84 @scorearray = Array.new
80 @users.each do |u|
85 @users.each do |u|
81 ustat = Array.new
86 ustat = Array.new
82 ustat[0] = u
87 ustat[0] = u
83 @problems.each do |p|
88 @problems.each do |p|
84 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
89 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
85 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
90 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
86 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
91 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
87 else
92 else
88 ustat << [0,false]
93 ustat << [0,false]
89 end
94 end
90 end
95 end
91 @scorearray << ustat
96 @scorearray << ustat
92 end
97 end
93 if params[:commit] == 'download csv' then
98 if params[:commit] == 'download csv' then
94 csv = gen_csv_from_scorearray(@scorearray,@problems)
99 csv = gen_csv_from_scorearray(@scorearray,@problems)
95 send_data csv, filename: 'last_score.csv'
100 send_data csv, filename: 'last_score.csv'
96 else
101 else
97 render template: 'user_admin/user_stat'
102 render template: 'user_admin/user_stat'
98 end
103 end
99
104
100 end
105 end
101
106
102 def login_stat
107 def login_stat
103 @logins = Array.new
108 @logins = Array.new
104
109
105 date_and_time = '%Y-%m-%d %H:%M'
110 date_and_time = '%Y-%m-%d %H:%M'
106 begin
111 begin
107 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
112 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
108 @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)
113 @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)
109 rescue
114 rescue
110 @since_time = DateTime.new(1000,1,1)
115 @since_time = DateTime.new(1000,1,1)
111 end
116 end
112 begin
117 begin
113 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
118 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
114 @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)
119 @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)
115 rescue
120 rescue
116 @until_time = DateTime.new(3000,1,1)
121 @until_time = DateTime.new(3000,1,1)
117 end
122 end
118
123
119 User.all.each do |user|
124 User.all.each do |user|
120 @logins << { id: user.id,
125 @logins << { id: user.id,
121 login: user.login,
126 login: user.login,
122 full_name: user.full_name,
127 full_name: user.full_name,
123 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
128 count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
124 user.id,@since_time,@until_time)
129 user.id,@since_time,@until_time)
125 .count(:id),
130 .count(:id),
126 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
131 min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
127 user.id,@since_time,@until_time)
132 user.id,@since_time,@until_time)
128 .minimum(:created_at),
133 .minimum(:created_at),
129 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
134 max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
130 user.id,@since_time,@until_time)
135 user.id,@since_time,@until_time)
131 .maximum(:created_at),
136 .maximum(:created_at),
132 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
137 ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
133 user.id,@since_time,@until_time)
138 user.id,@since_time,@until_time)
134 .select(:ip_address).uniq
139 .select(:ip_address).uniq
135
140
136 }
141 }
137 end
142 end
138 end
143 end
139
144
140 def submission_stat
145 def submission_stat
141
146
142 date_and_time = '%Y-%m-%d %H:%M'
147 date_and_time = '%Y-%m-%d %H:%M'
143 begin
148 begin
144 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
149 @since_time = DateTime.strptime(params[:since_datetime],date_and_time)
145 rescue
150 rescue
146 @since_time = DateTime.new(1000,1,1)
151 @since_time = DateTime.new(1000,1,1)
147 end
152 end
148 begin
153 begin
149 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
154 @until_time = DateTime.strptime(params[:until_datetime],date_and_time)
150 rescue
155 rescue
151 @until_time = DateTime.new(3000,1,1)
156 @until_time = DateTime.new(3000,1,1)
152 end
157 end
153
158
154 @submissions = {}
159 @submissions = {}
155
160
156 User.find_each do |user|
161 User.find_each do |user|
157 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
162 @submissions[user.id] = { login: user.login, full_name: user.full_name, count: 0, sub: { } }
158 end
163 end
159
164
160 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
165 Submission.where("submitted_at >= ? AND submitted_at <= ?",@since_time,@until_time).find_each do |s|
161 if @submissions[s.user_id]
166 if @submissions[s.user_id]
162 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
167 if not @submissions[s.user_id][:sub].has_key?(s.problem_id)
163 a = Problem.find_by_id(s.problem_id)
168 a = Problem.find_by_id(s.problem_id)
164 @submissions[s.user_id][:sub][s.problem_id] =
169 @submissions[s.user_id][:sub][s.problem_id] =
165 { prob_name: (a ? a.full_name : '(NULL)'),
170 { prob_name: (a ? a.full_name : '(NULL)'),
166 sub_ids: [s.id] }
171 sub_ids: [s.id] }
167 else
172 else
168 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
173 @submissions[s.user_id][:sub][s.problem_id][:sub_ids] << s.id
169 end
174 end
170 @submissions[s.user_id][:count] += 1
175 @submissions[s.user_id][:count] += 1
171 end
176 end
172 end
177 end
173 end
178 end
174
179
175 def problem_hof
180 def problem_hof
176 # gen problem list
181 # gen problem list
177 @user = User.find(session[:user_id])
182 @user = User.find(session[:user_id])
178 @problems = @user.available_problems
183 @problems = @user.available_problems
179
184
180 # get selected problems or the default
185 # get selected problems or the default
181 if params[:id]
186 if params[:id]
182 begin
187 begin
183 @problem = Problem.available.find(params[:id])
188 @problem = Problem.available.find(params[:id])
184 rescue
189 rescue
185 redirect_to action: :problem_hof
190 redirect_to action: :problem_hof
186 flash[:notice] = 'Error: submissions for that problem are not viewable.'
191 flash[:notice] = 'Error: submissions for that problem are not viewable.'
187 return
192 return
188 end
193 end
189 end
194 end
190
195
191 return unless @problem
196 return unless @problem
192
197
193 @by_lang = {} #aggregrate by language
198 @by_lang = {} #aggregrate by language
194
199
195 range =65
200 range =65
196 @histogram = { data: Array.new(range,0), summary: {} }
201 @histogram = { data: Array.new(range,0), summary: {} }
197 @summary = {count: 0, solve: 0, attempt: 0}
202 @summary = {count: 0, solve: 0, attempt: 0}
198 user = Hash.new(0)
203 user = Hash.new(0)
199 Submission.where(problem_id: @problem.id).find_each do |sub|
204 Submission.where(problem_id: @problem.id).find_each do |sub|
200 #histogram
205 #histogram
201 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
206 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
202 @histogram[:data][d.to_i] += 1 if d < range
207 @histogram[:data][d.to_i] += 1 if d < range
203
208
204 next unless sub.points
209 next unless sub.points
205 @summary[:count] += 1
210 @summary[:count] += 1
206 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
211 user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
207
212
208 lang = Language.find_by_id(sub.language_id)
213 lang = Language.find_by_id(sub.language_id)
209 next unless lang
214 next unless lang
210 next unless sub.points >= @problem.full_score
215 next unless sub.points >= @problem.full_score
211
216
212 #initialize
217 #initialize
213 unless @by_lang.has_key?(lang.pretty_name)
218 unless @by_lang.has_key?(lang.pretty_name)
214 @by_lang[lang.pretty_name] = {
219 @by_lang[lang.pretty_name] = {
215 runtime: { avail: false, value: 2**30-1 },
220 runtime: { avail: false, value: 2**30-1 },
216 memory: { avail: false, value: 2**30-1 },
221 memory: { avail: false, value: 2**30-1 },
217 length: { avail: false, value: 2**30-1 },
222 length: { avail: false, value: 2**30-1 },
218 first: { avail: false, value: DateTime.new(3000,1,1) }
223 first: { avail: false, value: DateTime.new(3000,1,1) }
219 }
224 }
220 end
225 end
221
226
222 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
227 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
223 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
228 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
224 end
229 end
225
230
226 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
231 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
227 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
232 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
228 end
233 end
229
234
230 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
235 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and sub.user and
231 !sub.user.admin?
236 !sub.user.admin?
232 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
237 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
233 end
238 end
234
239
235 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
240 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
236 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
241 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
237 end
242 end
238 end
243 end
239
244
240 #process user_id
245 #process user_id
241 @by_lang.each do |lang,prop|
246 @by_lang.each do |lang,prop|
242 prop.each do |k,v|
247 prop.each do |k,v|
243 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
248 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
244 end
249 end
245 end
250 end
246
251
247 #sum into best
252 #sum into best
248 if @by_lang and @by_lang.first
253 if @by_lang and @by_lang.first
249 @best = @by_lang.first[1].clone
254 @best = @by_lang.first[1].clone
250 @by_lang.each do |lang,prop|
255 @by_lang.each do |lang,prop|
251 if @best[:runtime][:value] >= prop[:runtime][:value]
256 if @best[:runtime][:value] >= prop[:runtime][:value]
252 @best[:runtime] = prop[:runtime]
257 @best[:runtime] = prop[:runtime]
253 @best[:runtime][:lang] = lang
258 @best[:runtime][:lang] = lang
254 end
259 end
255 if @best[:memory][:value] >= prop[:memory][:value]
260 if @best[:memory][:value] >= prop[:memory][:value]
256 @best[:memory] = prop[:memory]
261 @best[:memory] = prop[:memory]
257 @best[:memory][:lang] = lang
262 @best[:memory][:lang] = lang
258 end
263 end
259 if @best[:length][:value] >= prop[:length][:value]
264 if @best[:length][:value] >= prop[:length][:value]
260 @best[:length] = prop[:length]
265 @best[:length] = prop[:length]
261 @best[:length][:lang] = lang
266 @best[:length][:lang] = lang
262 end
267 end
263 if @best[:first][:value] >= prop[:first][:value]
268 if @best[:first][:value] >= prop[:first][:value]
264 @best[:first] = prop[:first]
269 @best[:first] = prop[:first]
265 @best[:first][:lang] = lang
270 @best[:first][:lang] = lang
266 end
271 end
267 end
272 end
268 end
273 end
269
274
270 @histogram[:summary][:max] = [@histogram[:data].max,1].max
275 @histogram[:summary][:max] = [@histogram[:data].max,1].max
271 @summary[:attempt] = user.count
276 @summary[:attempt] = user.count
272 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
277 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
273 end
278 end
274
279
275 def stuck #report struggling user,problem
280 def stuck #report struggling user,problem
276 # init
281 # init
277 user,problem = nil
282 user,problem = nil
278 solve = true
283 solve = true
279 tries = 0
284 tries = 0
280 @struggle = Array.new
285 @struggle = Array.new
281 record = {}
286 record = {}
282 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
287 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
283 next unless sub.problem and sub.user
288 next unless sub.problem and sub.user
284 if user != sub.user_id or problem != sub.problem_id
289 if user != sub.user_id or problem != sub.problem_id
285 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
290 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
286 record = {user: sub.user, problem: sub.problem}
291 record = {user: sub.user, problem: sub.problem}
287 user,problem = sub.user_id, sub.problem_id
292 user,problem = sub.user_id, sub.problem_id
288 solve = false
293 solve = false
289 tries = 0
294 tries = 0
290 end
295 end
291 if sub.points >= sub.problem.full_score
296 if sub.points >= sub.problem.full_score
292 solve = true
297 solve = true
293 else
298 else
294 tries += 1
299 tries += 1
295 end
300 end
296 end
301 end
297 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
302 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
298 @struggle = @struggle[0..50]
303 @struggle = @struggle[0..50]
299 end
304 end
300
305
301
306
302 def multiple_login
307 def multiple_login
303 #user with multiple IP
308 #user with multiple IP
304 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
309 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
305 last,count = 0,0
310 last,count = 0,0
306 first = 0
311 first = 0
307 @users = []
312 @users = []
308 raw.each do |r|
313 raw.each do |r|
309 if last != r.user.login
314 if last != r.user.login
310 count = 1
315 count = 1
311 last = r.user.login
316 last = r.user.login
312 first = r
317 first = r
313 else
318 else
314 @users << first if count == 1
319 @users << first if count == 1
315 @users << r
320 @users << r
316 count += 1
321 count += 1
317 end
322 end
318 end
323 end
319
324
320 #IP with multiple user
325 #IP with multiple user
321 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
326 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
322 last,count = 0,0
327 last,count = 0,0
323 first = 0
328 first = 0
324 @ip = []
329 @ip = []
325 raw.each do |r|
330 raw.each do |r|
326 if last != r.ip_address
331 if last != r.ip_address
327 count = 1
332 count = 1
328 last = r.ip_address
333 last = r.ip_address
329 first = r
334 first = r
330 else
335 else
331 @ip << first if count == 1
336 @ip << first if count == 1
332 @ip << r
337 @ip << r
333 count += 1
338 count += 1
334 end
339 end
335 end
340 end
336 end
341 end
337
342
338 def cheat_report
343 def cheat_report
339 date_and_time = '%Y-%m-%d %H:%M'
344 date_and_time = '%Y-%m-%d %H:%M'
340 begin
345 begin
341 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
346 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
342 @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)
347 @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)
343 rescue
348 rescue
344 @since_time = Time.zone.now.ago( 90.minutes)
349 @since_time = Time.zone.now.ago( 90.minutes)
345 end
350 end
346 begin
351 begin
347 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
352 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
348 @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)
353 @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)
349 rescue
354 rescue
350 @until_time = Time.zone.now
355 @until_time = Time.zone.now
351 end
356 end
352
357
353 #multi login
358 #multi login
354 @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")
359 @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")
355
360
356 st = <<-SQL
361 st = <<-SQL
357 SELECT l2.*
362 SELECT l2.*
358 FROM logins l2 INNER JOIN
363 FROM logins l2 INNER JOIN
359 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
364 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
360 FROM logins l
365 FROM logins l
361 INNER JOIN users u ON l.user_id = u.id
366 INNER JOIN users u ON l.user_id = u.id
362 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
367 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
363 GROUP BY u.id
368 GROUP BY u.id
364 HAVING count > 1
369 HAVING count > 1
365 ) ml ON l2.user_id = ml.id
370 ) ml ON l2.user_id = ml.id
366 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
371 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
367 UNION
372 UNION
368 SELECT l2.*
373 SELECT l2.*
369 FROM logins l2 INNER JOIN
374 FROM logins l2 INNER JOIN
370 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
375 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
371 FROM logins l
376 FROM logins l
372 INNER JOIN users u ON l.user_id = u.id
377 INNER JOIN users u ON l.user_id = u.id
373 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
378 WHERE l.created_at >= '#{@since_time.in_time_zone("UTC")}' and l.created_at <= '#{@until_time.in_time_zone("UTC")}'
374 GROUP BY l.ip_address
379 GROUP BY l.ip_address
375 HAVING count > 1
380 HAVING count > 1
376 ) ml on ml.ip_address = l2.ip_address
381 ) ml on ml.ip_address = l2.ip_address
377 INNER JOIN users u ON l2.user_id = u.id
382 INNER JOIN users u ON l2.user_id = u.id
378 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
383 WHERE l2.created_at >= '#{@since_time.in_time_zone("UTC")}' and l2.created_at <= '#{@until_time.in_time_zone("UTC")}'
379 ORDER BY ip_address,created_at
384 ORDER BY ip_address,created_at
380 SQL
385 SQL
381 @mld = Login.find_by_sql(st)
386 @mld = Login.find_by_sql(st)
382
387
383 st = <<-SQL
388 st = <<-SQL
384 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
389 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
385 FROM submissions s INNER JOIN
390 FROM submissions s INNER JOIN
386 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
391 (SELECT u.id,COUNT(DISTINCT ip_address) as count,u.login,u.full_name
387 FROM logins l
392 FROM logins l
388 INNER JOIN users u ON l.user_id = u.id
393 INNER JOIN users u ON l.user_id = u.id
389 WHERE l.created_at >= ? and l.created_at <= ?
394 WHERE l.created_at >= ? and l.created_at <= ?
390 GROUP BY u.id
395 GROUP BY u.id
391 HAVING count > 1
396 HAVING count > 1
392 ) ml ON s.user_id = ml.id
397 ) ml ON s.user_id = ml.id
393 WHERE s.submitted_at >= ? and s.submitted_at <= ?
398 WHERE s.submitted_at >= ? and s.submitted_at <= ?
394 UNION
399 UNION
395 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
400 SELECT s.id,s.user_id,s.ip_address,s.submitted_at,s.problem_id
396 FROM submissions s INNER JOIN
401 FROM submissions s INNER JOIN
397 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
402 (SELECT l.ip_address,COUNT(DISTINCT u.id) as count
398 FROM logins l
403 FROM logins l
399 INNER JOIN users u ON l.user_id = u.id
404 INNER JOIN users u ON l.user_id = u.id
400 WHERE l.created_at >= ? and l.created_at <= ?
405 WHERE l.created_at >= ? and l.created_at <= ?
401 GROUP BY l.ip_address
406 GROUP BY l.ip_address
402 HAVING count > 1
407 HAVING count > 1
403 ) ml on ml.ip_address = s.ip_address
408 ) ml on ml.ip_address = s.ip_address
404 WHERE s.submitted_at >= ? and s.submitted_at <= ?
409 WHERE s.submitted_at >= ? and s.submitted_at <= ?
@@ -1,75 +1,74
1 class TasksController < ApplicationController
1 class TasksController < ApplicationController
2
2
3 before_action :check_valid_login, :check_viewability
3 before_action :check_valid_login, :check_viewability
4
4
5 def index
5 def index
6 redirect_to :action => 'list'
6 redirect_to :action => 'list'
7 end
7 end
8
8
9 def list
9 def list
10 @problems = @user.available_problems
10 @problems = @user.available_problems
11 end
11 end
12
12
13 # this has contest-wide access control
13 # this has contest-wide access control
14 def view
14 def view
15 base_name = params[:file]
15 base_name = params[:file]
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
16 base_filename = File.basename("#{base_name}.#{params[:ext]}")
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
17 filename = "#{Problem.download_file_basedir}/#{base_filename}"
18
18
19 if !FileTest.exists?(filename)
19 if !FileTest.exists?(filename)
20 redirect_to :action => 'index' and return
20 redirect_to :action => 'index' and return
21 end
21 end
22
22
23 send_file_to_user(filename, base_filename)
23 send_file_to_user(filename, base_filename)
24 end
24 end
25
25
26 # this has problem-level access control
26 # this has problem-level access control
27 def download
27 def download
28 problem = Problem.find(params[:id])
28 problem = Problem.find(params[:id])
29 unless @current_user.can_view_problem? problem
29 unless @current_user.can_view_problem? problem
30 + flash[:notice] = 'You are not authorized to access this file'
30 redirect_to :action => 'index' and return
31 redirect_to :action => 'index' and return
31 end
32 end
32
33
33 base_name = params[:file]
34 base_name = params[:file]
34 base_filename = File.basename("#{base_name}.#{params[:ext]}")
35 base_filename = File.basename("#{base_name}.#{params[:ext]}")
35 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
36 filename = "#{Problem.download_file_basedir}/#{params[:id]}/#{base_filename}"
36 - puts "SENDING: #{filename}"
37
37
38 if !FileTest.exists?(filename)
38 if !FileTest.exists?(filename)
39 + flash[:notice] = 'File does not exists'
39 redirect_to :action => 'index' and return
40 redirect_to :action => 'index' and return
40 end
41 end
41
42
42 - puts "SENDING: #{filename}"
43 -
44 send_file_to_user(filename, base_filename)
43 send_file_to_user(filename, base_filename)
45 end
44 end
46
45
47 protected
46 protected
48
47
49 def send_file_to_user(filename, base_filename)
48 def send_file_to_user(filename, base_filename)
50 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
49 if defined?(USE_APACHE_XSENDFILE) and USE_APACHE_XSENDFILE
51 response.headers['Content-Type'] = "application/force-download"
50 response.headers['Content-Type'] = "application/force-download"
52 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
51 response.headers['Content-Disposition'] = "attachment; filename=\"#{File.basename(filename)}\""
53 response.headers["X-Sendfile"] = filename
52 response.headers["X-Sendfile"] = filename
54 response.headers['Content-length'] = File.size(filename)
53 response.headers['Content-length'] = File.size(filename)
55 render :nothing => true
54 render :nothing => true
56 else
55 else
57 if params[:ext]=='pdf'
56 if params[:ext]=='pdf'
58 content_type = 'application/pdf'
57 content_type = 'application/pdf'
59 else
58 else
60 content_type = 'application/octet-stream'
59 content_type = 'application/octet-stream'
61 end
60 end
62
61
63 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
62 send_file filename, :stream => false, :disposition => 'inline', :filename => base_filename, :type => content_type
64 end
63 end
65 end
64 end
66
65
67 def check_viewability
66 def check_viewability
68 @user = User.find(session[:user_id])
67 @user = User.find(session[:user_id])
69 if @user==nil or !GraderConfiguration.show_tasks_to?(@user)
68 if @user==nil or !GraderConfiguration.show_tasks_to?(@user)
70 redirect_to :controller => 'main', :action => 'list'
69 redirect_to :controller => 'main', :action => 'list'
71 return false
70 return false
72 end
71 end
73 end
72 end
74
73
75 end
74 end
@@ -1,499 +1,519
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5 include MailHelperMethods
5 include MailHelperMethods
6
6
7 before_action :admin_authorization
7 before_action :admin_authorization
8
8
9 def index
9 def index
10 @user_count = User.count
10 @user_count = User.count
11 if params[:page] == 'all'
11 if params[:page] == 'all'
12 @users = User.all
12 @users = User.all
13 @paginated = false
13 @paginated = false
14 else
14 else
15 @users = User.paginate :page => params[:page]
15 @users = User.paginate :page => params[:page]
16 @paginated = true
16 @paginated = true
17 end
17 end
18 @users = User.all
18 @users = User.all
19 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
19 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
20 @contests = Contest.enabled
20 @contests = Contest.enabled
21 end
21 end
22
22
23 def active
23 def active
24 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
24 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
25 @users = []
25 @users = []
26 sessions.each do |session|
26 sessions.each do |session|
27 if session.data[:user_id]
27 if session.data[:user_id]
28 @users << User.find(session.data[:user_id])
28 @users << User.find(session.data[:user_id])
29 end
29 end
30 end
30 end
31 end
31 end
32
32
33 def show
33 def show
34 @user = User.find(params[:id])
34 @user = User.find(params[:id])
35 end
35 end
36
36
37 def new
37 def new
38 @user = User.new
38 @user = User.new
39 end
39 end
40
40
41 def create
41 def create
42 @user = User.new(user_params)
42 @user = User.new(user_params)
43 @user.activated = true
43 @user.activated = true
44 if @user.save
44 if @user.save
45 flash[:notice] = 'User was successfully created.'
45 flash[:notice] = 'User was successfully created.'
46 redirect_to :action => 'index'
46 redirect_to :action => 'index'
47 else
47 else
48 render :action => 'new'
48 render :action => 'new'
49 end
49 end
50 end
50 end
51
51
52 def clear_last_ip
52 def clear_last_ip
53 @user = User.find(params[:id])
53 @user = User.find(params[:id])
54 @user.last_ip = nil
54 @user.last_ip = nil
55 @user.save
55 @user.save
56 redirect_to action: 'index', page: params[:page]
56 redirect_to action: 'index', page: params[:page]
57 end
57 end
58
58
59 def create_from_list
59 def create_from_list
60 lines = params[:user_list]
60 lines = params[:user_list]
61
61
62 note = []
62 note = []
63 + error_note = []
64 + ok_user = []
63
65
64 lines.split("\n").each do |line|
66 lines.split("\n").each do |line|
65 items = line.chomp.split(',')
67 items = line.chomp.split(',')
66 if items.length>=2
68 if items.length>=2
67 login = items[0]
69 login = items[0]
68 full_name = items[1]
70 full_name = items[1]
69 remark =''
71 remark =''
70 user_alias = ''
72 user_alias = ''
71
73
72 added_random_password = false
74 added_random_password = false
73 if items.length >= 3 and items[2].chomp(" ").length > 0;
75 if items.length >= 3 and items[2].chomp(" ").length > 0;
74 password = items[2].chomp(" ")
76 password = items[2].chomp(" ")
75 else
77 else
76 password = random_password
78 password = random_password
77 add_random_password=true;
79 add_random_password=true;
78 end
80 end
79
81
80 if items.length>= 4 and items[3].chomp(" ").length > 0;
82 if items.length>= 4 and items[3].chomp(" ").length > 0;
81 user_alias = items[3].chomp(" ")
83 user_alias = items[3].chomp(" ")
82 else
84 else
83 user_alias = login
85 user_alias = login
84 end
86 end
85
87
86 if items.length>=5
88 if items.length>=5
87 remark = items[4].strip;
89 remark = items[4].strip;
88 end
90 end
89
91
90 user = User.find_by_login(login)
92 user = User.find_by_login(login)
91 if (user)
93 if (user)
92 user.full_name = full_name
94 user.full_name = full_name
93 user.password = password
95 user.password = password
94 user.remark = remark
96 user.remark = remark
95 else
97 else
96 user = User.new({:login => login,
98 user = User.new({:login => login,
97 :full_name => full_name,
99 :full_name => full_name,
98 :password => password,
100 :password => password,
99 :password_confirmation => password,
101 :password_confirmation => password,
100 :alias => user_alias,
102 :alias => user_alias,
101 :remark => remark})
103 :remark => remark})
102 end
104 end
103 user.activated = true
105 user.activated = true
104 - user.save
105
106
107 + if user.save
106 if added_random_password
108 if added_random_password
107 note << "'#{login}' (+)"
109 note << "'#{login}' (+)"
108 else
110 else
109 note << login
111 note << login
110 end
112 end
113 + ok_user << user
114 + else
115 + error_note << "#{login}"
116 + end
117 +
111 end
118 end
112 end
119 end
120 +
121 + #add to group
122 + if params[:add_to_group]
123 + group = Group.where(id: params[:group_id]).first
124 + if group
125 + group.users << ok_user
126 + end
127 + end
128 +
129 + # show flash
113 flash[:success] = 'User(s) ' + note.join(', ') +
130 flash[:success] = 'User(s) ' + note.join(', ') +
114 ' were successfully created. ' +
131 ' were successfully created. ' +
115 '( (+) - created with random passwords.)'
132 '( (+) - created with random passwords.)'
133 + if error_note.size > 0
134 + flash[:error] = "Following user(s) failed to be created: " + error_note.join(', ')
135 + end
116 redirect_to :action => 'index'
136 redirect_to :action => 'index'
117 end
137 end
118
138
119 def edit
139 def edit
120 @user = User.find(params[:id])
140 @user = User.find(params[:id])
121 end
141 end
122
142
123 def update
143 def update
124 @user = User.find(params[:id])
144 @user = User.find(params[:id])
125 if @user.update_attributes(user_params)
145 if @user.update_attributes(user_params)
126 flash[:notice] = 'User was successfully updated.'
146 flash[:notice] = 'User was successfully updated.'
127 redirect_to :action => 'show', :id => @user
147 redirect_to :action => 'show', :id => @user
128 else
148 else
129 render :action => 'edit'
149 render :action => 'edit'
130 end
150 end
131 end
151 end
132
152
133 def destroy
153 def destroy
134 User.find(params[:id]).destroy
154 User.find(params[:id]).destroy
135 redirect_to :action => 'index'
155 redirect_to :action => 'index'
136 end
156 end
137
157
138 def user_stat
158 def user_stat
139 if params[:commit] == 'download csv'
159 if params[:commit] == 'download csv'
140 @problems = Problem.all
160 @problems = Problem.all
141 else
161 else
142 @problems = Problem.available_problems
162 @problems = Problem.available_problems
143 end
163 end
144 @users = User.includes(:contests, :contest_stat).where(enabled: true)
164 @users = User.includes(:contests, :contest_stat).where(enabled: true)
145 @scorearray = Array.new
165 @scorearray = Array.new
146 @users.each do |u|
166 @users.each do |u|
147 ustat = Array.new
167 ustat = Array.new
148 ustat[0] = u
168 ustat[0] = u
149 @problems.each do |p|
169 @problems.each do |p|
150 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
170 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
151 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
171 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
152 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
172 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
153 else
173 else
154 ustat << [0,false]
174 ustat << [0,false]
155 end
175 end
156 end
176 end
157 @scorearray << ustat
177 @scorearray << ustat
158 end
178 end
159 if params[:commit] == 'download csv' then
179 if params[:commit] == 'download csv' then
160 csv = gen_csv_from_scorearray(@scorearray,@problems)
180 csv = gen_csv_from_scorearray(@scorearray,@problems)
161 send_data csv, filename: 'last_score.csv'
181 send_data csv, filename: 'last_score.csv'
162 else
182 else
163 render template: 'user_admin/user_stat'
183 render template: 'user_admin/user_stat'
164 end
184 end
165 end
185 end
166
186
167 def user_stat_max
187 def user_stat_max
168 if params[:commit] == 'download csv'
188 if params[:commit] == 'download csv'
169 @problems = Problem.all
189 @problems = Problem.all
170 else
190 else
171 @problems = Problem.available_problems
191 @problems = Problem.available_problems
172 end
192 end
173 @users = User.includes(:contests).includes(:contest_stat).all
193 @users = User.includes(:contests).includes(:contest_stat).all
174 @scorearray = Array.new
194 @scorearray = Array.new
175 #set up range from param
195 #set up range from param
176 since_id = params.fetch(:since_id, 0).to_i
196 since_id = params.fetch(:since_id, 0).to_i
177 until_id = params.fetch(:until_id, 0).to_i
197 until_id = params.fetch(:until_id, 0).to_i
178 @users.each do |u|
198 @users.each do |u|
179 ustat = Array.new
199 ustat = Array.new
180 ustat[0] = u
200 ustat[0] = u
181 @problems.each do |p|
201 @problems.each do |p|
182 max_points = 0
202 max_points = 0
183 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
203 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
184 max_points = sub.points if sub and sub.points and (sub.points > max_points)
204 max_points = sub.points if sub and sub.points and (sub.points > max_points)
185 end
205 end
186 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
206 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
187 end
207 end
188 @scorearray << ustat
208 @scorearray << ustat
189 end
209 end
190
210
191 if params[:commit] == 'download csv' then
211 if params[:commit] == 'download csv' then
192 csv = gen_csv_from_scorearray(@scorearray,@problems)
212 csv = gen_csv_from_scorearray(@scorearray,@problems)
193 send_data csv, filename: 'max_score.csv'
213 send_data csv, filename: 'max_score.csv'
194 else
214 else
195 render template: 'user_admin/user_stat'
215 render template: 'user_admin/user_stat'
196 end
216 end
197 end
217 end
198
218
199 def import
219 def import
200 if params[:file]==''
220 if params[:file]==''
201 flash[:notice] = 'Error importing no file'
221 flash[:notice] = 'Error importing no file'
202 redirect_to :action => 'index' and return
222 redirect_to :action => 'index' and return
203 end
223 end
204 import_from_file(params[:file])
224 import_from_file(params[:file])
205 end
225 end
206
226
207 def random_all_passwords
227 def random_all_passwords
208 users = User.all
228 users = User.all
209 @prefix = params[:prefix] || ''
229 @prefix = params[:prefix] || ''
210 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
230 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
211 @changed = false
231 @changed = false
212 if params[:commit] == 'Go ahead'
232 if params[:commit] == 'Go ahead'
213 @non_admin_users.each do |user|
233 @non_admin_users.each do |user|
214 password = random_password
234 password = random_password
215 user.password = password
235 user.password = password
216 user.password_confirmation = password
236 user.password_confirmation = password
217 user.save
237 user.save
218 end
238 end
219 @changed = true
239 @changed = true
220 end
240 end
221 end
241 end
222
242
223 # contest management
243 # contest management
224
244
225 def contests
245 def contests
226 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
246 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
227 @contests = Contest.enabled
247 @contests = Contest.enabled
228 end
248 end
229
249
230 def assign_from_list
250 def assign_from_list
231 contest_id = params[:users_contest_id]
251 contest_id = params[:users_contest_id]
232 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
252 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
233 contest = Contest.find(params[:new_contest][:id])
253 contest = Contest.find(params[:new_contest][:id])
234 if !contest
254 if !contest
235 flash[:notice] = 'Error: no contest'
255 flash[:notice] = 'Error: no contest'
236 redirect_to :action => 'contests', :id =>contest_id
256 redirect_to :action => 'contests', :id =>contest_id
237 end
257 end
238
258
239 note = []
259 note = []
240 users.each do |u|
260 users.each do |u|
241 u.contests = [contest]
261 u.contests = [contest]
242 note << u.login
262 note << u.login
243 end
263 end
244 flash[:notice] = 'User(s) ' + note.join(', ') +
264 flash[:notice] = 'User(s) ' + note.join(', ') +
245 " were successfully reassigned to #{contest.title}."
265 " were successfully reassigned to #{contest.title}."
246 redirect_to :action => 'contests', :id =>contest.id
266 redirect_to :action => 'contests', :id =>contest.id
247 end
267 end
248
268
249 def add_to_contest
269 def add_to_contest
250 user = User.find(params[:id])
270 user = User.find(params[:id])
251 contest = Contest.find(params[:contest_id])
271 contest = Contest.find(params[:contest_id])
252 if user and contest
272 if user and contest
253 user.contests << contest
273 user.contests << contest
254 end
274 end
255 redirect_to :action => 'index'
275 redirect_to :action => 'index'
256 end
276 end
257
277
258 def remove_from_contest
278 def remove_from_contest
259 user = User.find(params[:id])
279 user = User.find(params[:id])
260 contest = Contest.find(params[:contest_id])
280 contest = Contest.find(params[:contest_id])
261 if user and contest
281 if user and contest
262 user.contests.delete(contest)
282 user.contests.delete(contest)
263 end
283 end
264 redirect_to :action => 'index'
284 redirect_to :action => 'index'
265 end
285 end
266
286
267 def contest_management
287 def contest_management
268 end
288 end
269
289
270 def manage_contest
290 def manage_contest
271 contest = Contest.find(params[:contest][:id])
291 contest = Contest.find(params[:contest][:id])
272 if !contest
292 if !contest
273 flash[:notice] = 'You did not choose the contest.'
293 flash[:notice] = 'You did not choose the contest.'
274 redirect_to :action => 'contest_management' and return
294 redirect_to :action => 'contest_management' and return
275 end
295 end
276
296
277 operation = params[:operation]
297 operation = params[:operation]
278
298
279 if not ['add','remove','assign'].include? operation
299 if not ['add','remove','assign'].include? operation
280 flash[:notice] = 'You did not choose the operation to perform.'
300 flash[:notice] = 'You did not choose the operation to perform.'
281 redirect_to :action => 'contest_management' and return
301 redirect_to :action => 'contest_management' and return
282 end
302 end
283
303
284 lines = params[:login_list]
304 lines = params[:login_list]
285 if !lines or lines.blank?
305 if !lines or lines.blank?
286 flash[:notice] = 'You entered an empty list.'
306 flash[:notice] = 'You entered an empty list.'
287 redirect_to :action => 'contest_management' and return
307 redirect_to :action => 'contest_management' and return
288 end
308 end
289
309
290 note = []
310 note = []
291 users = []
311 users = []
292 lines.split("\n").each do |line|
312 lines.split("\n").each do |line|
293 user = User.find_by_login(line.chomp)
313 user = User.find_by_login(line.chomp)
294 if user
314 if user
295 if operation=='add'
315 if operation=='add'
296 if ! user.contests.include? contest
316 if ! user.contests.include? contest
297 user.contests << contest
317 user.contests << contest
298 end
318 end
299 elsif operation=='remove'
319 elsif operation=='remove'
300 user.contests.delete(contest)
320 user.contests.delete(contest)
301 else
321 else
302 user.contests = [contest]
322 user.contests = [contest]
303 end
323 end
304
324
305 if params[:reset_timer]
325 if params[:reset_timer]
306 user.contest_stat.forced_logout = true
326 user.contest_stat.forced_logout = true
307 user.contest_stat.reset_timer_and_save
327 user.contest_stat.reset_timer_and_save
308 end
328 end
309
329
310 if params[:notification_emails]
330 if params[:notification_emails]
311 send_contest_update_notification_email(user, contest)
331 send_contest_update_notification_email(user, contest)
312 end
332 end
313
333
314 note << user.login
334 note << user.login
315 users << user
335 users << user
316 end
336 end
317 end
337 end
318
338
319 if params[:reset_timer]
339 if params[:reset_timer]
320 logout_users(users)
340 logout_users(users)
321 end
341 end
322
342
323 flash[:notice] = 'User(s) ' + note.join(', ') +
343 flash[:notice] = 'User(s) ' + note.join(', ') +
324 ' were successfully modified. '
344 ' were successfully modified. '
325 redirect_to :action => 'contest_management'
345 redirect_to :action => 'contest_management'
326 end
346 end
327
347
328 # admin management
348 # admin management
329
349
330 def admin
350 def admin
331 @admins = User.all.find_all {|user| user.admin? }
351 @admins = User.all.find_all {|user| user.admin? }
332 end
352 end
333
353
334 def grant_admin
354 def grant_admin
335 login = params[:login]
355 login = params[:login]
336 user = User.find_by_login(login)
356 user = User.find_by_login(login)
337 if user!=nil
357 if user!=nil
338 admin_role = Role.find_by_name('admin')
358 admin_role = Role.find_by_name('admin')
339 user.roles << admin_role
359 user.roles << admin_role
340 else
360 else
341 flash[:notice] = 'Unknown user'
361 flash[:notice] = 'Unknown user'
342 end
362 end
343 flash[:notice] = 'User added as admins'
363 flash[:notice] = 'User added as admins'
344 redirect_to :action => 'admin'
364 redirect_to :action => 'admin'
345 end
365 end
346
366
347 def revoke_admin
367 def revoke_admin
348 user = User.find(params[:id])
368 user = User.find(params[:id])
349 if user==nil
369 if user==nil
350 flash[:notice] = 'Unknown user'
370 flash[:notice] = 'Unknown user'
351 redirect_to :action => 'admin' and return
371 redirect_to :action => 'admin' and return
352 elsif user.login == 'root'
372 elsif user.login == 'root'
353 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
373 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
354 redirect_to :action => 'admin' and return
374 redirect_to :action => 'admin' and return
355 end
375 end
356
376
357 admin_role = Role.find_by_name('admin')
377 admin_role = Role.find_by_name('admin')
358 user.roles.delete(admin_role)
378 user.roles.delete(admin_role)
359 flash[:notice] = 'User permission revoked'
379 flash[:notice] = 'User permission revoked'
360 redirect_to :action => 'admin'
380 redirect_to :action => 'admin'
361 end
381 end
362
382
363 # mass mailing
383 # mass mailing
364
384
365 def mass_mailing
385 def mass_mailing
366 end
386 end
367
387
368 def bulk_mail
388 def bulk_mail
369 lines = params[:login_list]
389 lines = params[:login_list]
370 if !lines or lines.blank?
390 if !lines or lines.blank?
371 flash[:notice] = 'You entered an empty list.'
391 flash[:notice] = 'You entered an empty list.'
372 redirect_to :action => 'mass_mailing' and return
392 redirect_to :action => 'mass_mailing' and return
373 end
393 end
374
394
375 mail_subject = params[:subject]
395 mail_subject = params[:subject]
376 if !mail_subject or mail_subject.blank?
396 if !mail_subject or mail_subject.blank?
377 flash[:notice] = 'You entered an empty mail subject.'
397 flash[:notice] = 'You entered an empty mail subject.'
378 redirect_to :action => 'mass_mailing' and return
398 redirect_to :action => 'mass_mailing' and return
379 end
399 end
380
400
381 mail_body = params[:email_body]
401 mail_body = params[:email_body]
382 if !mail_body or mail_body.blank?
402 if !mail_body or mail_body.blank?
383 flash[:notice] = 'You entered an empty mail body.'
403 flash[:notice] = 'You entered an empty mail body.'
384 redirect_to :action => 'mass_mailing' and return
404 redirect_to :action => 'mass_mailing' and return
385 end
405 end
386
406
387 note = []
407 note = []
388 users = []
408 users = []
389 lines.split("\n").each do |line|
409 lines.split("\n").each do |line|
390 user = User.find_by_login(line.chomp)
410 user = User.find_by_login(line.chomp)
391 if user
411 if user
392 send_mail(user.email, mail_subject, mail_body)
412 send_mail(user.email, mail_subject, mail_body)
393 note << user.login
413 note << user.login
394 end
414 end
395 end
415 end
396
416
397 flash[:notice] = 'User(s) ' + note.join(', ') +
417 flash[:notice] = 'User(s) ' + note.join(', ') +
398 ' were successfully modified. '
418 ' were successfully modified. '
399 redirect_to :action => 'mass_mailing'
419 redirect_to :action => 'mass_mailing'
400 end
420 end
401
421
402 #bulk manage
422 #bulk manage
403 def bulk_manage
423 def bulk_manage
404
424
405 begin
425 begin
406 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
426 @users = User.where('(login REGEXP ?) OR (remark REGEXP ?)',params[:regex],params[:regex]) if params[:regex]
407 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
427 @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
408 rescue Exception
428 rescue Exception
409 flash[:error] = 'Regular Expression is malformed'
429 flash[:error] = 'Regular Expression is malformed'
410 @users = nil
430 @users = nil
411 end
431 end
412
432
413 if params[:commit]
433 if params[:commit]
414 @action = {}
434 @action = {}
415 @action[:set_enable] = params[:enabled]
435 @action[:set_enable] = params[:enabled]
416 @action[:enabled] = params[:enable] == "1"
436 @action[:enabled] = params[:enable] == "1"
417 @action[:gen_password] = params[:gen_password]
437 @action[:gen_password] = params[:gen_password]
418 @action[:add_group] = params[:add_group]
438 @action[:add_group] = params[:add_group]
419 @action[:group_name] = params[:group_name]
439 @action[:group_name] = params[:group_name]
420 end
440 end
421
441
422 if params[:commit] == "Perform"
442 if params[:commit] == "Perform"
423 if @action[:set_enable]
443 if @action[:set_enable]
424 @users.update_all(enabled: @action[:enabled])
444 @users.update_all(enabled: @action[:enabled])
425 end
445 end
426 if @action[:gen_password]
446 if @action[:gen_password]
427 @users.each do |u|
447 @users.each do |u|
428 password = random_password
448 password = random_password
429 u.password = password
449 u.password = password
430 u.password_confirmation = password
450 u.password_confirmation = password
431 u.save
451 u.save
432 end
452 end
433 end
453 end
434 if @action[:add_group] and @action[:group_name]
454 if @action[:add_group] and @action[:group_name]
435 @group = Group.find(@action[:group_name])
455 @group = Group.find(@action[:group_name])
436 ok = []
456 ok = []
437 failed = []
457 failed = []
438 @users.each do |user|
458 @users.each do |user|
439 begin
459 begin
440 @group.users << user
460 @group.users << user
441 ok << user.login
461 ok << user.login
442 rescue => e
462 rescue => e
443 failed << user.login
463 failed << user.login
444 end
464 end
445 end
465 end
446 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
466 flash[:success] = "The following users are added to the 'group #{@group.name}': " + ok.join(', ') if ok.count > 0
447 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
467 flash[:alert] = "The following users are already in the 'group #{@group.name}': " + failed.join(', ') if failed.count > 0
448 end
468 end
449 end
469 end
450 end
470 end
451
471
452 protected
472 protected
453
473
454 def random_password(length=5)
474 def random_password(length=5)
455 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
475 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
456 newpass = ""
476 newpass = ""
457 length.times { newpass << chars[rand(chars.size-1)] }
477 length.times { newpass << chars[rand(chars.size-1)] }
458 return newpass
478 return newpass
459 end
479 end
460
480
461 def import_from_file(f)
481 def import_from_file(f)
462 data_hash = YAML.load(f)
482 data_hash = YAML.load(f)
463 @import_log = ""
483 @import_log = ""
464
484
465 country_data = data_hash[:countries]
485 country_data = data_hash[:countries]
466 site_data = data_hash[:sites]
486 site_data = data_hash[:sites]
467 user_data = data_hash[:users]
487 user_data = data_hash[:users]
468
488
469 # import country
489 # import country
470 countries = {}
490 countries = {}
471 country_data.each_pair do |id,country|
491 country_data.each_pair do |id,country|
472 c = Country.find_by_name(country[:name])
492 c = Country.find_by_name(country[:name])
473 if c!=nil
493 if c!=nil
474 countries[id] = c
494 countries[id] = c
475 @import_log << "Found #{country[:name]}\n"
495 @import_log << "Found #{country[:name]}\n"
476 else
496 else
477 countries[id] = Country.new(:name => country[:name])
497 countries[id] = Country.new(:name => country[:name])
478 countries[id].save
498 countries[id].save
479 @import_log << "Created #{country[:name]}\n"
499 @import_log << "Created #{country[:name]}\n"
480 end
500 end
481 end
501 end
482
502
483 # import sites
503 # import sites
484 sites = {}
504 sites = {}
485 site_data.each_pair do |id,site|
505 site_data.each_pair do |id,site|
486 s = Site.find_by_name(site[:name])
506 s = Site.find_by_name(site[:name])
487 if s!=nil
507 if s!=nil
488 @import_log << "Found #{site[:name]}\n"
508 @import_log << "Found #{site[:name]}\n"
489 else
509 else
490 s = Site.new(:name => site[:name])
510 s = Site.new(:name => site[:name])
491 @import_log << "Created #{site[:name]}\n"
511 @import_log << "Created #{site[:name]}\n"
492 end
512 end
493 s.password = site[:password]
513 s.password = site[:password]
494 s.country = countries[site[:country_id]]
514 s.country = countries[site[:country_id]]
495 s.save
515 s.save
496 sites[id] = s
516 sites[id] = s
497 end
517 end
498
518
499 # import users
519 # import users
@@ -1,19 +1,20
1 module MainHelper
1 module MainHelper
2
2
3 def link_to_description_if_any(name, problem, options={})
3 def link_to_description_if_any(name, problem, options={})
4 if !problem.url.blank?
4 if !problem.url.blank?
5 return link_to name, problem.url, options
5 return link_to name, problem.url, options
6 elsif !problem.description_filename.blank?
6 elsif !problem.description_filename.blank?
7 + #build a link to a problem (via task controller)
7 basename, ext = problem.description_filename.split('.')
8 basename, ext = problem.description_filename.split('.')
8 options[:controller] = 'tasks'
9 options[:controller] = 'tasks'
9 options[:action] = 'download'
10 options[:action] = 'download'
10 options[:id] = problem.id
11 options[:id] = problem.id
11 options[:file] = basename
12 options[:file] = basename
12 options[:ext] = ext
13 options[:ext] = ext
13 return link_to name, options
14 return link_to name, options
14 else
15 else
15 return ''
16 return ''
16 end
17 end
17 end
18 end
18
19
19 end
20 end
@@ -1,369 +1,374
1 require 'digest/sha1'
1 require 'digest/sha1'
2 require 'net/pop'
2 require 'net/pop'
3 require 'net/https'
3 require 'net/https'
4 require 'net/http'
4 require 'net/http'
5 require 'json'
5 require 'json'
6
6
7 class User < ActiveRecord::Base
7 class User < ActiveRecord::Base
8
8
9 has_and_belongs_to_many :roles
9 has_and_belongs_to_many :roles
10
10
11 #has_and_belongs_to_many :groups
11 #has_and_belongs_to_many :groups
12 has_many :groups_users, class_name: 'GroupUser'
12 has_many :groups_users, class_name: 'GroupUser'
13 has_many :groups, :through => :groups_users
13 has_many :groups, :through => :groups_users
14
14
15 has_many :test_requests, -> {order(submitted_at: :desc)}
15 has_many :test_requests, -> {order(submitted_at: :desc)}
16
16
17 has_many :messages, -> { order(created_at: :desc) },
17 has_many :messages, -> { order(created_at: :desc) },
18 :class_name => "Message",
18 :class_name => "Message",
19 :foreign_key => "sender_id"
19 :foreign_key => "sender_id"
20
20
21 has_many :replied_messages, -> { order(created_at: :desc) },
21 has_many :replied_messages, -> { order(created_at: :desc) },
22 :class_name => "Message",
22 :class_name => "Message",
23 :foreign_key => "receiver_id"
23 :foreign_key => "receiver_id"
24
24
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
25 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26
26
27 belongs_to :site
27 belongs_to :site
28 belongs_to :country
28 belongs_to :country
29
29
30 has_and_belongs_to_many :contests, -> { order(:name)}
30 has_and_belongs_to_many :contests, -> { order(:name)}
31
31
32 scope :activated_users, -> {where activated: true}
32 scope :activated_users, -> {where activated: true}
33
33
34 validates_presence_of :login
34 validates_presence_of :login
35 validates_uniqueness_of :login
35 validates_uniqueness_of :login
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
36 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 validates_length_of :login, :within => 3..30
37 validates_length_of :login, :within => 3..30
38
38
39 validates_presence_of :full_name
39 validates_presence_of :full_name
40 validates_length_of :full_name, :minimum => 1
40 validates_length_of :full_name, :minimum => 1
41
41
42 validates_presence_of :password, :if => :password_required?
42 validates_presence_of :password, :if => :password_required?
43 validates_length_of :password, :within => 4..20, :if => :password_required?
43 validates_length_of :password, :within => 4..20, :if => :password_required?
44 validates_confirmation_of :password, :if => :password_required?
44 validates_confirmation_of :password, :if => :password_required?
45
45
46 validates_format_of :email,
46 validates_format_of :email,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
47 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 :if => :email_validation?
48 :if => :email_validation?
49 validate :uniqueness_of_email_from_activated_users,
49 validate :uniqueness_of_email_from_activated_users,
50 :if => :email_validation?
50 :if => :email_validation?
51 validate :enough_time_interval_between_same_email_registrations,
51 validate :enough_time_interval_between_same_email_registrations,
52 :if => :email_validation?
52 :if => :email_validation?
53
53
54 # these are for ytopc
54 # these are for ytopc
55 # disable for now
55 # disable for now
56 #validates_presence_of :province
56 #validates_presence_of :province
57
57
58 attr_accessor :password
58 attr_accessor :password
59
59
60 before_save :encrypt_new_password
60 before_save :encrypt_new_password
61 before_save :assign_default_site
61 before_save :assign_default_site
62 before_save :assign_default_contest
62 before_save :assign_default_contest
63
63
64 # this is for will_paginate
64 # this is for will_paginate
65 cattr_reader :per_page
65 cattr_reader :per_page
66 @@per_page = 50
66 @@per_page = 50
67
67
68 def self.authenticate(login, password)
68 def self.authenticate(login, password)
69 user = find_by_login(login)
69 user = find_by_login(login)
70 if user
70 if user
71 return user if user.authenticated?(password)
71 return user if user.authenticated?(password)
72 end
72 end
73 end
73 end
74
74
75 def authenticated?(password)
75 def authenticated?(password)
76 if self.activated
76 if self.activated
77 hashed_password == User.encrypt(password,self.salt)
77 hashed_password == User.encrypt(password,self.salt)
78 else
78 else
79 false
79 false
80 end
80 end
81 end
81 end
82
82
83 def admin?
83 def admin?
84 self.roles.where(name: 'admin').count > 0
84 self.roles.where(name: 'admin').count > 0
85 end
85 end
86
86
87 def email_for_editing
87 def email_for_editing
88 if self.email==nil
88 if self.email==nil
89 "(unknown)"
89 "(unknown)"
90 elsif self.email==''
90 elsif self.email==''
91 "(blank)"
91 "(blank)"
92 else
92 else
93 self.email
93 self.email
94 end
94 end
95 end
95 end
96
96
97 def email_for_editing=(e)
97 def email_for_editing=(e)
98 self.email=e
98 self.email=e
99 end
99 end
100
100
101 def alias_for_editing
101 def alias_for_editing
102 if self.alias==nil
102 if self.alias==nil
103 "(unknown)"
103 "(unknown)"
104 elsif self.alias==''
104 elsif self.alias==''
105 "(blank)"
105 "(blank)"
106 else
106 else
107 self.alias
107 self.alias
108 end
108 end
109 end
109 end
110
110
111 def alias_for_editing=(e)
111 def alias_for_editing=(e)
112 self.alias=e
112 self.alias=e
113 end
113 end
114
114
115 def activation_key
115 def activation_key
116 if self.hashed_password==nil
116 if self.hashed_password==nil
117 encrypt_new_password
117 encrypt_new_password
118 end
118 end
119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
119 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
120 end
120 end
121
121
122 def verify_activation_key(key)
122 def verify_activation_key(key)
123 key == activation_key
123 key == activation_key
124 end
124 end
125
125
126 def self.random_password(length=5)
126 def self.random_password(length=5)
127 chars = 'abcdefghjkmnopqrstuvwxyz'
127 chars = 'abcdefghjkmnopqrstuvwxyz'
128 password = ''
128 password = ''
129 length.times { password << chars[rand(chars.length - 1)] }
129 length.times { password << chars[rand(chars.length - 1)] }
130 password
130 password
131 end
131 end
132
132
133 def self.find_non_admin_with_prefix(prefix='')
133 def self.find_non_admin_with_prefix(prefix='')
134 users = User.all
134 users = User.all
135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
135 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
136 end
136 end
137
137
138 # Contest information
138 # Contest information
139
139
140 def self.find_users_with_no_contest()
140 def self.find_users_with_no_contest()
141 users = User.all
141 users = User.all
142 return users.find_all { |u| u.contests.length == 0 }
142 return users.find_all { |u| u.contests.length == 0 }
143 end
143 end
144
144
145
145
146 def contest_time_left
146 def contest_time_left
147 if GraderConfiguration.contest_mode?
147 if GraderConfiguration.contest_mode?
148 return nil if site==nil
148 return nil if site==nil
149 return site.time_left
149 return site.time_left
150 elsif GraderConfiguration.indv_contest_mode?
150 elsif GraderConfiguration.indv_contest_mode?
151 time_limit = GraderConfiguration.contest_time_limit
151 time_limit = GraderConfiguration.contest_time_limit
152 if time_limit == nil
152 if time_limit == nil
153 return nil
153 return nil
154 end
154 end
155 if contest_stat==nil or contest_stat.started_at==nil
155 if contest_stat==nil or contest_stat.started_at==nil
156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
156 return (Time.now.gmtime + time_limit) - Time.now.gmtime
157 else
157 else
158 finish_time = contest_stat.started_at + time_limit
158 finish_time = contest_stat.started_at + time_limit
159 current_time = Time.now.gmtime
159 current_time = Time.now.gmtime
160 if current_time > finish_time
160 if current_time > finish_time
161 return 0
161 return 0
162 else
162 else
163 return finish_time - current_time
163 return finish_time - current_time
164 end
164 end
165 end
165 end
166 else
166 else
167 return nil
167 return nil
168 end
168 end
169 end
169 end
170
170
171 def contest_finished?
171 def contest_finished?
172 if GraderConfiguration.contest_mode?
172 if GraderConfiguration.contest_mode?
173 return false if site==nil
173 return false if site==nil
174 return site.finished?
174 return site.finished?
175 elsif GraderConfiguration.indv_contest_mode?
175 elsif GraderConfiguration.indv_contest_mode?
176 return false if self.contest_stat==nil
176 return false if self.contest_stat==nil
177 return contest_time_left == 0
177 return contest_time_left == 0
178 else
178 else
179 return false
179 return false
180 end
180 end
181 end
181 end
182
182
183 def contest_started?
183 def contest_started?
184 if GraderConfiguration.indv_contest_mode?
184 if GraderConfiguration.indv_contest_mode?
185 stat = self.contest_stat
185 stat = self.contest_stat
186 return ((stat != nil) and (stat.started_at != nil))
186 return ((stat != nil) and (stat.started_at != nil))
187 elsif GraderConfiguration.contest_mode?
187 elsif GraderConfiguration.contest_mode?
188 return true if site==nil
188 return true if site==nil
189 return site.started
189 return site.started
190 else
190 else
191 return true
191 return true
192 end
192 end
193 end
193 end
194
194
195 def update_start_time
195 def update_start_time
196 stat = self.contest_stat
196 stat = self.contest_stat
197 if stat.nil? or stat.started_at.nil?
197 if stat.nil? or stat.started_at.nil?
198 stat ||= UserContestStat.new(:user => self)
198 stat ||= UserContestStat.new(:user => self)
199 stat.started_at = Time.now.gmtime
199 stat.started_at = Time.now.gmtime
200 stat.save
200 stat.save
201 end
201 end
202 end
202 end
203
203
204 def problem_in_user_contests?(problem)
204 def problem_in_user_contests?(problem)
205 problem_contests = problem.contests.all
205 problem_contests = problem.contests.all
206
206
207 if problem_contests.length == 0 # this is public contest
207 if problem_contests.length == 0 # this is public contest
208 return true
208 return true
209 end
209 end
210
210
211 contests.each do |contest|
211 contests.each do |contest|
212 if problem_contests.find {|c| c.id == contest.id }
212 if problem_contests.find {|c| c.id == contest.id }
213 return true
213 return true
214 end
214 end
215 end
215 end
216 return false
216 return false
217 end
217 end
218
218
219 def available_problems_group_by_contests
219 def available_problems_group_by_contests
220 contest_problems = []
220 contest_problems = []
221 pin = {}
221 pin = {}
222 contests.enabled.each do |contest|
222 contests.enabled.each do |contest|
223 available_problems = contest.problems.available
223 available_problems = contest.problems.available
224 contest_problems << {
224 contest_problems << {
225 :contest => contest,
225 :contest => contest,
226 :problems => available_problems
226 :problems => available_problems
227 }
227 }
228 available_problems.each {|p| pin[p.id] = true}
228 available_problems.each {|p| pin[p.id] = true}
229 end
229 end
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
230 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
231 contest_problems << {
231 contest_problems << {
232 :contest => nil,
232 :contest => nil,
233 :problems => other_avaiable_problems
233 :problems => other_avaiable_problems
234 }
234 }
235 return contest_problems
235 return contest_problems
236 end
236 end
237
237
238 def solve_all_available_problems?
238 def solve_all_available_problems?
239 available_problems.each do |p|
239 available_problems.each do |p|
240 u = self
240 u = self
241 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
241 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
242 return false if !p or !sub or sub.points < p.full_score
242 return false if !p or !sub or sub.points < p.full_score
243 end
243 end
244 return true
244 return true
245 end
245 end
246
246
247 #get a list of available problem
247 #get a list of available problem
248 def available_problems
248 def available_problems
249 + # first, we check if this is normal mode
249 if not GraderConfiguration.multicontests?
250 if not GraderConfiguration.multicontests?
251 +
252 + #if this is a normal mode
253 + #we show problem based on problem_group, if the config said so
250 if GraderConfiguration.use_problem_group?
254 if GraderConfiguration.use_problem_group?
251 return available_problems_in_group
255 return available_problems_in_group
252 else
256 else
253 return Problem.available_problems
257 return Problem.available_problems
254 end
258 end
255 else
259 else
260 + #this is multi contest mode
256 contest_problems = []
261 contest_problems = []
257 pin = {}
262 pin = {}
258 contests.enabled.each do |contest|
263 contests.enabled.each do |contest|
259 contest.problems.available.each do |problem|
264 contest.problems.available.each do |problem|
260 if not pin.has_key? problem.id
265 if not pin.has_key? problem.id
261 contest_problems << problem
266 contest_problems << problem
262 end
267 end
263 pin[problem.id] = true
268 pin[problem.id] = true
264 end
269 end
265 end
270 end
266 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
271 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
267 return contest_problems + other_avaiable_problems
272 return contest_problems + other_avaiable_problems
268 end
273 end
269 end
274 end
270
275
271 def available_problems_in_group
276 def available_problems_in_group
272 problem = []
277 problem = []
273 self.groups.each do |group|
278 self.groups.each do |group|
274 group.problems.where(available: true).each { |p| problem << p }
279 group.problems.where(available: true).each { |p| problem << p }
275 end
280 end
276 problem.uniq!
281 problem.uniq!
277 if problem
282 if problem
278 problem.sort! do |a,b|
283 problem.sort! do |a,b|
279 case
284 case
280 when a.date_added < b.date_added
285 when a.date_added < b.date_added
281 1
286 1
282 when a.date_added > b.date_added
287 when a.date_added > b.date_added
283 -1
288 -1
284 else
289 else
285 a.name <=> b.name
290 a.name <=> b.name
286 end
291 end
287 end
292 end
288 return problem
293 return problem
289 else
294 else
290 return []
295 return []
291 end
296 end
292 end
297 end
293
298
294 def can_view_problem?(problem)
299 def can_view_problem?(problem)
295 return true if admin?
300 return true if admin?
296 return available_problems.include? problem
301 return available_problems.include? problem
297 end
302 end
298
303
299 def self.clear_last_login
304 def self.clear_last_login
300 User.update_all(:last_ip => nil)
305 User.update_all(:last_ip => nil)
301 end
306 end
302
307
303 protected
308 protected
304 def encrypt_new_password
309 def encrypt_new_password
305 return if password.blank?
310 return if password.blank?
306 self.salt = (10+rand(90)).to_s
311 self.salt = (10+rand(90)).to_s
307 self.hashed_password = User.encrypt(self.password,self.salt)
312 self.hashed_password = User.encrypt(self.password,self.salt)
308 end
313 end
309
314
310 def assign_default_site
315 def assign_default_site
311 # have to catch error when migrating (because self.site is not available).
316 # have to catch error when migrating (because self.site is not available).
312 begin
317 begin
313 if self.site==nil
318 if self.site==nil
314 self.site = Site.find_by_name('default')
319 self.site = Site.find_by_name('default')
315 if self.site==nil
320 if self.site==nil
316 self.site = Site.find(1) # when 'default has be renamed'
321 self.site = Site.find(1) # when 'default has be renamed'
317 end
322 end
318 end
323 end
319 rescue
324 rescue
320 end
325 end
321 end
326 end
322
327
323 def assign_default_contest
328 def assign_default_contest
324 # have to catch error when migrating (because self.site is not available).
329 # have to catch error when migrating (because self.site is not available).
325 begin
330 begin
326 if self.contests.length == 0
331 if self.contests.length == 0
327 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
332 default_contest = Contest.find_by_name(GraderConfiguration['contest.default_contest_name'])
328 if default_contest
333 if default_contest
329 self.contests = [default_contest]
334 self.contests = [default_contest]
330 end
335 end
331 end
336 end
332 rescue
337 rescue
333 end
338 end
334 end
339 end
335
340
336 def password_required?
341 def password_required?
337 self.hashed_password.blank? || !self.password.blank?
342 self.hashed_password.blank? || !self.password.blank?
338 end
343 end
339
344
340 def self.encrypt(string,salt)
345 def self.encrypt(string,salt)
341 Digest::SHA1.hexdigest(salt + string)
346 Digest::SHA1.hexdigest(salt + string)
342 end
347 end
343
348
344 def uniqueness_of_email_from_activated_users
349 def uniqueness_of_email_from_activated_users
345 user = User.activated_users.find_by_email(self.email)
350 user = User.activated_users.find_by_email(self.email)
346 if user and (user.login != self.login)
351 if user and (user.login != self.login)
347 self.errors.add(:base,"Email has already been taken")
352 self.errors.add(:base,"Email has already been taken")
348 end
353 end
349 end
354 end
350
355
351 def enough_time_interval_between_same_email_registrations
356 def enough_time_interval_between_same_email_registrations
352 return if !self.new_record?
357 return if !self.new_record?
353 return if self.activated
358 return if self.activated
354 open_user = User.find_by_email(self.email,
359 open_user = User.find_by_email(self.email,
355 :order => 'created_at DESC')
360 :order => 'created_at DESC')
356 if open_user and open_user.created_at and
361 if open_user and open_user.created_at and
357 (open_user.created_at > Time.now.gmtime - 5.minutes)
362 (open_user.created_at > Time.now.gmtime - 5.minutes)
358 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
363 self.errors.add(:base,"There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
359 end
364 end
360 end
365 end
361
366
362 def email_validation?
367 def email_validation?
363 begin
368 begin
364 return VALIDATE_USER_EMAILS
369 return VALIDATE_USER_EMAILS
365 rescue
370 rescue
366 return false
371 return false
367 end
372 end
368 end
373 end
369 end
374 end
@@ -1,73 +1,80
1 - %p
1 + .container-fluid
2 - %b Name:
2 + .row
3 - = @group.name
3 + .col-md-6
4 - %p
4 + %h1 Group #{@group.name}
5 + .row
6 + .col-md-6
5 %b Description:
7 %b Description:
6 = @group.description
8 = @group.description
7 -
8 %br
9 %br
9 - = link_to 'Edit', edit_group_path(@group)
10 + = link_to 'Edit', edit_group_path(@group), class: 'btn btn-primary'
10 - \|
11 - = link_to 'Back', groups_path
12 -
13 .row
11 .row
14 .col-md-12
12 .col-md-12
15 %h1 Group details
13 %h1 Group details
16 .row
14 .row
17 .col-md-6
15 .col-md-6
18 .panel.panel-default
16 .panel.panel-default
19 .panel-heading
17 .panel-heading
20 .panel-title Users in this group
18 .panel-title Users in this group
21 .panel-body
19 .panel-body
20 + %ul
21 + %li
22 + If you want to add several users to a group, it may be easier to just re-import those users in
23 + = link_to 'New list of users', new_list_user_admin_index_path
24 + page
22 =form_tag add_user_group_path(@group), class: 'form-inline' do
25 =form_tag add_user_group_path(@group), class: 'form-inline' do
23 .form-group
26 .form-group
24 =label_tag :user_id, "User"
27 =label_tag :user_id, "User"
25 =select_tag :user_id, options_from_collection_for_select(User.all,'id','full_name'), class: 'select2'
28 =select_tag :user_id, options_from_collection_for_select(User.all,'id','full_name'), class: 'select2'
26 =submit_tag "Add",class: 'btn btn-primary'
29 =submit_tag "Add",class: 'btn btn-primary'
27
30
28
31
29 %table.table.table-hover
32 %table.table.table-hover
30 %thead
33 %thead
31 %tr
34 %tr
32 %th Login
35 %th Login
33 %th Full name
36 %th Full name
34 %th Remark
37 %th Remark
35 %th= link_to 'Remove All', remove_all_user_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL USERS from group?" }, class: 'btn btn-danger btn-sm'
38 %th= link_to 'Remove All', remove_all_user_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL USERS from group?" }, class: 'btn btn-danger btn-sm'
36
39
37 %tbody
40 %tbody
38 - @group.users.each do |user|
41 - @group.users.each do |user|
39 %tr
42 %tr
40 %td= user.login
43 %td= user.login
41 %td= user.full_name
44 %td= user.full_name
42 %td= user.remark
45 %td= user.remark
43 %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger btn-sm'
46 %td= link_to 'Remove', remove_user_group_path(@group,user), :method => :delete, :data => { :confirm => "Remove #{user.full_name}?" }, class: 'btn btn-danger btn-sm'
44 .col-md-6
47 .col-md-6
45 .panel.panel-default
48 .panel.panel-default
46 .panel-heading
49 .panel-heading
47 .panel-title Problems
50 .panel-title Problems
48 .panel-body
51 .panel-body
49 -
52 + %ul
53 + %li
54 + If you want to add several problem to a group, it may be easier to bulk manage them in the
55 + = link_to 'Bulk Manage', manage_problems_path
56 + page
50 =form_tag add_problem_group_path(@group), class: 'form-inline' do
57 =form_tag add_problem_group_path(@group), class: 'form-inline' do
51 .form-group
58 .form-group
52 =label_tag :problem_id, "Problem"
59 =label_tag :problem_id, "Problem"
53 =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','full_name'), class: 'select2'
60 =select_tag :problem_id, options_from_collection_for_select(Problem.all,'id','full_name'), class: 'select2'
54 =submit_tag "Add",class: 'btn btn-primary'
61 =submit_tag "Add",class: 'btn btn-primary'
55
62
56
63
57 %table.table.table-hover
64 %table.table.table-hover
58 %thead
65 %thead
59 %tr
66 %tr
60 %th name
67 %th name
61 %th Full name
68 %th Full name
62 %th Full score
69 %th Full score
63 %th= link_to 'Remove All', remove_all_problem_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL PROBLEMS from group?" }, class: 'btn btn-danger btn-sm'
70 %th= link_to 'Remove All', remove_all_problem_group_path(@group), method: :delete, :data => { :confirm => "Remove ALL PROBLEMS from group?" }, class: 'btn btn-danger btn-sm'
64
71
65 %tbody
72 %tbody
66 - @group.problems.each do |problem|
73 - @group.problems.each do |problem|
67 %tr
74 %tr
68 %td= problem.name
75 %td= problem.name
69 %td= problem.full_name
76 %td= problem.full_name
70 %td= problem.full_score
77 %td= problem.full_score
71 %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger btn-sm'
78 %td= link_to 'Remove', remove_problem_group_path(@group,problem), :method => :delete, :data => { :confirm => "Remove #{problem.full_name}?" }, class: 'btn btn-danger btn-sm'
72
79
73
80
@@ -1,3 +1,11
1 + .container-fluid
1 %h1 Current Score
2 %h1 Current Score
3 + = form_tag current_score_report_path, method: 'get' do
4 + Show only users from this group
5 + = select_tag "group_id", options_from_collection_for_select( Group.all, 'id','name',params[:group_name]), id: 'group_name',class: 'select2'
6 + = submit_tag 'Apply',class: 'btn btn-default'
7 +
8 + %br
9 +
2
10
3 = render "score_table"
11 = render "score_table"
@@ -1,190 +1,190
1 Rails.application.routes.draw do
1 Rails.application.routes.draw do
2 resources :tags
2 resources :tags
3 get "sources/direct_edit"
3 get "sources/direct_edit"
4
4
5 root :to => 'main#login'
5 root :to => 'main#login'
6
6
7 #logins
7 #logins
8 match 'login/login', to: 'login#login', via: [:get,:post]
8 match 'login/login', to: 'login#login', via: [:get,:post]
9
9
10 resources :contests
10 resources :contests
11 resources :sites
11 resources :sites
12 resources :test
12 resources :test
13
13
14 resources :messages do
14 resources :messages do
15 collection do
15 collection do
16 get 'console'
16 get 'console'
17 end
17 end
18 end
18 end
19
19
20 resources :announcements do
20 resources :announcements do
21 member do
21 member do
22 get 'toggle','toggle_front'
22 get 'toggle','toggle_front'
23 end
23 end
24 end
24 end
25
25
26 resources :problems do
26 resources :problems do
27 member do
27 member do
28 get 'toggle'
28 get 'toggle'
29 get 'toggle_test'
29 get 'toggle_test'
30 get 'toggle_view_testcase'
30 get 'toggle_view_testcase'
31 get 'stat'
31 get 'stat'
32 end
32 end
33 collection do
33 collection do
34 get 'turn_all_off'
34 get 'turn_all_off'
35 get 'turn_all_on'
35 get 'turn_all_on'
36 get 'import'
36 get 'import'
37 get 'manage'
37 get 'manage'
38 get 'quick_create'
38 get 'quick_create'
39 post 'do_manage'
39 post 'do_manage'
40 post 'do_import'
40 post 'do_import'
41 end
41 end
42 end
42 end
43
43
44 resources :groups do
44 resources :groups do
45 member do
45 member do
46 post 'add_user', to: 'groups#add_user', as: 'add_user'
46 post 'add_user', to: 'groups#add_user', as: 'add_user'
47 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
47 delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user'
48 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
48 delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user'
49 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
49 post 'add_problem', to: 'groups#add_problem', as: 'add_problem'
50 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
50 delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem'
51 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
51 delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem'
52 end
52 end
53 collection do
53 collection do
54
54
55 end
55 end
56 end
56 end
57
57
58 resources :testcases, only: [] do
58 resources :testcases, only: [] do
59 member do
59 member do
60 get 'download_input'
60 get 'download_input'
61 get 'download_sol'
61 get 'download_sol'
62 end
62 end
63 collection do
63 collection do
64 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
64 get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
65 end
65 end
66 end
66 end
67
67
68 resources :grader_configuration, controller: 'configurations'
68 resources :grader_configuration, controller: 'configurations'
69
69
70 resources :users do
70 resources :users do
71 member do
71 member do
72 get 'toggle_activate', 'toggle_enable'
72 get 'toggle_activate', 'toggle_enable'
73 get 'stat'
73 get 'stat'
74 end
74 end
75 collection do
75 collection do
76 get 'profile'
76 get 'profile'
77 post 'chg_passwd'
77 post 'chg_passwd'
78 end
78 end
79 end
79 end
80
80
81 resources :submissions do
81 resources :submissions do
82 member do
82 member do
83 get 'download'
83 get 'download'
84 get 'compiler_msg'
84 get 'compiler_msg'
85 get 'rejudge'
85 get 'rejudge'
86 get 'source'
86 get 'source'
87 end
87 end
88 collection do
88 collection do
89 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
89 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
90 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
90 get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
91 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
91 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
92 end
92 end
93 end
93 end
94
94
95
95
96 #user admin
96 #user admin
97 resources :user_admin do
97 resources :user_admin do
98 collection do
98 collection do
99 match 'bulk_manage', via: [:get, :post]
99 match 'bulk_manage', via: [:get, :post]
100 get 'bulk_mail'
100 get 'bulk_mail'
101 get 'user_stat'
101 get 'user_stat'
102 get 'import'
102 get 'import'
103 get 'new_list'
103 get 'new_list'
104 get 'admin'
104 get 'admin'
105 get 'active'
105 get 'active'
106 get 'mass_mailing'
106 get 'mass_mailing'
107 get 'revoke_admin'
107 get 'revoke_admin'
108 post 'grant_admin'
108 post 'grant_admin'
109 match 'create_from_list', via: [:get, :post]
109 match 'create_from_list', via: [:get, :post]
110 match 'random_all_passwords', via: [:get, :post]
110 match 'random_all_passwords', via: [:get, :post]
111 end
111 end
112 member do
112 member do
113 get 'clear_last_ip'
113 get 'clear_last_ip'
114 end
114 end
115 end
115 end
116
116
117 resources :contest_management, only: [:index] do
117 resources :contest_management, only: [:index] do
118 collection do
118 collection do
119 get 'user_stat'
119 get 'user_stat'
120 get 'clear_stat'
120 get 'clear_stat'
121 get 'clear_all_stat'
121 get 'clear_all_stat'
122 get 'change_contest_mode'
122 get 'change_contest_mode'
123 end
123 end
124 end
124 end
125
125
126 #get 'user_admin', to: 'user_admin#index'
126 #get 'user_admin', to: 'user_admin#index'
127 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
127 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
128 #post 'user_admin', to: 'user_admin#create'
128 #post 'user_admin', to: 'user_admin#create'
129 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
129 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
130
130
131 #singular resource
131 #singular resource
132 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
132 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
133 #report
133 #report
134 resource :report, only: [], controller: 'report' do
134 resource :report, only: [], controller: 'report' do
135 get 'login'
135 get 'login'
136 get 'multiple_login'
136 get 'multiple_login'
137 get 'problem_hof/:id', action: 'problem_hof'
137 get 'problem_hof/:id', action: 'problem_hof'
138 - get 'current_score'
138 + get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
139 get 'max_score'
139 get 'max_score'
140 post 'show_max_score'
140 post 'show_max_score'
141 end
141 end
142 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
142 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
143 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
143 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
144 #get "report/login"
144 #get "report/login"
145 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
145 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
146 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
146 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
147
147
148 resource :main, only: [], controller: 'main' do
148 resource :main, only: [], controller: 'main' do
149 get 'login'
149 get 'login'
150 get 'logout'
150 get 'logout'
151 get 'list'
151 get 'list'
152 get 'submission(/:id)', action: 'submission', as: 'main_submission'
152 get 'submission(/:id)', action: 'submission', as: 'main_submission'
153 get 'announcements'
153 get 'announcements'
154 get 'help'
154 get 'help'
155 post 'submit'
155 post 'submit'
156 end
156 end
157 #main
157 #main
158 #get "main/list"
158 #get "main/list"
159 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
159 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
160 #post 'main/submit', to: 'main#submit'
160 #post 'main/submit', to: 'main#submit'
161 #get 'main/announcements', to: 'main#announcements'
161 #get 'main/announcements', to: 'main#announcements'
162
162
163
163
164 #
164 #
165 get 'tasks/view/:file.:ext' => 'tasks#view'
165 get 'tasks/view/:file.:ext' => 'tasks#view'
166 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
166 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
167 get 'heartbeat/:id/edit' => 'heartbeat#edit'
167 get 'heartbeat/:id/edit' => 'heartbeat#edit'
168
168
169 #grader
169 #grader
170 get 'graders/list', to: 'graders#list', as: 'grader_list'
170 get 'graders/list', to: 'graders#list', as: 'grader_list'
171 namespace :graders do
171 namespace :graders do
172 get 'task/:id/:type', action: 'task', as: 'task'
172 get 'task/:id/:type', action: 'task', as: 'task'
173 get 'view/:id/:type', action: 'view', as: 'view'
173 get 'view/:id/:type', action: 'view', as: 'view'
174 get 'clear/:id', action: 'clear', as: 'clear'
174 get 'clear/:id', action: 'clear', as: 'clear'
175 get 'stop'
175 get 'stop'
176 get 'stop_all'
176 get 'stop_all'
177 get 'clear_all'
177 get 'clear_all'
178 get 'clear_terminated'
178 get 'clear_terminated'
179 get 'start_grading'
179 get 'start_grading'
180 get 'start_exam'
180 get 'start_exam'
181
181
182 end
182 end
183
183
184
184
185 # See how all your routes lay out with "rake routes"
185 # See how all your routes lay out with "rake routes"
186
186
187 # This is a legacy wild controller route that's not recommended for RESTful applications.
187 # This is a legacy wild controller route that's not recommended for RESTful applications.
188 # Note: This route will make all actions in every controller accessible via GET requests.
188 # Note: This route will make all actions in every controller accessible via GET requests.
189 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
189 # match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
190 end
190 end
deleted file
You need to be logged in to leave comments. Login now