Description:
- login report - fix bugs on pagination on user manage
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r792:6ae18fbc4b91 - - 14 files changed: 255 inserted, 76 deleted

@@ -0,0 +1,130
1 + - content_for :header do
2 + = javascript_include_tag 'local_jquery'
3 +
4 + %h1 Logins detail
5 +
6 + .row
7 + .col-md-4
8 + .alert.alert-info
9 + %ul
10 + %li You have to click refresh when changing the filter above
11 + %li Detail tab shows each logins separately
12 + %li Summary tab shows logins summary of each user
13 + .col-md-4
14 + = render partial: 'shared/date_filter'
15 + .col-md-4
16 + = render partial: 'shared/user_select'
17 +
18 + .row.form-group
19 + .col-sm-12
20 + %ul.nav.nav-tabs
21 + %li.active
22 + %a{href: '#detail', data: {toggle: :tab}} Detail
23 + %li
24 + %a{href: '#summary', data: {toggle: :tab}} Summary
25 + .row
26 + .col-sm-12
27 + .tab-content
28 + .tab-pane.active#detail
29 + %table#detail-table.table.table-hover.table-condense.datatable{style: 'width: 100%'}
30 + .tab-pane#summary
31 + %table#summary-table.table.table-hover.table-condense.datatable{style: 'width: 100%'}
32 +
33 +
34 +
35 + :javascript
36 + $(function() {
37 + detail_table = $('#detail-table').DataTable({
38 + dom: "<'row'<'col-sm-3'B><'col-sm-3'l><'col-sm-6'f>>" + "<'row'<'col-sm-12'tr>>" + "<'row'<'col-sm-5'i><'col-sm-7'p>>",
39 + autoWidth: true,
40 + buttons: [
41 + {
42 + text: 'Refresh',
43 + action: (e,dt,node,config) => {
44 + detail_table.clear().draw()
45 + detail_table.ajax.reload( () => { detail_table.columns.adjust().draw() } )
46 + summary_table.clear().draw()
47 + summary_table.ajax.reload( () => { summary_table.columns.adjust().draw() } )
48 + }
49 + },
50 + 'copy',
51 + {
52 + extend: 'excel',
53 + title: 'Login detail',
54 + }
55 + ],
56 + columns: [
57 + {title: 'User', data: 'login_text'},
58 + {title: 'Time', data: 'created_at'},
59 + {title: 'IP', data: 'ip_address'},
60 + ],
61 + ajax: {
62 + url: '#{login_detail_query_report_path}',
63 + type: 'POST',
64 + data: (d) => {
65 + d.since_datetime = $('#since_datetime').val()
66 + d.until_datetime = $('#until_datetime').val()
67 + d.users = $("input[name='users']:checked").val()
68 + d.groups = $("#group_id").select2('val')
69 + },
70 + dataType: 'json',
71 + beforeSend: (request) => {
72 + request.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
73 + },
74 + }, //end ajax
75 + pageLength: 25,
76 + processing: true,
77 + });
78 +
79 + summary_table = $('#summary-table').DataTable({
80 + dom: "<'row'<'col-sm-3'B><'col-sm-3'l><'col-sm-6'f>>" + "<'row'<'col-sm-12'tr>>" + "<'row'<'col-sm-5'i><'col-sm-7'p>>",
81 + autoWidth: true,
82 + buttons: [
83 + {
84 + text: 'Refresh',
85 + action: (e,dt,node,config) => {
86 + summary_table.clear().draw()
87 + summary_table.ajax.reload( () => { summary_table.columns.adjust().draw() } )
88 + detail_table.clear().draw()
89 + detail_table.ajax.reload( () => { detail_table.columns.adjust().draw() } )
90 + }
91 + },
92 + 'copy',
93 + {
94 + extend: 'excel',
95 + title: 'Login summary',
96 + }
97 + ],
98 + columns: [
99 + {title: 'User', data: 'login_text'},
100 + {title: 'Login Count', data: 'count'},
101 + {title: 'Earliest', data: 'earliest'},
102 + {title: 'Latest', data: 'latest'},
103 + {title: 'IP', data: 'ip_address'},
104 + ],
105 + ajax: {
106 + url: '#{login_summary_query_report_path}',
107 + type: 'POST',
108 + data: (d) => {
109 + d.since_datetime = $('#since_datetime').val()
110 + d.until_datetime = $('#until_datetime').val()
111 + d.users = $("input[name='users']:checked").val()
112 + d.groups = $("#group_id").select2('val')
113 + },
114 + dataType: 'json',
115 + beforeSend: (request) => {
116 + request.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
117 + },
118 + }, //end ajax
119 + pageLength: 25,
120 + processing: true,
121 + });
122 +
123 + $('.input-group.date').datetimepicker({
124 + format: 'YYYY-MM-DD HH:mm',
125 + showTodayButton: true,
126 + locale: 'en',
127 + widgetPositioning: {horizontal: 'auto', vertical: 'bottom'},
128 + defaultDate: moment()
129 + });
130 + });
@@ -0,0 +1,10
1 + json.draw params['draw']&.to_i
2 + json.recordsTotal @recordsTotal
3 + json.recordsFiltered @recordsFiltered
4 + json.data do
5 + json.array! @logins do |login|
6 + json.login_text login.user ? "<a href='#{stat_user_path(login.user_id)}'>(#{login.user.login})</a> #{login.user.full_name}" : '-- deletec user --'
7 + json.created_at login.created_at.strftime('%Y-%m-%d %H:%M')
8 + json.ip_address login.ip_address
9 + end
10 + end
@@ -0,0 +1,12
1 + json.draw params['draw']&.to_i
2 + json.recordsTotal @recordsTotal
3 + json.recordsFiltered @recordsFiltered
4 + json.data do
5 + json.array! @users do |user|
6 + json.login_text "<a href='#{stat_user_path(user[:id])}'>(#{user[:login]})</a> #{user[:full_name]}"
7 + json.count user[:count]
8 + json.earliest user[:min].strftime('%Y-%m-%d %H:%M')
9 + json.latest user[:max].strftime('%Y-%m-%d %H:%M')
10 + json.ip_address user[:ip].join('<br/>')
11 + end
12 + end
@@ -0,0 +1,5
1 + class AddIndexToLogin < ActiveRecord::Migration[5.2]
2 + def change
3 + add_index :logins, :user_id
4 + end
5 + end
@@ -1,31 +1,33
1 1 require 'csv'
2 2
3 3 class ReportController < ApplicationController
4 4
5 5 before_action :check_valid_login
6 6
7 - before_action :admin_authorization, only: [:login_stat,:submission, :submission_query, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
7 + before_action :admin_authorization, only: [:login_stat,:submission, :submission_query,
8 + :login, :login_detail_query, :login_summary_query,
9 + :stuck, :cheat_report, :cheat_scruntinize, :show_max_score, :current_score]
8 10
9 11 before_action(only: [:problem_hof]) { |c|
10 12 return false unless check_valid_login
11 13
12 14 admin_authorization unless GraderConfiguration["right.user_view_submission"]
13 15 }
14 16
15 17 def max_score
16 18 end
17 19
18 20 def current_score
19 21 @problems = Problem.available_problems
20 22 if params[:group_id]
21 23 @group = Group.find(params[:group_id])
22 24 @users = @group.users.where(enabled: true)
23 25 else
24 26 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
25 27 end
26 28 @scorearray = calculate_max_score(@problems, @users,0,0,true)
27 29
28 30 #rencer accordingly
29 31 if params[:button] == 'download' then
30 32 csv = gen_csv_from_scorearray(@scorearray,@problems)
31 33 send_data csv, filename: 'max_score.csv'
@@ -83,116 +85,156
83 85 @users = User.includes(:contests, :contest_stat).where(enabled: true)
84 86 @scorearray = Array.new
85 87 @users.each do |u|
86 88 ustat = Array.new
87 89 ustat[0] = u
88 90 @problems.each do |p|
89 91 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
90 92 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
91 93 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
92 94 else
93 95 ustat << [0,false]
94 96 end
95 97 end
96 98 @scorearray << ustat
97 99 end
98 100 if params[:commit] == 'download csv' then
99 101 csv = gen_csv_from_scorearray(@scorearray,@problems)
100 102 send_data csv, filename: 'last_score.csv'
101 103 else
102 104 render template: 'user_admin/user_stat'
103 105 end
104 106
105 107 end
106 108
107 - def login_stat
109 + def login
110 + end
111 +
112 + def login_summary_query
113 + @users = Array.new
114 +
115 + date_and_time = '%Y-%m-%d %H:%M'
116 + begin
117 + md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
118 + @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)
119 + rescue
120 + @since_time = DateTime.new(1000,1,1)
121 + end
122 + begin
123 + md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
124 + @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)
125 + rescue
126 + @until_time = DateTime.new(3000,1,1)
127 + end
128 +
129 + record = User
130 + .left_outer_joins(:logins).group('users.id')
131 + .where("logins.created_at >= ? AND logins.created_at <= ?",@since_time, @until_time)
132 + case params[:users]
133 + when 'enabled'
134 + record = record.where(enabled: true)
135 + when 'group'
136 + record = record.joins(:groups).where(groups: {id: params[:groups]}) if params[:groups]
137 + end
138 +
139 + record = record.pluck("users.id,users.login,users.full_name,count(logins.created_at),min(logins.created_at),max(logins.created_at)")
140 + record.each do |user|
141 + x = Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
142 + user[0],@since_time,@until_time)
143 + .pluck(:ip_address).uniq
144 + @users << { id: user[0],
145 + login: user[1],
146 + full_name: user[2],
147 + count: user[3],
148 + min: user[4],
149 + max: user[5],
150 + ip: x
151 + }
152 + end
153 + end
154 +
155 + def login_detail_query
108 156 @logins = Array.new
109 157
110 158 date_and_time = '%Y-%m-%d %H:%M'
111 159 begin
112 160 md = params[:since_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
113 161 @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)
114 162 rescue
115 163 @since_time = DateTime.new(1000,1,1)
116 164 end
117 165 begin
118 166 md = params[:until_datetime].match(/(\d+)-(\d+)-(\d+) (\d+):(\d+)/)
119 167 @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)
120 168 rescue
121 169 @until_time = DateTime.new(3000,1,1)
122 170 end
123 -
124 - User.all.each do |user|
125 - @logins << { id: user.id,
126 - login: user.login,
127 - full_name: user.full_name,
128 - count: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
129 - user.id,@since_time,@until_time)
130 - .count(:id),
131 - min: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
132 - user.id,@since_time,@until_time)
133 - .minimum(:created_at),
134 - max: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
135 - user.id,@since_time,@until_time)
136 - .maximum(:created_at),
137 - ip: Login.where("user_id = ? AND created_at >= ? AND created_at <= ?",
138 - user.id,@since_time,@until_time)
139 - .select(:ip_address).uniq
140 171
141 - }
172 + @logins = Login.includes(:user).where("logins.created_at >= ? AND logins.created_at <= ?",@since_time, @until_time)
173 + case params[:users]
174 + when 'enabled'
175 + @logins = @logins.where(users: {enabled: true})
176 + when 'group'
177 + @logins = @logins.joins(user: :groups).where(user: {groups: {id: params[:groups]}}) if params[:groups]
142 178 end
143 179 end
144 180
145 181 def submission
146 182 end
147 183
148 184 def submission_query
149 185 @submissions = Submission
150 186 .includes(:problem).includes(:user).includes(:language)
151 187
152 - if params[:problem]
153 - @submission = @submission.where(problem_id: params[:problem])
188 + case params[:users]
189 + when 'enabled'
190 + @submissions = @submissions.where(users: {enabled: true})
191 + when 'group'
192 + @submissions = @submissions.joins(user: :groups).where(user: {groups: {id: params[:groups]}}) if params[:groups]
154 193 end
155 194
156 - case params[:users]
195 + case params[:problems]
157 196 when 'enabled'
158 - @submissions = @submissions.where('user.enabled': true)
159 - when 'group'
160 - @submissions = @submissions.joins(user: :groups).where(user: {groups: {id: params[:groups]}}) if params[:groups]
197 + @submissions = @submissions.where(problems: {available: true})
198 + when 'selected'
199 + @submissions = @submissions.where(problem_id: params[:problem_id])
161 200 end
162 201
163 202 #set default
164 203 params[:since_datetime] = Date.today.to_s if params[:since_datetime].blank?
165 204
166 205 @submissions, @recordsTotal, @recordsFiltered = process_query_record( @submissions,
167 206 global_search: ['user.login','user.full_name','problem.name','problem.full_name','points'],
168 207 date_filter: 'submitted_at',
169 208 date_param_since: 'since_datetime',
170 209 date_param_until: 'until_datetime',
171 210 hard_limit: 100_000
172 211 )
173 212 end
174 213
214 + def login
215 + end
216 +
175 217 def problem_hof
176 218 # gen problem list
177 219 @user = User.find(session[:user_id])
178 220 @problems = @user.available_problems
179 221
180 222 # get selected problems or the default
181 223 if params[:id]
182 224 begin
183 225 @problem = Problem.available.find(params[:id])
184 226 rescue
185 227 redirect_to action: :problem_hof
186 228 flash[:notice] = 'Error: submissions for that problem are not viewable.'
187 229 return
188 230 end
189 231 end
190 232
191 233 return unless @problem
192 234
193 235 @by_lang = {} #aggregrate by language
194 236
195 237 range =65
196 238 @histogram = { data: Array.new(range,0), summary: {} }
197 239 @summary = {count: 0, solve: 0, attempt: 0}
198 240 user = Hash.new(0)
@@ -1,41 +1,34
1 1 require 'csv'
2 2
3 3 class UserAdminController < ApplicationController
4 4
5 5 include MailHelperMethods
6 6
7 7 before_action :admin_authorization
8 8
9 9 def index
10 10 @user_count = User.count
11 - if params[:page] == 'all'
12 - @users = User.all
13 - @paginated = false
14 - else
15 - @users = User.paginate :page => params[:page]
16 - @paginated = true
17 - end
18 11 @users = User.all
19 12 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
20 13 @contests = Contest.enabled
21 14 end
22 15
23 16 def active
24 17 sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
25 18 @users = []
26 19 sessions.each do |session|
27 20 if session.data[:user_id]
28 21 @users << User.find(session.data[:user_id])
29 22 end
30 23 end
31 24 end
32 25
33 26 def show
34 27 @user = User.find(params[:id])
35 28 end
36 29
37 30 def new
38 31 @user = User.new
39 32 end
40 33
41 34 def create
@@ -1,48 +1,50
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 9 has_and_belongs_to_many :roles
10 10
11 11 #has_and_belongs_to_many :groups
12 12 has_many :groups_users, class_name: 'GroupUser'
13 13 has_many :groups, :through => :groups_users
14 14
15 15 has_many :test_requests, -> {order(submitted_at: :desc)}
16 16
17 17 has_many :messages, -> { order(created_at: :desc) },
18 18 :class_name => "Message",
19 19 :foreign_key => "sender_id"
20 20
21 21 has_many :replied_messages, -> { order(created_at: :desc) },
22 22 :class_name => "Message",
23 23 :foreign_key => "receiver_id"
24 24
25 + has_many :logins
26 +
25 27 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
26 28
27 29 belongs_to :site
28 30 belongs_to :country
29 31
30 32 has_and_belongs_to_many :contests, -> { order(:name)}
31 33
32 34 scope :activated_users, -> {where activated: true}
33 35
34 36 validates_presence_of :login
35 37 validates_uniqueness_of :login
36 38 validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
37 39 validates_length_of :login, :within => 3..30
38 40
39 41 validates_presence_of :full_name
40 42 validates_length_of :full_name, :minimum => 1
41 43
42 44 validates_presence_of :password, :if => :password_required?
43 45 validates_length_of :password, :within => 4..50, :if => :password_required?
44 46 validates_confirmation_of :password, :if => :password_required?
45 47
46 48 validates_format_of :email,
47 49 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
48 50 :if => :email_validation?
@@ -44,48 +44,49
44 44 Manage
45 45 %span.caret
46 46 %ul.dropdown-menu
47 47 = add_menu( 'Announcements', 'announcements', 'index')
48 48 = add_menu( 'Problems', 'problems', 'index')
49 49 = add_menu( 'Tags', 'tags', 'index')
50 50 = add_menu( 'Users', 'user_admin', 'index')
51 51 = add_menu( 'User Groups', 'groups', 'index')
52 52 = add_menu( 'Graders', 'graders', 'list')
53 53 = add_menu( 'Message ', 'messages', 'console')
54 54 %li.divider{role: 'separator'}
55 55 = add_menu( 'System config', 'configurations', 'index')
56 56 %li.divider{role: 'separator'}
57 57 = add_menu( 'Sites', 'sites', 'index')
58 58 = add_menu( 'Contests', 'contest_management', 'index')
59 59 / report
60 60 %li.dropdown
61 61 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
62 62 Report
63 63 %span.caret
64 64 %ul.dropdown-menu
65 65 = add_menu( 'Current Score', 'report', 'current_score')
66 66 = add_menu( 'Score Report', 'report', 'max_score')
67 67 = add_menu( 'Submission Report', 'report', 'submission')
68 + = add_menu( 'Login Report', 'report', 'login')
68 69 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
69 70 =link_to "#{ungraded} backlogs!",
70 71 grader_list_path,
71 72 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
72 73
73 74 %ul.nav.navbar-nav.navbar-right
74 75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
75 76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'index', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
76 77 - if GraderConfiguration['system.user_setting_enabled']
77 78 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog', id: 'user_profile')}".html_safe, 'users', 'profile', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
78 79 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
79 80
80 81 /
81 82 - if (@current_user!=nil) and (session[:admin])
82 83 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
83 84 .container-fluid
84 85 .collapse.navbar-collapse
85 86 %ul.nav.navbar-nav
86 87 = add_menu( '[Announcements]', 'announcements', 'index')
87 88 = add_menu( '[Msg console]', 'messages', 'console')
88 89 = add_menu( '[Problems]', 'problems', 'index')
89 90 = add_menu( '[Users]', 'user_admin', 'index')
90 91 = add_menu( '[Results]', 'user_admin', 'user_stat')
91 92 = add_menu( '[Report]', 'report', 'multiple_login')
@@ -15,63 +15,68
15 15 .col-md-6
16 16 .alert.alert-info
17 17 %ul
18 18 %li Display a maximum of 100,000 entries to save computation power
19 19 %li You have to click refresh when changing the filter above
20 20
21 21 .row
22 22 .col-sm-12
23 23 %table.table.table-hover.table-condense.datatable{style: 'width: 100%'}
24 24
25 25
26 26 :javascript
27 27 $(function() {
28 28 submission_table = $('.datatable').DataTable({
29 29 dom: "<'row'<'col-sm-3'B><'col-sm-3'l><'col-sm-6'f>>" + "<'row'<'col-sm-12'tr>>" + "<'row'<'col-sm-5'i><'col-sm-7'p>>",
30 30 autoWidth: true,
31 31 buttons: [
32 32 {
33 33 text: 'Refresh',
34 34 action: (e,dt,node,config) => {
35 35 submission_table.clear().draw()
36 36 submission_table.ajax.reload( () => { submission_table.columns.adjust().draw() } )
37 37 }
38 38 },
39 - 'copy', 'excel'
39 + 'copy',
40 + {
41 + extend: 'excel',
42 + title: 'Submission detail'
43 + }
40 44 ],
41 45 columns: [
42 46 {title: 'Sub ID', data: 'id'},
43 47 {title: 'User', data: 'user.login'},
44 48 {title: 'Problem', data: 'problem.long_name'},
45 49 {title: 'Language', data: 'language.pretty_name'},
46 50 {title: 'Submit at', data: 'submitted_at'},
47 51 {title: 'Result', data: 'grader_comment'},
48 52 {title: 'Score', data: 'points'},
49 53 {title: 'IP', data: 'ip_address'},
50 54 ],
51 55 ajax: {
52 56 url: '#{submission_query_report_path}',
53 57 type: 'POST',
54 58 data: (d) => {
55 59 d.since_datetime = $('#since_datetime').val()
56 60 d.until_datetime = $('#until_datetime').val()
57 61 d.users = $("input[name='users']:checked").val()
58 - d.problems = $("#problem_id").select2('val')
59 62 d.groups = $("#group_id").select2('val')
63 + d.problems = $("input[name='problems']:checked").val()
64 + d.problem_id = $("#problem_id").select2('val')
60 65 },
61 66 dataType: 'json',
62 67 beforeSend: (request) => {
63 68 request.setRequestHeader('X-CSRF-Token', $('meta[name="csrf-token"]').attr('content'));
64 69 },
65 70 }, //end ajax
66 71 'pageLength': 50,
67 72 processing: true,
68 73 });
69 74
70 75 $('.input-group.date').datetimepicker({
71 76 format: 'YYYY-MM-DD',
72 77 showTodayButton: true,
73 78 locale: 'en',
74 79 widgetPositioning: {horizontal: 'auto', vertical: 'bottom'},
75 80 defaultDate: moment()
76 81 });
77 82 });
@@ -1,10 +1,19
1 1 .panel.panel-primary
2 2 .panel-heading
3 3 Problems
4 4 .panel-body
5 - %p
6 - Select problem(s) to be included in the report
7 - = label_tag :problem_id, "Problems"
5 + .radio
6 + %label
7 + = radio_button_tag 'problems', 'all', (params[:users] == "all")
8 + All problems
9 + .radio
10 + %label
11 + = radio_button_tag 'problems', 'enabled', (params[:users] == "enabled"), checked: true
12 + Only problems with available = "yes"
13 + .radio
14 + %label
15 + = radio_button_tag 'problems', 'selected', (params[:users] == "group")
16 + Only these selected problems
8 17 = select_tag 'problem_id[]',
9 18 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
10 19 { id: :problem_id, class: 'select2 form-control', multiple: "true" }
@@ -1,19 +1,19
1 1 .panel.panel-primary
2 2 .panel-heading
3 3 Users
4 4 .panel-body
5 5 .radio
6 6 %label
7 7 = radio_button_tag 'users', 'all', (params[:users] == "all")
8 8 All users
9 9 .radio
10 10 %label
11 - = radio_button_tag 'users', 'enabled', (params[:users] == "enabled")
11 + = radio_button_tag 'users', 'enabled', (params[:users] == "enabled"), checked: true
12 12 Only enabled users
13 13 .radio
14 14 %label
15 15 = radio_button_tag 'users', 'group', (params[:users] == "group")
16 16 Only these groups
17 17 = select_tag 'group_id[]',
18 18 options_for_select(Group.all.collect {|g| ["[#{g.name}] #{g.description}", g.id]}),
19 19 { id: 'group_id', class: 'select2 form-control', multiple: "true"}
@@ -133,48 +133,53
133 133 end
134 134
135 135 #get 'user_admin', to: 'user_admin#index'
136 136 #get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
137 137 #post 'user_admin', to: 'user_admin#create'
138 138 #delete 'user_admin/:id', to: 'user_admin#destroy', as: 'user_admin_destroy'
139 139
140 140 #singular resource
141 141 #---- BEWARE ---- singular resource maps to plural controller by default, we can override by provide controller name directly
142 142 #report
143 143 resource :report, only: [], controller: 'report' do
144 144 get 'login'
145 145 get 'multiple_login'
146 146 get 'problem_hof(/:id)', action: 'problem_hof', as: 'problem_hof'
147 147 get 'current_score(/:group_id)', action: 'current_score', as: 'current_score'
148 148 get 'max_score'
149 149 post 'show_max_score'
150 150 get 'stuck'
151 151 get 'cheat_report'
152 152 post 'cheat_report'
153 153 get 'cheat_scruntinize'
154 154 post 'cheat_scruntinize'
155 155 get 'submission'
156 156 post 'submission_query'
157 + get 'login_stat'
158 + post 'login_stat'
159 + get 'login'
160 + post 'login_summary_query'
161 + post 'login_detail_query'
157 162 end
158 163 #get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
159 164 #get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
160 165 #get "report/login"
161 166 #get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
162 167 #post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
163 168
164 169 resource :main, only: [], controller: 'main' do
165 170 get 'login'
166 171 get 'logout'
167 172 get 'list'
168 173 get 'submission(/:id)', action: 'submission', as: 'main_submission'
169 174 get 'announcements'
170 175 get 'help'
171 176 post 'submit'
172 177 end
173 178 #main
174 179 #get "main/list"
175 180 #get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
176 181 #post 'main/submit', to: 'main#submit'
177 182 #get 'main/announcements', to: 'main#announcements'
178 183
179 184
180 185 #
@@ -1,37 +1,37
1 1 # This file is auto-generated from the current state of the database. Instead
2 2 # of editing this file, please use the migrations feature of Active Record to
3 3 # incrementally modify your database, and then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your
6 6 # database schema. If you need to create the application database on another
7 7 # system, you should be using db:schema:load, not running all the migrations
8 8 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 9 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 10 #
11 11 # It's strongly recommended that you check this file into your version control system.
12 12
13 - ActiveRecord::Schema.define(version: 2020_04_04_142959) do
13 + ActiveRecord::Schema.define(version: 2020_04_05_112919) do
14 14
15 15 create_table "announcements", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
16 16 t.string "author"
17 17 t.text "body", limit: 16777215
18 18 t.boolean "published"
19 19 t.datetime "created_at", null: false
20 20 t.datetime "updated_at", null: false
21 21 t.boolean "frontpage", default: false
22 22 t.boolean "contest_only", default: false
23 23 t.string "title"
24 24 t.string "notes"
25 25 end
26 26
27 27 create_table "contests", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
28 28 t.string "title"
29 29 t.boolean "enabled"
30 30 t.datetime "created_at", null: false
31 31 t.datetime "updated_at", null: false
32 32 t.string "name"
33 33 end
34 34
35 35 create_table "contests_problems", id: false, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
36 36 t.integer "contest_id"
37 37 t.integer "problem_id"
@@ -94,48 +94,49
94 94 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
95 95 end
96 96
97 97 create_table "heart_beats", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
98 98 t.integer "user_id"
99 99 t.string "ip_address"
100 100 t.datetime "created_at", null: false
101 101 t.datetime "updated_at", null: false
102 102 t.string "status"
103 103 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
104 104 end
105 105
106 106 create_table "languages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
107 107 t.string "name", limit: 10
108 108 t.string "pretty_name"
109 109 t.string "ext", limit: 10
110 110 t.string "common_ext"
111 111 end
112 112
113 113 create_table "logins", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
114 114 t.integer "user_id"
115 115 t.string "ip_address"
116 116 t.datetime "created_at", null: false
117 117 t.datetime "updated_at", null: false
118 + t.index ["user_id"], name: "index_logins_on_user_id"
118 119 end
119 120
120 121 create_table "messages", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
121 122 t.integer "sender_id"
122 123 t.integer "receiver_id"
123 124 t.integer "replying_message_id"
124 125 t.text "body", limit: 16777215
125 126 t.boolean "replied"
126 127 t.datetime "created_at", null: false
127 128 t.datetime "updated_at", null: false
128 129 end
129 130
130 131 create_table "problems", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=utf8", force: :cascade do |t|
131 132 t.string "name", limit: 100
132 133 t.string "full_name"
133 134 t.integer "full_score"
134 135 t.date "date_added"
135 136 t.boolean "available"
136 137 t.string "url"
137 138 t.integer "description_id"
138 139 t.boolean "test_allowed"
139 140 t.boolean "output_only"
140 141 t.string "description_filename"
141 142 t.boolean "view_testcase"
deleted file
You need to be logged in to leave comments. Login now