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: 64 inserted, 17 deleted

@@ -118,97 +118,97
118 118 render :action => 'edit'
119 119 end
120 120 end
121 121
122 122 def destroy
123 123 Problem.find(params[:id]).destroy
124 124 redirect_to :action => 'list'
125 125 end
126 126
127 127 def toggle
128 128 @problem = Problem.find(params[:id])
129 129 @problem.available = !(@problem.available)
130 130 @problem.save
131 131 end
132 132
133 133 def turn_all_off
134 134 Problem.find(:all,
135 135 :conditions => "available = 1").each do |problem|
136 136 problem.available = false
137 137 problem.save
138 138 end
139 139 redirect_to :action => 'list'
140 140 end
141 141
142 142 def turn_all_on
143 143 Problem.find(:all,
144 144 :conditions => "available = 0").each do |problem|
145 145 problem.available = true
146 146 problem.save
147 147 end
148 148 redirect_to :action => 'list'
149 149 end
150 150
151 151 def stat
152 152 @problem = Problem.find(params[:id])
153 153 unless @problem.available or session[:admin]
154 154 redirect_to :controller => 'main', :action => 'list'
155 155 return
156 156 end
157 157 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
158 158
159 159 #stat summary
160 160 range =65
161 161 @histogram = { data: Array.new(range,0), summary: {} }
162 162 user = Hash.new(0)
163 163 @submissions.find_each do |sub|
164 164 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
165 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 167 end
168 168 @histogram[:summary][:max] = [@histogram[:data].max,1].max
169 169
170 170 @summary = { attempt: user.count, solve: 0 }
171 171 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
172 172 end
173 173
174 174 def manage
175 175 @problems = Problem.find(:all, :order => 'date_added DESC')
176 176 end
177 177
178 178 def do_manage
179 179 if params.has_key? 'change_date_added'
180 180 change_date_added
181 181 elsif params.has_key? 'add_to_contest'
182 182 add_to_contest
183 183 elsif params.has_key? 'enable_problem'
184 184 set_available(true)
185 185 elsif params.has_key? 'disable_problem'
186 186 set_available(false)
187 187 end
188 188 redirect_to :action => 'manage'
189 189 end
190 190
191 191 def import
192 192 @allow_test_pair_import = allow_test_pair_import?
193 193 end
194 194
195 195 def do_import
196 196 old_problem = Problem.find_by_name(params[:name])
197 197 if !allow_test_pair_import? and params.has_key? :import_to_db
198 198 params.delete :import_to_db
199 199 end
200 200 @problem, import_log = Problem.create_from_import_form_params(params,
201 201 old_problem)
202 202
203 203 if !@problem.errors.empty?
204 204 render :action => 'import' and return
205 205 end
206 206
207 207 if old_problem!=nil
208 208 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
209 209 end
210 210 @log = import_log
211 211 end
212 212
213 213 def remove_contest
214 214 problem = Problem.find(params[:id])
@@ -171,61 +171,84
171 171 if @best[:memory][:value] >= prop[:memory][:value]
172 172 @best[:memory] = prop[:memory]
173 173 @best[:memory][:lang] = lang
174 174 end
175 175 if @best[:length][:value] >= prop[:length][:value]
176 176 @best[:length] = prop[:length]
177 177 @best[:length][:lang] = lang
178 178 end
179 179 if @best[:first][:value] >= prop[:first][:value]
180 180 @best[:first] = prop[:first]
181 181 @best[:first][:lang] = lang
182 182 end
183 183 end
184 184 end
185 185
186 186 @histogram[:summary][:max] = [@histogram[:data].max,1].max
187 187 @summary[:attempt] = user.count
188 188 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
189 189 end
190 190
191 191 def stuck #report struggling user,problem
192 192 # init
193 193 user,problem = nil
194 194 solve = true
195 195 tries = 0
196 196 @struggle = Array.new
197 197 record = {}
198 198 Submission.includes(:problem,:user).order(:problem_id,:user_id).find_each do |sub|
199 199 next unless sub.user and sub.problem
200 200 if user != sub.user_id or problem != sub.problem_id
201 201 @struggle << { user: record[:user], problem: record[:problem], tries: tries } unless solve
202 202 record = {user: sub.user, problem: sub.problem}
203 203 user,problem = sub.user_id, sub.problem_id
204 204 solve = false
205 205 tries = 0
206 206 end
207 207 if sub.points >= sub.problem.full_score
208 208 solve = true
209 209 else
210 210 tries += 1
211 211 end
212 212 end
213 213 @struggle.sort!{|a,b| b[:tries] <=> a[:tries] }
214 214 @struggle = @struggle[0..50]
215 215 end
216 216
217 217
218 218 def multiple_login
219 + #user with multiple IP
219 220 raw = Submission.joins(:user).joins(:problem).where("problems.available != 0").group("login,ip_address").order(:login)
220 221 last,count = 0,0
221 - @multiple = []
222 + first = 0
223 + @users = []
222 224 raw.each do |r|
223 225 if last != r.user.login
224 226 count = 1
227 + last = r.user.login
228 + first = r
225 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 250 end
228 251 end
229 252 end
230 253
231 254 end
@@ -39,101 +39,106
39 39 @users = []
40 40 sessions.each do |session|
41 41 if session.data[:user_id]
42 42 @users << User.find(session.data[:user_id])
43 43 end
44 44 end
45 45 end
46 46
47 47 def show
48 48 @user = User.find(params[:id])
49 49 end
50 50
51 51 def new
52 52 @user = User.new
53 53 end
54 54
55 55 def create
56 56 @user = User.new(params[:user])
57 57 @user.activated = true
58 58 if @user.save
59 59 flash[:notice] = 'User was successfully created.'
60 60 redirect_to :action => 'list'
61 61 else
62 62 render :action => 'new'
63 63 end
64 64 end
65 65
66 66 def create_from_list
67 67 lines = params[:user_list]
68 68
69 69 note = []
70 70
71 71 lines.split("\n").each do |line|
72 72 items = line.chomp.split(',')
73 73 if items.length>=2
74 74 login = items[0]
75 75 full_name = items[1]
76 76
77 77 added_random_password = false
78 78 if items.length>=3
79 79 password = items[2].chomp(" ")
80 80 user_alias = (items.length>=4) ? items[3] : login
81 81 else
82 82 password = random_password
83 83 user_alias = (items.length>=4) ? items[3] : login
84 84 added_random_password = true
85 85 end
86 86
87 - user = User.new({:login => login,
88 - :full_name => full_name,
89 - :password => password,
90 - :password_confirmation => password,
91 - :alias => user_alias})
87 + user = User.find_by_login(login)
88 + if user
89 + user.password = password
90 + else
91 + user = User.new({:login => login,
92 + :full_name => full_name,
93 + :password => password,
94 + :password_confirmation => password,
95 + :alias => user_alias})
96 + end
92 97 user.activated = true
93 98 user.save
94 99
95 100 if added_random_password
96 101 note << "'#{login}' (+)"
97 102 else
98 103 note << login
99 104 end
100 105 end
101 106 end
102 107 flash[:notice] = 'User(s) ' + note.join(', ') +
103 108 ' were successfully created. ' +
104 109 '( (+) - created with random passwords.)'
105 110 redirect_to :action => 'list'
106 111 end
107 112
108 113 def edit
109 114 @user = User.find(params[:id])
110 115 end
111 116
112 117 def update
113 118 @user = User.find(params[:id])
114 119 if @user.update_attributes(params[:user])
115 120 flash[:notice] = 'User was successfully updated.'
116 121 redirect_to :action => 'show', :id => @user
117 122 else
118 123 render :action => 'edit'
119 124 end
120 125 end
121 126
122 127 def destroy
123 128 User.find(params[:id]).destroy
124 129 redirect_to :action => 'list'
125 130 end
126 131
127 132 def user_stat
128 133 if params[:commit] == 'download csv'
129 134 @problems = Problem.all
130 135 else
131 136 @problems = Problem.find_available_problems
132 137 end
133 138 @users = User.find(:all, :include => [:contests, :contest_stat])
134 139 @scorearray = Array.new
135 140 @users.each do |u|
136 141 ustat = Array.new
137 142 ustat[0] = u
138 143 @problems.each do |p|
139 144 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
@@ -1,64 +1,64
1 1 # Methods added to this helper will be available to all templates in the application.
2 2 module ApplicationHelper
3 3
4 4 def user_header
5 5 menu_items = ''
6 6 user = User.find(session[:user_id])
7 7
8 8 if (user!=nil) and (session[:admin])
9 9 # admin menu
10 10 menu_items << "<b>Administrative task:</b> "
11 11 append_to menu_items, '[Announcements]', 'announcements', 'index'
12 12 append_to menu_items, '[Msg console]', 'messages', 'console'
13 13 append_to menu_items, '[Problems]', 'problems', 'index'
14 14 append_to menu_items, '[Users]', 'user_admin', 'index'
15 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 17 append_to menu_items, '[Graders]', 'graders', 'list'
18 18 append_to menu_items, '[Contests]', 'contest_management', 'index'
19 19 append_to menu_items, '[Sites]', 'sites', 'index'
20 20 append_to menu_items, '[System config]', 'configurations', 'index'
21 21 menu_items << "<br/>"
22 22 end
23 23
24 24 # main page
25 25 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
26 26 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
27 27
28 28 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
29 29 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
30 30 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
31 31 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
32 32 end
33 33
34 34 if GraderConfiguration['right.user_hall_of_fame']
35 35 append_to menu_items, "[#{I18n.t 'menu.hall_of_fame'}]", 'report', 'problem_hof'
36 36 end
37 37 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
38 38
39 39 if GraderConfiguration['system.user_setting_enabled']
40 40 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
41 41 end
42 42 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
43 43
44 44 menu_items.html_safe
45 45 end
46 46
47 47 def append_to(option,label, controller, action)
48 48 option << ' ' if option!=''
49 49 option << link_to_unless_current(label,
50 50 :controller => controller,
51 51 :action => action)
52 52 end
53 53
54 54 def format_short_time(time)
55 55 now = Time.now.gmtime
56 56 st = ''
57 57 if (time.yday != now.yday) or
58 58 (time.year != now.year)
59 59 st = time.strftime("%x ")
60 60 end
61 61 st + time.strftime("%X")
62 62 end
63 63
64 64 def format_short_duration(duration)
@@ -22,101 +22,101
22 22
23 23 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24 24
25 25 belongs_to :site
26 26 belongs_to :country
27 27
28 28 has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
29 29
30 30 scope :activated_users, :conditions => {:activated => true}
31 31
32 32 validates_presence_of :login
33 33 validates_uniqueness_of :login
34 34 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
35 35 validates_length_of :login, :within => 3..30
36 36
37 37 validates_presence_of :full_name
38 38 validates_length_of :full_name, :minimum => 1
39 39
40 40 validates_presence_of :password, :if => :password_required?
41 41 validates_length_of :password, :within => 4..20, :if => :password_required?
42 42 validates_confirmation_of :password, :if => :password_required?
43 43
44 44 validates_format_of :email,
45 45 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 46 :if => :email_validation?
47 47 validate :uniqueness_of_email_from_activated_users,
48 48 :if => :email_validation?
49 49 validate :enough_time_interval_between_same_email_registrations,
50 50 :if => :email_validation?
51 51
52 52 # these are for ytopc
53 53 # disable for now
54 54 #validates_presence_of :province
55 55
56 56 attr_accessor :password
57 57
58 58 before_save :encrypt_new_password
59 59 before_save :assign_default_site
60 60 before_save :assign_default_contest
61 61
62 62 # this is for will_paginate
63 63 cattr_reader :per_page
64 64 @@per_page = 50
65 65
66 66 def self.authenticate(login, password)
67 67 user = find_by_login(login)
68 68 if user
69 69 return user if user.authenticated?(password)
70 - if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 - user.password = password
72 - user.save
73 - return user
74 - end
70 + # if user.authenticated_by_cucas?(password) or user.authenticated_by_pop3?(password)
71 + # user.password = password
72 + # user.save
73 + # return user
74 + # end
75 75 end
76 76 end
77 77
78 78 def authenticated?(password)
79 79 if self.activated
80 80 hashed_password == User.encrypt(password,self.salt)
81 81 else
82 82 false
83 83 end
84 84 end
85 85
86 86 def authenticated_by_pop3?(password)
87 87 Net::POP3.enable_ssl
88 88 pop = Net::POP3.new('pops.it.chula.ac.th')
89 89 authen = true
90 90 begin
91 91 pop.start(login, password)
92 92 pop.finish
93 93 return true
94 94 rescue
95 95 return false
96 96 end
97 97 end
98 98
99 99 def authenticated_by_cucas?(password)
100 100 url = URI.parse('https://www.cas.chula.ac.th/cas/api/?q=studentAuthenticate')
101 101 appid = '41508763e340d5858c00f8c1a0f5a2bb'
102 102 appsecret ='d9cbb5863091dbe186fded85722a1e31'
103 103 post_args = {
104 104 'appid' => appid,
105 105 'appsecret' => appsecret,
106 106 'username' => login,
107 107 'password' => password
108 108 }
109 109
110 110 #simple call
111 111 begin
112 112 http = Net::HTTP.new('www.cas.chula.ac.th', 443)
113 113 http.use_ssl = true
114 114 result = [ ]
115 115 http.start do |http|
116 116 req = Net::HTTP::Post.new('/cas/api/?q=studentAuthenticate')
117 117 param = "appid=#{appid}&appsecret=#{appsecret}&username=#{login}&password=#{password}"
118 118 resp = http.request(req,param)
119 119 result = JSON.parse resp.body
120 120 end
121 121 return true if result["type"] == "beanStudent"
122 122 rescue
@@ -1,51 +1,53
1 1 :css
2 2 .fix-width {
3 3 font-family: "Consolas, Monaco, Droid Sans Mono,Mono, Monospace,Courier"
4 4 }
5 5
6 6 %h1 Problem stat: #{@problem.name}
7 7 %h2 Overview
8 8
9 9
10 10 %table.info
11 11 %thead
12 12 %tr.info-head
13 13 %th Stat
14 14 %th Value
15 15 %tbody
16 16 %tr{class: cycle('info-even','info-odd')}
17 17 %td Submissions
18 18 %td= @submissions.count
19 19 %tr{class: cycle('info-even','info-odd')}
20 20 %td Solved/Attempted User
21 21 %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
22 22
23 23 %h2 Submissions Count
24 24 = render partial: 'application/bar_graph', locals: { histogram: @histogram }
25 25
26 26 %h2 Submissions
27 27 - if @submissions and @submissions.count > 0
28 28 %table.info#main_table
29 29 %thead
30 30 %tr.info-head
31 31 %th ID
32 32 %th Login
33 33 %th Name
34 34 %th Submitted_at
35 35 %th Points
36 36 %th comment
37 + %th IP
37 38 %tbody
38 39 - row_odd,curr = true,''
39 40 - @submissions.each do |sub|
40 41 - next unless sub.user
41 42 - row_odd,curr = !row_odd, sub.user if curr != sub.user
42 43 %tr{class: row_odd ? "info-odd" : "info-even"}
43 44 %td= link_to sub.id, controller: 'graders', action: 'submission', id: sub.id
44 45 %td= link_to sub.user.login, controller: :users, action: :profile, id: sub.user.id
45 46 %td= sub.user.full_name
46 47 %td= time_ago_in_words(sub.submitted_at) + " ago"
47 48 %td= sub.points
48 49 %td.fix-width= sub.grader_comment
50 + %td= sub.ip_address
49 51 - else
50 52 No submission
51 53
@@ -1,20 +1,37
1 1 - content_for :header do
2 2 = stylesheet_link_tag 'tablesorter-theme.cafe'
3 3 = javascript_include_tag 'local_jquery'
4 4
5 5 %h1 Login status
6 6
7 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 12 %table.tablesorter-cafe#my_table
10 13 %thead
11 14 %tr
12 15 %th login
13 16 %th full name
14 17 %th IP
15 18 %tbody
16 - - @multiple.each do |l|
19 + - @users.each do |l|
17 20 %tr{class: cycle('info-even','info-odd')}
18 - %td= link_to l[:login], controller: 'users', action: 'profile', id: l[:id]
19 - %td= l[:full_name]
21 + %td= link_to l.user.login, controller: 'users', action: 'profile', id: l[:id]
22 + %td= l.user.full_name
20 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