Description:
finalize multiple_login, change default menu of report to multiple login
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r521:5a22064770a9 - - 7 files changed: 59 inserted, 12 deleted

@@ -70,193 +70,193
70
70
71 def edit
71 def edit
72 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
73 @description = @problem.description
73 @description = @problem.description
74 end
74 end
75
75
76 def update
76 def update
77 @problem = Problem.find(params[:id])
77 @problem = Problem.find(params[:id])
78 @description = @problem.description
78 @description = @problem.description
79 if @description == nil and params[:description][:body]!=''
79 if @description == nil and params[:description][:body]!=''
80 @description = Description.new(params[:description])
80 @description = Description.new(params[:description])
81 if !@description.save
81 if !@description.save
82 flash[:notice] = 'Error saving description'
82 flash[:notice] = 'Error saving description'
83 render :action => 'edit' and return
83 render :action => 'edit' and return
84 end
84 end
85 @problem.description = @description
85 @problem.description = @description
86 elsif @description!=nil
86 elsif @description!=nil
87 if !@description.update_attributes(params[:description])
87 if !@description.update_attributes(params[:description])
88 flash[:notice] = 'Error saving description'
88 flash[:notice] = 'Error saving description'
89 render :action => 'edit' and return
89 render :action => 'edit' and return
90 end
90 end
91 end
91 end
92 if params[:file] and params[:file].content_type != 'application/pdf'
92 if params[:file] and params[:file].content_type != 'application/pdf'
93 flash[:notice] = 'Error: Uploaded file is not PDF'
93 flash[:notice] = 'Error: Uploaded file is not PDF'
94 render :action => 'edit' and return
94 render :action => 'edit' and return
95 end
95 end
96 if @problem.update_attributes(params[:problem])
96 if @problem.update_attributes(params[:problem])
97 flash[:notice] = 'Problem was successfully updated.'
97 flash[:notice] = 'Problem was successfully updated.'
98 unless params[:file] == nil or params[:file] == ''
98 unless params[:file] == nil or params[:file] == ''
99 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
99 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
100 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
100 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
101 if not FileTest.exists? out_dirname
101 if not FileTest.exists? out_dirname
102 Dir.mkdir out_dirname
102 Dir.mkdir out_dirname
103 end
103 end
104
104
105 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
105 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
106 if FileTest.exists? out_filename
106 if FileTest.exists? out_filename
107 File.delete out_filename
107 File.delete out_filename
108 end
108 end
109
109
110 File.open(out_filename,"wb") do |file|
110 File.open(out_filename,"wb") do |file|
111 file.write(params[:file].read)
111 file.write(params[:file].read)
112 end
112 end
113 @problem.description_filename = "#{@problem.name}.pdf"
113 @problem.description_filename = "#{@problem.name}.pdf"
114 @problem.save
114 @problem.save
115 end
115 end
116 redirect_to :action => 'show', :id => @problem
116 redirect_to :action => 'show', :id => @problem
117 else
117 else
118 render :action => 'edit'
118 render :action => 'edit'
119 end
119 end
120 end
120 end
121
121
122 def destroy
122 def destroy
123 Problem.find(params[:id]).destroy
123 Problem.find(params[:id]).destroy
124 redirect_to :action => 'list'
124 redirect_to :action => 'list'
125 end
125 end
126
126
127 def toggle
127 def toggle
128 @problem = Problem.find(params[:id])
128 @problem = Problem.find(params[:id])
129 @problem.available = !(@problem.available)
129 @problem.available = !(@problem.available)
130 @problem.save
130 @problem.save
131 end
131 end
132
132
133 def turn_all_off
133 def turn_all_off
134 Problem.find(:all,
134 Problem.find(:all,
135 :conditions => "available = 1").each do |problem|
135 :conditions => "available = 1").each do |problem|
136 problem.available = false
136 problem.available = false
137 problem.save
137 problem.save
138 end
138 end
139 redirect_to :action => 'list'
139 redirect_to :action => 'list'
140 end
140 end
141
141
142 def turn_all_on
142 def turn_all_on
143 Problem.find(:all,
143 Problem.find(:all,
144 :conditions => "available = 0").each do |problem|
144 :conditions => "available = 0").each do |problem|
145 problem.available = true
145 problem.available = true
146 problem.save
146 problem.save
147 end
147 end
148 redirect_to :action => 'list'
148 redirect_to :action => 'list'
149 end
149 end
150
150
151 def stat
151 def stat
152 @problem = Problem.find(params[:id])
152 @problem = Problem.find(params[:id])
153 unless @problem.available or session[:admin]
153 unless @problem.available or session[:admin]
154 redirect_to :controller => 'main', :action => 'list'
154 redirect_to :controller => 'main', :action => 'list'
155 return
155 return
156 end
156 end
157 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
157 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
158
158
159 #stat summary
159 #stat summary
160 range =65
160 range =65
161 @histogram = { data: Array.new(range,0), summary: {} }
161 @histogram = { data: Array.new(range,0), summary: {} }
162 user = Hash.new(0)
162 user = Hash.new(0)
163 @submissions.find_each do |sub|
163 @submissions.find_each do |sub|
164 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
164 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
165 @histogram[:data][d.to_i] += 1 if d < range
165 @histogram[:data][d.to_i] += 1 if d < range
166 - user[sub.user_id] = [user[sub.user_id], (sub.points >= @problem.full_score) ? 1 : 0].max
166 + user[sub.user_id] = [user[sub.user_id], (sub.try(:points) >= @problem.full_score) ? 1 : 0].max
167 end
167 end
168 @histogram[:summary][:max] = [@histogram[:data].max,1].max
168 @histogram[:summary][:max] = [@histogram[:data].max,1].max
169
169
170 @summary = { attempt: user.count, solve: 0 }
170 @summary = { attempt: user.count, solve: 0 }
171 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
171 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
172 end
172 end
173
173
174 def manage
174 def manage
175 @problems = Problem.find(:all, :order => 'date_added DESC')
175 @problems = Problem.find(:all, :order => 'date_added DESC')
176 end
176 end
177
177
178 def do_manage
178 def do_manage
179 if params.has_key? 'change_date_added'
179 if params.has_key? 'change_date_added'
180 change_date_added
180 change_date_added
181 elsif params.has_key? 'add_to_contest'
181 elsif params.has_key? 'add_to_contest'
182 add_to_contest
182 add_to_contest
183 elsif params.has_key? 'enable_problem'
183 elsif params.has_key? 'enable_problem'
184 set_available(true)
184 set_available(true)
185 elsif params.has_key? 'disable_problem'
185 elsif params.has_key? 'disable_problem'
186 set_available(false)
186 set_available(false)
187 end
187 end
188 redirect_to :action => 'manage'
188 redirect_to :action => 'manage'
189 end
189 end
190
190
191 def import
191 def import
192 @allow_test_pair_import = allow_test_pair_import?
192 @allow_test_pair_import = allow_test_pair_import?
193 end
193 end
194
194
195 def do_import
195 def do_import
196 old_problem = Problem.find_by_name(params[:name])
196 old_problem = Problem.find_by_name(params[:name])
197 if !allow_test_pair_import? and params.has_key? :import_to_db
197 if !allow_test_pair_import? and params.has_key? :import_to_db
198 params.delete :import_to_db
198 params.delete :import_to_db
199 end
199 end
200 @problem, import_log = Problem.create_from_import_form_params(params,
200 @problem, import_log = Problem.create_from_import_form_params(params,
201 old_problem)
201 old_problem)
202
202
203 if !@problem.errors.empty?
203 if !@problem.errors.empty?
204 render :action => 'import' and return
204 render :action => 'import' and return
205 end
205 end
206
206
207 if old_problem!=nil
207 if old_problem!=nil
208 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
208 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
209 end
209 end
210 @log = import_log
210 @log = import_log
211 end
211 end
212
212
213 def remove_contest
213 def remove_contest
214 problem = Problem.find(params[:id])
214 problem = Problem.find(params[:id])
215 contest = Contest.find(params[:contest_id])
215 contest = Contest.find(params[:contest_id])
216 if problem!=nil and contest!=nil
216 if problem!=nil and contest!=nil
217 problem.contests.delete(contest)
217 problem.contests.delete(contest)
218 end
218 end
219 redirect_to :action => 'manage'
219 redirect_to :action => 'manage'
220 end
220 end
221
221
222 ##################################
222 ##################################
223 protected
223 protected
224
224
225 def allow_test_pair_import?
225 def allow_test_pair_import?
226 if defined? ALLOW_TEST_PAIR_IMPORT
226 if defined? ALLOW_TEST_PAIR_IMPORT
227 return ALLOW_TEST_PAIR_IMPORT
227 return ALLOW_TEST_PAIR_IMPORT
228 else
228 else
229 return false
229 return false
230 end
230 end
231 end
231 end
232
232
233 def change_date_added
233 def change_date_added
234 problems = get_problems_from_params
234 problems = get_problems_from_params
235 year = params[:date_added][:year].to_i
235 year = params[:date_added][:year].to_i
236 month = params[:date_added][:month].to_i
236 month = params[:date_added][:month].to_i
237 day = params[:date_added][:day].to_i
237 day = params[:date_added][:day].to_i
238 date = Date.new(year,month,day)
238 date = Date.new(year,month,day)
239 problems.each do |p|
239 problems.each do |p|
240 p.date_added = date
240 p.date_added = date
241 p.save
241 p.save
242 end
242 end
243 end
243 end
244
244
245 def add_to_contest
245 def add_to_contest
246 problems = get_problems_from_params
246 problems = get_problems_from_params
247 contest = Contest.find(params[:contest][:id])
247 contest = Contest.find(params[:contest][:id])
248 if contest!=nil and contest.enabled
248 if contest!=nil and contest.enabled
249 problems.each do |p|
249 problems.each do |p|
250 p.contests << contest
250 p.contests << contest
251 end
251 end
252 end
252 end
253 end
253 end
254
254
255 def set_available(avail)
255 def set_available(avail)
256 problems = get_problems_from_params
256 problems = get_problems_from_params
257 problems.each do |p|
257 problems.each do |p|
258 p.available = avail
258 p.available = avail
259 p.save
259 p.save
260 end
260 end
261 end
261 end
262
262
@@ -123,109 +123,132
123
123
124 lang = Language.find_by_id(sub.language_id)
124 lang = Language.find_by_id(sub.language_id)
125 next unless lang
125 next unless lang
126 next unless sub.points >= @problem.full_score
126 next unless sub.points >= @problem.full_score
127
127
128 #initialize
128 #initialize
129 unless @by_lang.has_key?(lang.pretty_name)
129 unless @by_lang.has_key?(lang.pretty_name)
130 @by_lang[lang.pretty_name] = {
130 @by_lang[lang.pretty_name] = {
131 runtime: { avail: false, value: 2**30-1 },
131 runtime: { avail: false, value: 2**30-1 },
132 memory: { avail: false, value: 2**30-1 },
132 memory: { avail: false, value: 2**30-1 },
133 length: { avail: false, value: 2**30-1 },
133 length: { avail: false, value: 2**30-1 },
134 first: { avail: false, value: DateTime.new(3000,1,1) }
134 first: { avail: false, value: DateTime.new(3000,1,1) }
135 }
135 }
136 end
136 end
137
137
138 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
138 if sub.max_runtime and sub.max_runtime < @by_lang[lang.pretty_name][:runtime][:value]
139 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
139 @by_lang[lang.pretty_name][:runtime] = { avail: true, user_id: sub.user_id, value: sub.max_runtime, sub_id: sub.id }
140 end
140 end
141
141
142 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
142 if sub.peak_memory and sub.peak_memory < @by_lang[lang.pretty_name][:memory][:value]
143 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
143 @by_lang[lang.pretty_name][:memory] = { avail: true, user_id: sub.user_id, value: sub.peak_memory, sub_id: sub.id }
144 end
144 end
145
145
146 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
146 if sub.submitted_at and sub.submitted_at < @by_lang[lang.pretty_name][:first][:value] and
147 !sub.user.admin?
147 !sub.user.admin?
148 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
148 @by_lang[lang.pretty_name][:first] = { avail: true, user_id: sub.user_id, value: sub.submitted_at, sub_id: sub.id }
149 end
149 end
150
150
151 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
151 if @by_lang[lang.pretty_name][:length][:value] > sub.effective_code_length
152 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
152 @by_lang[lang.pretty_name][:length] = { avail: true, user_id: sub.user_id, value: sub.effective_code_length, sub_id: sub.id }
153 end
153 end
154 end
154 end
155
155
156 #process user_id
156 #process user_id
157 @by_lang.each do |lang,prop|
157 @by_lang.each do |lang,prop|
158 prop.each do |k,v|
158 prop.each do |k,v|
159 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
159 v[:user] = User.exists?(v[:user_id]) ? User.find(v[:user_id]).full_name : "(NULL)"
160 end
160 end
161 end
161 end
162
162
163 #sum into best
163 #sum into best
164 if @by_lang and @by_lang.first
164 if @by_lang and @by_lang.first
165 @best = @by_lang.first[1].clone
165 @best = @by_lang.first[1].clone
166 @by_lang.each do |lang,prop|
166 @by_lang.each do |lang,prop|
167 if @best[:runtime][:value] >= prop[:runtime][:value]
167 if @best[:runtime][:value] >= prop[:runtime][:value]
168 @best[:runtime] = prop[:runtime]
168 @best[:runtime] = prop[:runtime]
169 @best[:runtime][:lang] = lang
169 @best[:runtime][:lang] = lang
170 end
170 end
171 if @best[:memory][:value] >= prop[:memory][:value]
171 if @best[:memory][:value] >= prop[:memory][:value]
172 @best[:memory] = prop[:memory]
172 @best[:memory] = prop[:memory]
173 @best[:memory][:lang] = lang
173 @best[:memory][:lang] = lang
174 end
174 end
175 if @best[:length][:value] >= prop[:length][:value]
175 if @best[:length][:value] >= prop[:length][:value]
176 @best[:length] = prop[:length]
176 @best[:length] = prop[:length]
177 @best[:length][:lang] = lang
177 @best[:length][:lang] = lang
178 end
178 end
179 if @best[:first][:value] >= prop[:first][:value]
179 if @best[:first][:value] >= prop[:first][:value]
180 @best[:first] = prop[:first]
180 @best[:first] = prop[:first]
181 @best[:first][:lang] = lang
181 @best[:first][:lang] = lang
182 end
182 end
183 end
183 end
184 end
184 end
185
185
186 @histogram[:summary][:max] = [@histogram[:data].max,1].max
186 @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 @summary[:attempt] = user.count
187 @summary[:attempt] = user.count
188 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
188 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
189 end
189 end
190
190
191 def stuck #report struggling user,problem
191 def stuck #report struggling user,problem
192 # init
192 # init
193 user,problem = nil
193 user,problem = nil
194 solve = true
194 solve = true
195 tries = 0
195 tries = 0
196 @struggle = Array.new
196 @struggle = Array.new
197 record = {}
197 record = {}
198 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
198 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
199 next unless sub.user and sub.problem
199 next unless sub.user and sub.problem
200 if user != sub.user_id or problem != sub.problem_id
200 if user != sub.user_id or problem != sub.problem_id
201 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
201 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
202 record = {user: sub.user, problem: sub.problem}
202 record = {user: sub.user, problem: sub.problem}
203 user,problem = sub.user_id, sub.problem_id
203 user,problem = sub.user_id, sub.problem_id
204 solve = false
204 solve = false
205 tries = 0
205 tries = 0
206 end
206 end
207 if sub.points >= sub.problem.full_score
207 if sub.points >= sub.problem.full_score
208 solve = true
208 solve = true
209 else
209 else
210 tries += 1
210 tries += 1
211 end
211 end
212 end
212 end
213 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
213 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
214 @struggle = @struggle[0..50]
214 @struggle = @struggle[0..50]
215 end
215 end
216
216
217
217
218 def multiple_login
218 def multiple_login
219 + #user with multiple IP
219 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
220 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
220 last,count = 0,0
221 last,count = 0,0
221 - @multiple = []
222 + first = 0
223 + @users = []
222 raw.each do |r|
224 raw.each do |r|
223 if last != r.user.login
225 if last != r.user.login
224 count = 1
226 count = 1
227 + last = r.user.login
228 + first = r
225 else
229 else
226 - @multiple << r
230 + @users << first if count == 1
231 + @users << r
232 + count += 1
233 + end
234 + end
235 +
236 + #IP with multiple user
237 + raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:ip_address)
238 + last,count = 0,0
239 + first = 0
240 + @ip = []
241 + raw.each do |r|
242 + if last != r.ip_address
243 + count = 1
244 + last = r.ip_address
245 + first = r
246 + else
247 + @ip << first if count == 1
248 + @ip << r
249 + count += 1
227 end
250 end
228 end
251 end
229 end
252 end
230
253
231 end
254 end
@@ -1,187 +1,192
1 require 'csv'
1 require 'csv'
2
2
3 class UserAdminController < ApplicationController
3 class UserAdminController < ApplicationController
4
4
5
5
6 include MailHelperMethods
6 include MailHelperMethods
7
7
8 before_filter :admin_authorization
8 before_filter :admin_authorization
9
9
10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
10 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
11 verify :method => :post, :only => [ :destroy,
11 verify :method => :post, :only => [ :destroy,
12 :create, :create_from_list,
12 :create, :create_from_list,
13 :update,
13 :update,
14 :manage_contest,
14 :manage_contest,
15 :bulk_mail
15 :bulk_mail
16 ],
16 ],
17 :redirect_to => { :action => :list }
17 :redirect_to => { :action => :list }
18
18
19 def index
19 def index
20 list
20 list
21 render :action => 'list'
21 render :action => 'list'
22 end
22 end
23
23
24 def list
24 def list
25 @user_count = User.count
25 @user_count = User.count
26 if params[:page] == 'all'
26 if params[:page] == 'all'
27 @users = User.all
27 @users = User.all
28 @paginated = false
28 @paginated = false
29 else
29 else
30 @users = User.paginate :page => params[:page]
30 @users = User.paginate :page => params[:page]
31 @paginated = true
31 @paginated = true
32 end
32 end
33 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
33 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
34 @contests = Contest.enabled
34 @contests = Contest.enabled
35 end
35 end
36
36
37 def active
37 def active
38 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
38 sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
39 @users = []
39 @users = []
40 sessions.each do |session|
40 sessions.each do |session|
41 if session.data[:user_id]
41 if session.data[:user_id]
42 @users << User.find(session.data[:user_id])
42 @users << User.find(session.data[:user_id])
43 end
43 end
44 end
44 end
45 end
45 end
46
46
47 def show
47 def show
48 @user = User.find(params[:id])
48 @user = User.find(params[:id])
49 end
49 end
50
50
51 def new
51 def new
52 @user = User.new
52 @user = User.new
53 end
53 end
54
54
55 def create
55 def create
56 @user = User.new(params[:user])
56 @user = User.new(params[:user])
57 @user.activated = true
57 @user.activated = true
58 if @user.save
58 if @user.save
59 flash[:notice] = 'User was successfully created.'
59 flash[:notice] = 'User was successfully created.'
60 redirect_to :action => 'list'
60 redirect_to :action => 'list'
61 else
61 else
62 render :action => 'new'
62 render :action => 'new'
63 end
63 end
64 end
64 end
65
65
66 def create_from_list
66 def create_from_list
67 lines = params[:user_list]
67 lines = params[:user_list]
68
68
69 note = []
69 note = []
70
70
71 lines.split("\n").each do |line|
71 lines.split("\n").each do |line|
72 items = line.chomp.split(',')
72 items = line.chomp.split(',')
73 if items.length>=2
73 if items.length>=2
74 login = items[0]
74 login = items[0]
75 full_name = items[1]
75 full_name = items[1]
76
76
77 added_random_password = false
77 added_random_password = false
78 if items.length>=3
78 if items.length>=3
79 password = items[2].chomp(" ")
79 password = items[2].chomp(" ")
80 user_alias = (items.length>=4) ? items[3] : login
80 user_alias = (items.length>=4) ? items[3] : login
81 else
81 else
82 password = random_password
82 password = random_password
83 user_alias = (items.length>=4) ? items[3] : login
83 user_alias = (items.length>=4) ? items[3] : login
84 added_random_password = true
84 added_random_password = true
85 end
85 end
86
86
87 + user = User.find_by_login(login)
88 + if user
89 + user.password = password
90 + else
87 user = User.new({:login => login,
91 user = User.new({:login => login,
88 :full_name => full_name,
92 :full_name => full_name,
89 :password => password,
93 :password => password,
90 :password_confirmation => password,
94 :password_confirmation => password,
91 :alias => user_alias})
95 :alias => user_alias})
96 + end
92 user.activated = true
97 user.activated = true
93 user.save
98 user.save
94
99
95 if added_random_password
100 if added_random_password
96 note << "'#{login}' (+)"
101 note << "'#{login}' (+)"
97 else
102 else
98 note << login
103 note << login
99 end
104 end
100 end
105 end
101 end
106 end
102 flash[:notice] = 'User(s) ' + note.join(', ') +
107 flash[:notice] = 'User(s) ' + note.join(', ') +
103 ' were successfully created. ' +
108 ' were successfully created. ' +
104 '( (+) - created with random passwords.)'
109 '( (+) - created with random passwords.)'
105 redirect_to :action => 'list'
110 redirect_to :action => 'list'
106 end
111 end
107
112
108 def edit
113 def edit
109 @user = User.find(params[:id])
114 @user = User.find(params[:id])
110 end
115 end
111
116
112 def update
117 def update
113 @user = User.find(params[:id])
118 @user = User.find(params[:id])
114 if @user.update_attributes(params[:user])
119 if @user.update_attributes(params[:user])
115 flash[:notice] = 'User was successfully updated.'
120 flash[:notice] = 'User was successfully updated.'
116 redirect_to :action => 'show', :id => @user
121 redirect_to :action => 'show', :id => @user
117 else
122 else
118 render :action => 'edit'
123 render :action => 'edit'
119 end
124 end
120 end
125 end
121
126
122 def destroy
127 def destroy
123 User.find(params[:id]).destroy
128 User.find(params[:id]).destroy
124 redirect_to :action => 'list'
129 redirect_to :action => 'list'
125 end
130 end
126
131
127 def user_stat
132 def user_stat
128 if params[:commit] == 'download csv'
133 if params[:commit] == 'download csv'
129 @problems = Problem.all
134 @problems = Problem.all
130 else
135 else
131 @problems = Problem.find_available_problems
136 @problems = Problem.find_available_problems
132 end
137 end
133 @users = User.find(:all, :include => [:contests, :contest_stat])
138 @users = User.find(:all, :include => [:contests, :contest_stat])
134 @scorearray = Array.new
139 @scorearray = Array.new
135 @users.each do |u|
140 @users.each do |u|
136 ustat = Array.new
141 ustat = Array.new
137 ustat[0] = u
142 ustat[0] = u
138 @problems.each do |p|
143 @problems.each do |p|
139 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
140 if (sub!=nil) and (sub.points!=nil)
145 if (sub!=nil) and (sub.points!=nil)
141 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
146 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
142 else
147 else
143 ustat << [0,false]
148 ustat << [0,false]
144 end
149 end
145 end
150 end
146 @scorearray << ustat
151 @scorearray << ustat
147 end
152 end
148
153
149 if params[:commit] == 'download csv' then
154 if params[:commit] == 'download csv' then
150 csv = gen_csv_from_scorearray(@scorearray,@problems)
155 csv = gen_csv_from_scorearray(@scorearray,@problems)
151 send_data csv, filename: 'last_score.csv'
156 send_data csv, filename: 'last_score.csv'
152 else
157 else
153 render template: 'user_admin/user_stat'
158 render template: 'user_admin/user_stat'
154 end
159 end
155 end
160 end
156
161
157 def user_stat_max
162 def user_stat_max
158 if params[:commit] == 'download csv'
163 if params[:commit] == 'download csv'
159 @problems = Problem.all
164 @problems = Problem.all
160 else
165 else
161 @problems = Problem.find_available_problems
166 @problems = Problem.find_available_problems
162 end
167 end
163 @users = User.find(:all, :include => [:contests, :contest_stat])
168 @users = User.find(:all, :include => [:contests, :contest_stat])
164 @scorearray = Array.new
169 @scorearray = Array.new
165 #set up range from param
170 #set up range from param
166 since_id = params.fetch(:since_id, 0).to_i
171 since_id = params.fetch(:since_id, 0).to_i
167 until_id = params.fetch(:until_id, 0).to_i
172 until_id = params.fetch(:until_id, 0).to_i
168 @users.each do |u|
173 @users.each do |u|
169 ustat = Array.new
174 ustat = Array.new
170 ustat[0] = u
175 ustat[0] = u
171 @problems.each do |p|
176 @problems.each do |p|
172 max_points = 0
177 max_points = 0
173 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
178 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
174 max_points = sub.points if sub and sub.points and (sub.points > max_points)
179 max_points = sub.points if sub and sub.points and (sub.points > max_points)
175 end
180 end
176 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
181 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
177 end
182 end
178 @scorearray << ustat
183 @scorearray << ustat
179 end
184 end
180
185
181 if params[:commit] == 'download csv' then
186 if params[:commit] == 'download csv' then
182 csv = gen_csv_from_scorearray(@scorearray,@problems)
187 csv = gen_csv_from_scorearray(@scorearray,@problems)
183 send_data csv, filename: 'max_score.csv'
188 send_data csv, filename: 'max_score.csv'
184 else
189 else
185 render template: 'user_admin/user_stat'
190 render template: 'user_admin/user_stat'
186 end
191 end
187 end
192 end
@@ -1,112 +1,112
1 # Methods added to this helper will be available to all templates in the application.
1 # Methods added to this helper will be available to all templates in the application.
2 module ApplicationHelper
2 module ApplicationHelper
3
3
4 def user_header
4 def user_header
5 menu_items = ''
5 menu_items = ''
6 user = User.find(session[:user_id])
6 user = User.find(session[:user_id])
7
7
8 if (user!=nil) and (session[:admin])
8 if (user!=nil) and (session[:admin])
9 # admin menu
9 # admin menu
10 menu_items << "<b>Administrative task:</b> "
10 menu_items << "<b>Administrative task:</b> "
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
11 append_to menu_items, '[Announcements]', 'announcements', 'index'
12 append_to menu_items, '[Msg console]', 'messages', 'console'
12 append_to menu_items, '[Msg console]', 'messages', 'console'
13 append_to menu_items, '[Problems]', 'problems', 'index'
13 append_to menu_items, '[Problems]', 'problems', 'index'
14 append_to menu_items, '[Users]', 'user_admin', 'index'
14 append_to menu_items, '[Users]', 'user_admin', 'index'
15 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
15 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
16 - append_to menu_items, '[Report]', 'report', 'login_stat'
16 + append_to menu_items, '[Report]', 'report', 'multiple_login'
17 append_to menu_items, '[Graders]', 'graders', 'list'
17 append_to menu_items, '[Graders]', 'graders', 'list'
18 append_to menu_items, '[Contests]', 'contest_management', 'index'
18 append_to menu_items, '[Contests]', 'contest_management', 'index'
19 append_to menu_items, '[Sites]', 'sites', 'index'
19 append_to menu_items, '[Sites]', 'sites', 'index'
20 append_to menu_items, '[System config]', 'configurations', 'index'
20 append_to menu_items, '[System config]', 'configurations', 'index'
21 menu_items << "<br/>"
21 menu_items << "<br/>"
22 end
22 end
23
23
24 # main page
24 # main page
25 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
25 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
26 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
26 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
27
27
28 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
28 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
29 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
29 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
30 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
30 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
31 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
31 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
32 end
32 end
33
33
34 if GraderConfiguration['right.user_hall_of_fame']
34 if GraderConfiguration['right.user_hall_of_fame']
35 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
35 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
36 end
36 end
37 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
37 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
38
38
39 if GraderConfiguration['system.user_setting_enabled']
39 if GraderConfiguration['system.user_setting_enabled']
40 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
40 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
41 end
41 end
42 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
42 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
43
43
44 menu_items.html_safe
44 menu_items.html_safe
45 end
45 end
46
46
47 def append_to(option,label, controller, action)
47 def append_to(option,label, controller, action)
48 option << ' ' if option!=''
48 option << ' ' if option!=''
49 option << link_to_unless_current(label,
49 option << link_to_unless_current(label,
50 :controller => controller,
50 :controller => controller,
51 :action => action)
51 :action => action)
52 end
52 end
53
53
54 def format_short_time(time)
54 def format_short_time(time)
55 now = Time.now.gmtime
55 now = Time.now.gmtime
56 st = ''
56 st = ''
57 if (time.yday != now.yday) or
57 if (time.yday != now.yday) or
58 (time.year != now.year)
58 (time.year != now.year)
59 st = time.strftime("%x ")
59 st = time.strftime("%x ")
60 end
60 end
61 st + time.strftime("%X")
61 st + time.strftime("%X")
62 end
62 end
63
63
64 def format_short_duration(duration)
64 def format_short_duration(duration)
65 return '' if duration==nil
65 return '' if duration==nil
66 d = duration.to_f
66 d = duration.to_f
67 return Time.at(d).gmtime.strftime("%X")
67 return Time.at(d).gmtime.strftime("%X")
68 end
68 end
69
69
70 def read_textfile(fname,max_size=2048)
70 def read_textfile(fname,max_size=2048)
71 begin
71 begin
72 File.open(fname).read(max_size)
72 File.open(fname).read(max_size)
73 rescue
73 rescue
74 nil
74 nil
75 end
75 end
76 end
76 end
77
77
78 def user_title_bar(user)
78 def user_title_bar(user)
79 header = ''
79 header = ''
80 time_left = ''
80 time_left = ''
81
81
82 #
82 #
83 # if the contest is over
83 # if the contest is over
84 if GraderConfiguration.time_limit_mode?
84 if GraderConfiguration.time_limit_mode?
85 if user.contest_finished?
85 if user.contest_finished?
86 header = <<CONTEST_OVER
86 header = <<CONTEST_OVER
87 <tr><td colspan="2" align="center">
87 <tr><td colspan="2" align="center">
88 <span class="contest-over-msg">THE CONTEST IS OVER</span>
88 <span class="contest-over-msg">THE CONTEST IS OVER</span>
89 </td></tr>
89 </td></tr>
90 CONTEST_OVER
90 CONTEST_OVER
91 end
91 end
92 if !user.contest_started?
92 if !user.contest_started?
93 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
93 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
94 else
94 else
95 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
95 time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
96 " #{format_short_duration(user.contest_time_left)}"
96 " #{format_short_duration(user.contest_time_left)}"
97 end
97 end
98 end
98 end
99
99
100 #
100 #
101 # if the contest is in the anaysis mode
101 # if the contest is in the anaysis mode
102 if GraderConfiguration.analysis_mode?
102 if GraderConfiguration.analysis_mode?
103 header = <<ANALYSISMODE
103 header = <<ANALYSISMODE
104 <tr><td colspan="2" align="center">
104 <tr><td colspan="2" align="center">
105 <span class="contest-over-msg">ANALYSIS MODE</span>
105 <span class="contest-over-msg">ANALYSIS MODE</span>
106 </td></tr>
106 </td></tr>
107 ANALYSISMODE
107 ANALYSISMODE
108 end
108 end
109
109
110 contest_name = GraderConfiguration['contest.name']
110 contest_name = GraderConfiguration['contest.name']
111
111
112 #
112 #
@@ -1,170 +1,170
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_many :test_requests, :order => "submitted_at DESC"
11 has_many :test_requests, :order => "submitted_at DESC"
12
12
13 has_many :messages,
13 has_many :messages,
14 :class_name => "Message",
14 :class_name => "Message",
15 :foreign_key => "sender_id",
15 :foreign_key => "sender_id",
16 :order => 'created_at DESC'
16 :order => 'created_at DESC'
17
17
18 has_many :replied_messages,
18 has_many :replied_messages,
19 :class_name => "Message",
19 :class_name => "Message",
20 :foreign_key => "receiver_id",
20 :foreign_key => "receiver_id",
21 :order => 'created_at DESC'
21 :order => 'created_at DESC'
22
22
23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24
24
25 belongs_to :site
25 belongs_to :site
26 belongs_to :country
26 belongs_to :country
27
27
28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
29
29
30 scope :activated_users, :conditions => {:activated => true}
30 scope :activated_users, :conditions => {:activated => true}
31
31
32 validates_presence_of :login
32 validates_presence_of :login
33 validates_uniqueness_of :login
33 validates_uniqueness_of :login
34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
35 validates_length_of :login, :within => 3..30
35 validates_length_of :login, :within => 3..30
36
36
37 validates_presence_of :full_name
37 validates_presence_of :full_name
38 validates_length_of :full_name, :minimum => 1
38 validates_length_of :full_name, :minimum => 1
39
39
40 validates_presence_of :password, :if => :password_required?
40 validates_presence_of :password, :if => :password_required?
41 validates_length_of :password, :within => 4..20, :if => :password_required?
41 validates_length_of :password, :within => 4..20, :if => :password_required?
42 validates_confirmation_of :password, :if => :password_required?
42 validates_confirmation_of :password, :if => :password_required?
43
43
44 validates_format_of :email,
44 validates_format_of :email,
45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 :if => :email_validation?
46 :if => :email_validation?
47 validate :uniqueness_of_email_from_activated_users,
47 validate :uniqueness_of_email_from_activated_users,
48 :if => :email_validation?
48 :if => :email_validation?
49 validate :enough_time_interval_between_same_email_registrations,
49 validate :enough_time_interval_between_same_email_registrations,
50 :if => :email_validation?
50 :if => :email_validation?
51
51
52 # these are for ytopc
52 # these are for ytopc
53 # disable for now
53 # disable for now
54 #validates_presence_of :province
54 #validates_presence_of :province
55
55
56 attr_accessor :password
56 attr_accessor :password
57
57
58 before_save :encrypt_new_password
58 before_save :encrypt_new_password
59 before_save :assign_default_site
59 before_save :assign_default_site
60 before_save :assign_default_contest
60 before_save :assign_default_contest
61
61
62 # this is for will_paginate
62 # this is for will_paginate
63 cattr_reader :per_page
63 cattr_reader :per_page
64 @@per_page = 50
64 @@per_page = 50
65
65
66 def self.authenticate(login, password)
66 def self.authenticate(login, password)
67 user = find_by_login(login)
67 user = find_by_login(login)
68 if user
68 if user
69 return user if user.authenticated?(password)
69 return user if user.authenticated?(password)
70 - if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
70 + # if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 - user.password = password
71 + # user.password = password
72 - user.save
72 + # user.save
73 - return user
73 + # return user
74 - end
74 + # end
75 end
75 end
76 end
76 end
77
77
78 def authenticated?(password)
78 def authenticated?(password)
79 if self.activated
79 if self.activated
80 hashed_password == User.encrypt(password,self.salt)
80 hashed_password == User.encrypt(password,self.salt)
81 else
81 else
82 false
82 false
83 end
83 end
84 end
84 end
85
85
86 def authenticated_by_pop3?(password)
86 def authenticated_by_pop3?(password)
87 Net::POP3.enable_ssl
87 Net::POP3.enable_ssl
88 pop = Net::POP3.new('pops.it.chula.ac.th')
88 pop = Net::POP3.new('pops.it.chula.ac.th')
89 authen = true
89 authen = true
90 begin
90 begin
91 pop.start(login, password)
91 pop.start(login, password)
92 pop.finish
92 pop.finish
93 return true
93 return true
94 rescue
94 rescue
95 return false
95 return false
96 end
96 end
97 end
97 end
98
98
99 def authenticated_by_cucas?(password)
99 def authenticated_by_cucas?(password)
100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
103 post_args = {
103 post_args = {
104 'appid' => appid,
104 'appid' => appid,
105 'appsecret' => appsecret,
105 'appsecret' => appsecret,
106 'username' => login,
106 'username' => login,
107 'password' => password
107 'password' => password
108 }
108 }
109
109
110 #simple call
110 #simple call
111 begin
111 begin
112 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
112 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
113 http.use_ssl = true
113 http.use_ssl = true
114 result = [ ]
114 result = [ ]
115 http.start do |http|
115 http.start do |http|
116 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
116 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
117 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
117 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
118 resp = http.request(req,param)
118 resp = http.request(req,param)
119 result = JSON.parse resp.body
119 result = JSON.parse resp.body
120 end
120 end
121 return true if result["type"] == "beanStudent"
121 return true if result["type"] == "beanStudent"
122 rescue
122 rescue
123 return false
123 return false
124 end
124 end
125 return false
125 return false
126 end
126 end
127
127
128 def admin?
128 def admin?
129 self.roles.detect {|r| r.name == 'admin' }
129 self.roles.detect {|r| r.name == 'admin' }
130 end
130 end
131
131
132 def email_for_editing
132 def email_for_editing
133 if self.email==nil
133 if self.email==nil
134 "(unknown)"
134 "(unknown)"
135 elsif self.email==''
135 elsif self.email==''
136 "(blank)"
136 "(blank)"
137 else
137 else
138 self.email
138 self.email
139 end
139 end
140 end
140 end
141
141
142 def email_for_editing=(e)
142 def email_for_editing=(e)
143 self.email=e
143 self.email=e
144 end
144 end
145
145
146 def alias_for_editing
146 def alias_for_editing
147 if self.alias==nil
147 if self.alias==nil
148 "(unknown)"
148 "(unknown)"
149 elsif self.alias==''
149 elsif self.alias==''
150 "(blank)"
150 "(blank)"
151 else
151 else
152 self.alias
152 self.alias
153 end
153 end
154 end
154 end
155
155
156 def alias_for_editing=(e)
156 def alias_for_editing=(e)
157 self.alias=e
157 self.alias=e
158 end
158 end
159
159
160 def activation_key
160 def activation_key
161 if self.hashed_password==nil
161 if self.hashed_password==nil
162 encrypt_new_password
162 encrypt_new_password
163 end
163 end
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
164 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
165 end
165 end
166
166
167 def verify_activation_key(key)
167 def verify_activation_key(key)
168 key == activation_key
168 key == activation_key
169 end
169 end
170
170
@@ -1,51 +1,53
1 :css
1 :css
2 .fix-width {
2 .fix-width {
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 }
4 }
5
5
6 %h1 Problem stat: #{@problem.name}
6 %h1 Problem stat: #{@problem.name}
7 %h2 Overview
7 %h2 Overview
8
8
9
9
10 %table.info
10 %table.info
11 %thead
11 %thead
12 %tr.info-head
12 %tr.info-head
13 %th Stat
13 %th Stat
14 %th Value
14 %th Value
15 %tbody
15 %tbody
16 %tr{class: cycle('info-even','info-odd')}
16 %tr{class: cycle('info-even','info-odd')}
17 %td Submissions
17 %td Submissions
18 %td= @submissions.count
18 %td= @submissions.count
19 %tr{class: cycle('info-even','info-odd')}
19 %tr{class: cycle('info-even','info-odd')}
20 %td Solved/Attempted User
20 %td Solved/Attempted User
21 %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
21 %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22
22
23 %h2 Submissions Count
23 %h2 Submissions Count
24 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
24 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25
25
26 %h2 Submissions
26 %h2 Submissions
27 - if @submissions and @submissions.count > 0
27 - if @submissions and @submissions.count > 0
28 %table.info#main_table
28 %table.info#main_table
29 %thead
29 %thead
30 %tr.info-head
30 %tr.info-head
31 %th ID
31 %th ID
32 %th Login
32 %th Login
33 %th Name
33 %th Name
34 %th Submitted_at
34 %th Submitted_at
35 %th Points
35 %th Points
36 %th comment
36 %th comment
37 + %th IP
37 %tbody
38 %tbody
38 - row_odd,curr = true,''
39 - row_odd,curr = true,''
39 - @submissions.each do |sub|
40 - @submissions.each do |sub|
40 - next unless sub.user
41 - next unless sub.user
41 - row_odd,curr = !row_odd, sub.user if curr != sub.user
42 - row_odd,curr = !row_odd, sub.user if curr != sub.user
42 %tr{class: row_odd ? "info-odd" : "info-even"}
43 %tr{class: row_odd ? "info-odd" : "info-even"}
43 %td= link_to sub.id, controller: 'graders', action: 'submission', id: sub.id
44 %td= link_to sub.id, controller: 'graders', action: 'submission', id: sub.id
44 %td= link_to sub.user.login, controller: :users, action: :profile, id: sub.user.id
45 %td= link_to sub.user.login, controller: :users, action: :profile, id: sub.user.id
45 %td= sub.user.full_name
46 %td= sub.user.full_name
46 %td= time_ago_in_words(sub.submitted_at) + " ago"
47 %td= time_ago_in_words(sub.submitted_at) + " ago"
47 %td= sub.points
48 %td= sub.points
48 %td.fix-width= sub.grader_comment
49 %td.fix-width= sub.grader_comment
50 + %td= sub.ip_address
49 - else
51 - else
50 No submission
52 No submission
51
53
@@ -1,20 +1,37
1 - content_for :header do
1 - content_for :header do
2 = stylesheet_link_tag 'tablesorter-theme.cafe'
2 = stylesheet_link_tag 'tablesorter-theme.cafe'
3 = javascript_include_tag 'local_jquery'
3 = javascript_include_tag 'local_jquery'
4
4
5 %h1 Login status
5 %h1 Login status
6
6
7 =render partial: 'report_menu'
7 =render partial: 'report_menu'
8
8
9 + Checking for all submissions with the currently available problem
10 +
11 + %h2 Users with Multiple IP
9 %table.tablesorter-cafe#my_table
12 %table.tablesorter-cafe#my_table
10 %thead
13 %thead
11 %tr
14 %tr
12 %th login
15 %th login
13 %th full name
16 %th full name
14 %th IP
17 %th IP
15 %tbody
18 %tbody
16 - - @multiple.each do |l|
19 + - @users.each do |l|
17 %tr{class: cycle('info-even','info-odd')}
20 %tr{class: cycle('info-even','info-odd')}
18 - %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
21 + %td= link_to l.user.login, controller: 'users', action: 'profile', id: l[:id]
19 - %td= l[:full_name]
22 + %td= l.user.full_name
20 %td= l[:ip_address]
23 %td= l[:ip_address]
24 +
25 + %h2 IP with multiple users
26 + %table.tablesorter-cafe#my_table
27 + %thead
28 + %tr
29 + %th IP
30 + %th login
31 + %th full name
32 + %tbody
33 + - @ip.each do |l|
34 + %tr{class: cycle('info-even','info-odd')}
35 + %td= l[:ip_address]
36 + %td= link_to l.user.login, controller: 'users', action: 'profile', id: l[:id]
37 + %td= l.user.full_name
You need to be logged in to leave comments. Login now