Description:
modernize problem
Commit status:
[Not Reviewed]
References:
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r876:8cd1c60e1ef0 - - The requested commit is too big and content was truncated. 22 files changed. Show full diff

@@ -0,0 +1,6
1 + %h1 New Problem
2 +
3 + = render 'form', problem: @problem
4 + .row.my-3
5 + .col-md-4
6 + = link_to 'Back', problems_path, class: 'btn btn-secondary'
@@ -0,0 +1,57
1 + # This migration comes from active_storage (originally 20170806125915)
2 + class CreateActiveStorageTables < ActiveRecord::Migration[5.2]
3 + def change
4 + # Use Active Record's configured type for primary and foreign keys
5 + primary_key_type, foreign_key_type = primary_and_foreign_key_types
6 +
7 + create_table :active_storage_blobs, id: primary_key_type do |t|
8 + t.string :key, null: false
9 + t.string :filename, null: false
10 + t.string :content_type
11 + t.text :metadata
12 + t.string :service_name, null: false
13 + t.bigint :byte_size, null: false
14 + t.string :checksum
15 +
16 + if connection.supports_datetime_with_precision?
17 + t.datetime :created_at, precision: 6, null: false
18 + else
19 + t.datetime :created_at, null: false
20 + end
21 +
22 + t.index [ :key ], unique: true
23 + end
24 +
25 + create_table :active_storage_attachments, id: primary_key_type do |t|
26 + t.string :name, null: false
27 + t.references :record, null: false, polymorphic: true, index: false, type: foreign_key_type
28 + t.references :blob, null: false, type: foreign_key_type
29 +
30 + if connection.supports_datetime_with_precision?
31 + t.datetime :created_at, precision: 6, null: false
32 + else
33 + t.datetime :created_at, null: false
34 + end
35 +
36 + t.index [ :record_type, :record_id, :name, :blob_id ], name: :index_active_storage_attachments_uniqueness, unique: true
37 + t.foreign_key :active_storage_blobs, column: :blob_id
38 + end
39 +
40 + create_table :active_storage_variant_records, id: primary_key_type do |t|
41 + t.belongs_to :blob, null: false, index: false, type: foreign_key_type
42 + t.string :variation_digest, null: false
43 +
44 + t.index [ :blob_id, :variation_digest ], name: :index_active_storage_variant_records_uniqueness, unique: true
45 + t.foreign_key :active_storage_blobs, column: :blob_id
46 + end
47 + end
48 +
49 + private
50 + def primary_and_foreign_key_types
51 + config = Rails.configuration.generators
52 + setting = config.options[config.orm][:primary_key_type]
53 + primary_key_type = setting || :primary_key
54 + foreign_key_type = setting || :bigint
55 + [primary_key_type, foreign_key_type]
56 + end
57 + end
@@ -0,0 +1,6
1 + class AddDescriptionToProblems < ActiveRecord::Migration[7.0]
2 + def change
3 + add_column :problems, :description, :text
4 + add_column :problems, :markdown, :boolean
5 + end
6 + end
@@ -0,0 +1,21
1 + Problem.all.each do |p|
2 + next unless p.description_filename
3 + basename, ext = p.description_filename.split('.')
4 + filename = "#{Problem.download_file_basedir}/#{p.id}/#{basename}.#{ext}"
5 +
6 + if File.exists? filename
7 + p.statement.attach io: File.open(filename), filename: "#{basename}.#{ext}"
8 + puts "#{p.id}: OK"
9 + else
10 + puts "#{p.id}: #{p.name} #{filename} ERROR"
11 + end
12 +
13 + d = Description.where(id: p.description_id).first
14 + if d
15 + p.description = d.body
16 + p.markdown = d.markdowned
17 + end
18 + p.save
19 +
20 +
21 + end
@@ -26,12 +26,13
26
26
27 #ignore .orig and .swp
27 #ignore .orig and .swp
28 *.orig
28 *.orig
29 *.swp
29 *.swp
30
30
31 #ignore rvm setting file
31 #ignore rvm setting file
32 #.ruby-gemset
32 #.ruby-gemset
33 #.ruby-version
33 #.ruby-version
34
34
35 /config/secrets.yml
35 /config/secrets.yml
36
36
37 /.byebug_history
37 /.byebug_history
38 + /storage/*
@@ -68,25 +68,26
68 #gem 'bootstrap-sass', '~> 3.4.1'
68 #gem 'bootstrap-sass', '~> 3.4.1'
69 gem 'bootstrap', '~> 5.2'
69 gem 'bootstrap', '~> 5.2'
70 #gem 'bootstrap-switch-rails'
70 #gem 'bootstrap-switch-rails'
71 #gem 'bootstrap-toggle-rails'
71 #gem 'bootstrap-toggle-rails'
72 #gem 'autoprefixer-rails'
72 #gem 'autoprefixer-rails'
73 gem 'momentjs-rails'
73 gem 'momentjs-rails'
74 #gem 'rails_bootstrap_sortable'
74 #gem 'rails_bootstrap_sortable'
75 #gem 'bootstrap-datepicker-rails'
75 #gem 'bootstrap-datepicker-rails'
76 #gem 'bootstrap3-datetimepicker-rails', '~> 4.17.47'
76 #gem 'bootstrap3-datetimepicker-rails', '~> 4.17.47'
77 #gem 'jquery-datatables-rails'
77 #gem 'jquery-datatables-rails'
78
78
79 #----------- user interface -----------------
79 #----------- user interface -----------------
80 - gem 'simple_form'
80 + gem 'simple_form', git: 'https://github.com/heartcombo/simple_form', ref: '31fe255'
81 +
81 #select 2
82 #select 2
82 #gem 'select2-rails'
83 #gem 'select2-rails'
83 #ace editor
84 #ace editor
84 gem 'ace-rails-ap'
85 gem 'ace-rails-ap'
85 #paginator
86 #paginator
86 #gem 'will_paginate', '~> 3.0.7'
87 #gem 'will_paginate', '~> 3.0.7'
87
88
88 gem 'mail'
89 gem 'mail'
89 gem 'rdiscount' #markdown
90 gem 'rdiscount' #markdown
90
91
91
92
92 #---------------- testiing -----------------------
93 #---------------- testiing -----------------------
@@ -1,12 +1,21
1 + GIT
2 + remote: https://github.com/heartcombo/simple_form
3 + revision: 31fe25504771bd6cd425b585a4e0ed652fba4521
4 + ref: 31fe255
5 + specs:
6 + simple_form (5.1.0)
7 + actionpack (>= 5.2)
8 + activemodel (>= 5.2)
9 +
1 GIT
10 GIT
2 remote: https://github.com/mmotherwell/best_in_place
11 remote: https://github.com/mmotherwell/best_in_place
3 revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0
12 revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0
4 specs:
13 specs:
5 best_in_place (3.1.1)
14 best_in_place (3.1.1)
6 actionpack (>= 3.2)
15 actionpack (>= 3.2)
7 railties (>= 3.2)
16 railties (>= 3.2)
8
17
9 GEM
18 GEM
10 remote: https://rubygems.org/
19 remote: https://rubygems.org/
11 specs:
20 specs:
12 RubyInline (3.12.6)
21 RubyInline (3.12.6)
@@ -238,27 +247,24
238 sassc-rails (2.1.2)
247 sassc-rails (2.1.2)
239 railties (>= 4.0.0)
248 railties (>= 4.0.0)
240 sassc (>= 2.0)
249 sassc (>= 2.0)
241 sprockets (> 3.0)
250 sprockets (> 3.0)
242 sprockets-rails
251 sprockets-rails
243 tilt
252 tilt
244 selenium-webdriver (4.4.0)
253 selenium-webdriver (4.4.0)
245 childprocess (>= 0.5, < 5.0)
254 childprocess (>= 0.5, < 5.0)
246 rexml (~> 3.2, >= 3.2.5)
255 rexml (~> 3.2, >= 3.2.5)
247 rubyzip (>= 1.2.2, < 3.0)
256 rubyzip (>= 1.2.2, < 3.0)
248 websocket (~> 1.0)
257 websocket (~> 1.0)
249 sexp_processor (4.16.1)
258 sexp_processor (4.16.1)
250 - simple_form (5.1.0)
251 - actionpack (>= 5.2)
252 - activemodel (>= 5.2)
253 spring (2.1.1)
259 spring (2.1.1)
254 spring-watcher-listen (2.0.1)
260 spring-watcher-listen (2.0.1)
255 listen (>= 2.7, < 4.0)
261 listen (>= 2.7, < 4.0)
256 spring (>= 1.2, < 3.0)
262 spring (>= 1.2, < 3.0)
257 sprockets (4.1.1)
263 sprockets (4.1.1)
258 concurrent-ruby (~> 1.0)
264 concurrent-ruby (~> 1.0)
259 rack (> 1, < 3)
265 rack (> 1, < 3)
260 sprockets-rails (3.4.2)
266 sprockets-rails (3.4.2)
261 actionpack (>= 5.2)
267 actionpack (>= 5.2)
262 activesupport (>= 5.2)
268 activesupport (>= 5.2)
263 sprockets (>= 3.0.0)
269 sprockets (>= 3.0.0)
264 sqlite3 (1.5.0-x86_64-linux)
270 sqlite3 (1.5.0-x86_64-linux)
@@ -306,25 +312,25
306 listen (>= 3.0.5, < 3.2)
312 listen (>= 3.0.5, < 3.2)
307 mail
313 mail
308 material_icons
314 material_icons
309 minitest-reporters
315 minitest-reporters
310 momentjs-rails
316 momentjs-rails
311 mysql2
317 mysql2
312 puma
318 puma
313 rails (~> 7.0)
319 rails (~> 7.0)
314 rdiscount
320 rdiscount
315 rouge
321 rouge
316 sassc-rails
322 sassc-rails
317 selenium-webdriver
323 selenium-webdriver
318 - simple_form
324 + simple_form!
319 spring
325 spring
320 spring-watcher-listen (~> 2.0.0)
326 spring-watcher-listen (~> 2.0.0)
321 sprockets-rails
327 sprockets-rails
322 sqlite3
328 sqlite3
323 web-console (>= 3.3.0)
329 web-console (>= 3.3.0)
324 webdrivers
330 webdrivers
325
331
326 RUBY VERSION
332 RUBY VERSION
327 ruby 3.1.2p20
333 ruby 3.1.2p20
328
334
329 BUNDLED WITH
335 BUNDLED WITH
330 2.3.22
336 2.3.22
@@ -50,28 +50,24
50 }
50 }
51
51
52 &.text-right {
52 &.text-right {
53 padding-left: 20px !important;
53 padding-left: 20px !important;
54 padding-right: 8px !important;
54 padding-right: 8px !important;
55
55
56 &:after, span.sign {
56 &:after, span.sign {
57 left: (-15px) !important;
57 left: (-15px) !important;
58 }
58 }
59 }
59 }
60 }
60 }
61
61
62 - input {
63 - font-family: Tahoma, "sans-serif";
64 - }
65 -
66 h1 {
62 h1 {
67 color: #334488;
63 color: #334488;
68 }
64 }
69
65
70 h2 {
66 h2 {
71 color: #5566bb;
67 color: #5566bb;
72 }
68 }
73
69
74 hr {
70 hr {
75 border-top: 1px solid #dddddd;
71 border-top: 1px solid #dddddd;
76 border-bottom: 1px solid #eeeeee;
72 border-bottom: 1px solid #eeeeee;
77 }
73 }
@@ -1,43 +1,50
1 require 'ipaddr'
1 require 'ipaddr'
2 require "securerandom"
2 require "securerandom"
3
3
4 class ApplicationController < ActionController::Base
4 class ApplicationController < ActionController::Base
5 protect_from_forgery
5 protect_from_forgery
6
6
7 before_action :current_user
7 before_action :current_user
8 before_action :nav_announcement
8 before_action :nav_announcement
9 before_action :unique_visitor_id
9 before_action :unique_visitor_id
10 + before_action :active_controller_action
10
11
11 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
12 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
12 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
13 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
13 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
14 WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore'
14 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
15 WHITELIST_IP_CONF_KEY = 'right.whitelist_ip'
15
16
16 #report and redirect for unauthorized activities
17 #report and redirect for unauthorized activities
17 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
18 def unauthorized_redirect(notice = 'You are not authorized to view the page you requested')
18 flash[:notice] = notice
19 flash[:notice] = notice
19 redirect_to login_main_path
20 redirect_to login_main_path
20 end
21 end
21
22
22 # Returns the current logged-in user (if any).
23 # Returns the current logged-in user (if any).
23 def current_user
24 def current_user
24 return nil unless session[:user_id]
25 return nil unless session[:user_id]
25 @current_user ||= User.find(session[:user_id])
26 @current_user ||= User.find(session[:user_id])
26 end
27 end
27
28
28 def nav_announcement
29 def nav_announcement
29 @nav_announcement = Announcement.where(on_nav_bar: true)
30 @nav_announcement = Announcement.where(on_nav_bar: true)
30 end
31 end
31
32
33 + def active_controller_action
34 + #so that we can override this value inside each action
35 + @active_controller = controller_name
36 + @active_action = action_name
37 + end
38 +
32 def admin_authorization
39 def admin_authorization
33 return false unless check_valid_login
40 return false unless check_valid_login
34 user = User.includes(:roles).find(session[:user_id])
41 user = User.includes(:roles).find(session[:user_id])
35 unless user.admin?
42 unless user.admin?
36 unauthorized_redirect
43 unauthorized_redirect
37 return false
44 return false
38 end
45 end
39 return true
46 return true
40 end
47 end
41
48
42 #admin always count as every roles
49 #admin always count as every roles
43 def role_authorization(roles)
50 def role_authorization(roles)
@@ -1,167 +1,143
1 class ProblemsController < ApplicationController
1 class ProblemsController < ApplicationController
2
2
3 + include ActiveStorage::SetCurrent
4 +
3 before_action :admin_authorization, except: [:stat]
5 before_action :admin_authorization, except: [:stat]
6 + before_action :set_problem, only: [:show, :edit, :update, :destroy, :get_statement, :toggle, :toggle_test, :toggle_view_testcase, :stat]
4 before_action only: [:stat] do
7 before_action only: [:stat] do
5 authorization_by_roles(['admin','ta'])
8 authorization_by_roles(['admin','ta'])
6 end
9 end
7
10
11 +
8 def index
12 def index
9 @problems = Problem.order(date_added: :desc)
13 @problems = Problem.order(date_added: :desc)
10 end
14 end
11
15
12
16
13 def show
17 def show
14 - @problem = Problem.find(params[:id])
18 + end
19 +
20 + #get statement download link
21 + def get_statement
22 + unless @current_user.can_view_problem? @problem
23 + redirect_to list_main_path, error: 'You are not authorized to access this file'
24 + return
25 + end
26 +
27 + if params[:ext]=='pdf'
28 + content_type = 'application/pdf'
29 + else
30 + content_type = 'application/octet-stream'
31 + end
32 +
33 + filename = @problem.statement.filename.to_s
34 + data =@problem.statement.download
35 +
36 + send_data data, stream: false, disposition: 'inline', filename: filename, type: content_type
15 end
37 end
16
38
17 def new
39 def new
18 @problem = Problem.new
40 @problem = Problem.new
19 - @description = nil
20 end
41 end
21
42
22 def create
43 def create
23 @problem = Problem.new(problem_params)
44 @problem = Problem.new(problem_params)
24 - @description = Description.new(description_params)
25 - if @description.body!=''
26 - if !@description.save
27 - render :action => new and return
28 - end
29 - else
30 - @description = nil
31 - end
32 - @problem.description = @description
33 if @problem.save
45 if @problem.save
34 - flash[:notice] = 'Problem was successfully created.'
46 + redirect_to action: :index, notice: 'Problem was successfully created.'
35 - redirect_to action: :index
36 else
47 else
37 render :action => 'new'
48 render :action => 'new'
38 end
49 end
39 end
50 end
40
51
41 def quick_create
52 def quick_create
42 @problem = Problem.new(problem_params)
53 @problem = Problem.new(problem_params)
43 @problem.full_name = @problem.name if @problem.full_name == ''
54 @problem.full_name = @problem.name if @problem.full_name == ''
44 @problem.full_score = 100
55 @problem.full_score = 100
45 @problem.available = false
56 @problem.available = false
46 @problem.test_allowed = true
57 @problem.test_allowed = true
47 @problem.output_only = false
58 @problem.output_only = false
48 @problem.date_added = Time.new
59 @problem.date_added = Time.new
49 if @problem.save
60 if @problem.save
50 flash[:notice] = 'Problem was successfully created.'
61 flash[:notice] = 'Problem was successfully created.'
51 redirect_to action: :index
62 redirect_to action: :index
52 else
63 else
53 flash[:notice] = 'Error saving problem'
64 flash[:notice] = 'Error saving problem'
54 redirect_to action: :index
65 redirect_to action: :index
55 end
66 end
56 end
67 end
57
68
58 def edit
69 def edit
59 - @problem = Problem.find(params[:id])
60 @description = @problem.description
70 @description = @problem.description
61 end
71 end
62
72
63 def update
73 def update
64 - @problem = Problem.find(params[:id])
74 + if problem_params[:statement] && problem_params[:statement].content_type != 'application/pdf'
65 - @description = @problem.description
75 + flash[:error] = 'Error: Uploaded file is not PDF'
66 - if @description.nil? and params[:description][:body]!=''
76 + render :action => 'edit'
67 - @description = Description.new(description_params)
77 + return
68 - if !@description.save
69 - flash[:notice] = 'Error saving description'
70 - render :action => 'edit' and return
71 - end
72 - @problem.description = @description
73 - elsif @description
74 - if !@description.update(description_params)
75 - flash[:notice] = 'Error saving description'
76 - render :action => 'edit' and return
77 - end
78 - end
79 - if params[:file] and params[:file].content_type != 'application/pdf'
80 - flash[:notice] = 'Error: Uploaded file is not PDF'
81 - render :action => 'edit' and return
82 end
78 end
83 if @problem.update(problem_params)
79 if @problem.update(problem_params)
84 - flash[:notice] = 'Problem was successfully updated.'
80 + flash[:notice] = 'Problem was successfully updated. '
85 - unless params[:file] == nil or params[:file] == ''
81 + flash[:notice] += 'A new statement PDF is uploaded' if problem_params[:statement]
86 - flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
82 + @problem.save
87 - out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
83 + redirect_to edit_problem_path(@problem)
88 - if not FileTest.exists? out_dirname
89 - Dir.mkdir out_dirname
90 - end
91 -
92 - out_filename = "#{out_dirname}/#{@problem.name}.pdf"
93 - if FileTest.exists? out_filename
94 - File.delete out_filename
95 - end
96 -
97 - File.open(out_filename,"wb") do |file|
98 - file.write(params[:file].read)
99 - end
100 - @problem.description_filename = "#{@problem.name}.pdf"
101 - @problem.save
102 - end
103 - redirect_to :action => 'show', :id => @problem
104 else
84 else
105 render :action => 'edit'
85 render :action => 'edit'
106 end
86 end
107 end
87 end
108
88
109 def destroy
89 def destroy
110 - p = Problem.find(params[:id]).destroy
90 + @problem.destroy
111 redirect_to action: :index
91 redirect_to action: :index
112 end
92 end
113
93
114 def toggle
94 def toggle
115 - @problem = Problem.find(params[:id])
116 @problem.update(available: !(@problem.available) )
95 @problem.update(available: !(@problem.available) )
117 respond_to do |format|
96 respond_to do |format|
118 format.js { }
97 format.js { }
119 end
98 end
120 end
99 end
121
100
122 def toggle_test
101 def toggle_test
123 - @problem = Problem.find(params[:id])
124 @problem.update(test_allowed: !(@problem.test_allowed?) )
102 @problem.update(test_allowed: !(@problem.test_allowed?) )
125 respond_to do |format|
103 respond_to do |format|
126 format.js { }
104 format.js { }
127 end
105 end
128 end
106 end
129
107
130 def toggle_view_testcase
108 def toggle_view_testcase
131 - @problem = Problem.find(params[:id])
132 @problem.update(view_testcase: !(@problem.view_testcase?) )
109 @problem.update(view_testcase: !(@problem.view_testcase?) )
133 respond_to do |format|
110 respond_to do |format|
134 format.js { }
111 format.js { }
135 end
112 end
136 end
113 end
137
114
138 def turn_all_off
115 def turn_all_off
139 Problem.available.all.each do |problem|
116 Problem.available.all.each do |problem|
140 problem.available = false
117 problem.available = false
141 problem.save
118 problem.save
142 end
119 end
143 redirect_to action: :index
120 redirect_to action: :index
144 end
121 end
145
122
146 def turn_all_on
123 def turn_all_on
147 Problem.where.not(available: true).each do |problem|
124 Problem.where.not(available: true).each do |problem|
148 problem.available = true
125 problem.available = true
149 problem.save
126 problem.save
150 end
127 end
151 redirect_to action: :index
128 redirect_to action: :index
152 end
129 end
153
130
154 def stat
131 def stat
155 - @problem = Problem.find(params[:id])
156 unless @problem.available or session[:admin]
132 unless @problem.available or session[:admin]
157 redirect_to :controller => 'main', :action => 'list'
133 redirect_to :controller => 'main', :action => 'list'
158 return
134 return
159 end
135 end
160 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
136 @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id)
161
137
162 #stat summary
138 #stat summary
163 range =65
139 range =65
164 @histogram = { data: Array.new(range,0), summary: {} }
140 @histogram = { data: Array.new(range,0), summary: {} }
165 user = Hash.new(0)
141 user = Hash.new(0)
166 @submissions.find_each do |sub|
142 @submissions.find_each do |sub|
167 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
143 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
@@ -286,21 +262,26
286 name, id, order = k.split('-')
262 name, id, order = k.split('-')
287 problems << Problem.find(id)
263 problems << Problem.find(id)
288 end
264 end
289 end
265 end
290 problems
266 problems
291 end
267 end
292
268
293 def get_problems_stat
269 def get_problems_stat
294 end
270 end
295
271
296 private
272 private
297
273
274 + def set_problem
275 + @problem = Problem.find(params[:id])
276 + end
277 +
298 def problem_params
278 def problem_params
299 - params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, :test_allowed,:output_only, :url, :description, tag_ids:[])
279 + params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available,
280 + :test_allowed, :output_only, :url, :description, :statement, :description, tag_ids:[])
300 end
281 end
301
282
302 def description_params
283 def description_params
303 params.require(:description).permit(:body, :markdowned)
284 params.require(:description).permit(:body, :markdowned)
304 end
285 end
305
286
306 end
287 end
@@ -200,13 +200,24
200
200
201 BOOTSTRAP_FLASH_MSG = {
201 BOOTSTRAP_FLASH_MSG = {
202 success: 'alert-success',
202 success: 'alert-success',
203 error: 'alert-danger',
203 error: 'alert-danger',
204 alert: 'alert-danger',
204 alert: 'alert-danger',
205 notice: 'alert-info'
205 notice: 'alert-info'
206 }
206 }
207
207
208 def bootstrap_class_for(flash_type)
208 def bootstrap_class_for(flash_type)
209 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
209 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
210 end
210 end
211
211
212 + def active_class_when(options = {},cname = @active_controller, aname = @active_action)
213 + class_name = ' active '
214 + ok = true
215 + options.each do |k,v|
216 + ok = false if k == :controller && v.to_s != cname
217 + ok = false if k == :action && v.to_s != aname
218 + end
219 + return class_name if ok && options.size > 0
220 + return ''
221 + end
222 +
212 end
223 end
@@ -1,38 +1,42
1 class Problem < ApplicationRecord
1 class Problem < ApplicationRecord
2
2
3 - belongs_to :description
3 + #belongs_to :description
4 +
4 has_and_belongs_to_many :contests, :uniq => true
5 has_and_belongs_to_many :contests, :uniq => true
5
6
6 #has_and_belongs_to_many :groups
7 #has_and_belongs_to_many :groups
7 has_many :groups_problems, class_name: 'GroupProblem'
8 has_many :groups_problems, class_name: 'GroupProblem'
8 has_many :groups, :through => :groups_problems
9 has_many :groups, :through => :groups_problems
9
10
10 has_many :problems_tags, class_name: 'ProblemTag'
11 has_many :problems_tags, class_name: 'ProblemTag'
11 has_many :tags, through: :problems_tags
12 has_many :tags, through: :problems_tags
12
13
13 has_many :test_pairs, :dependent => :delete_all
14 has_many :test_pairs, :dependent => :delete_all
14 has_many :testcases, :dependent => :destroy
15 has_many :testcases, :dependent => :destroy
15
16
16 has_many :submissions
17 has_many :submissions
17
18
18 validates_presence_of :name
19 validates_presence_of :name
19 validates_format_of :name, :with => /\A\w+\z/
20 validates_format_of :name, :with => /\A\w+\z/
20 validates_presence_of :full_name
21 validates_presence_of :full_name
21
22
22 scope :available, -> { where(available: true) }
23 scope :available, -> { where(available: true) }
23
24
24 DEFAULT_TIME_LIMIT = 1
25 DEFAULT_TIME_LIMIT = 1
25 DEFAULT_MEMORY_LIMIT = 32
26 DEFAULT_MEMORY_LIMIT = 32
26
27
28 + has_one_attached :statement
29 + has_many_attached :attachments
30 +
27 def get_jschart_history
31 def get_jschart_history
28 start = 4.month.ago.beginning_of_day
32 start = 4.month.ago.beginning_of_day
29 start_date = start.to_date
33 start_date = start.to_date
30 count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count
34 count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count
31 i = 0
35 i = 0
32 label = []
36 label = []
33 value = []
37 value = []
34 while (start_date + i < Time.zone.now.to_date)
38 while (start_date + i < Time.zone.now.to_date)
35 if (start_date+i).day == 1
39 if (start_date+i).day == 1
36 #label << (start_date+i).strftime("%d %b %Y")
40 #label << (start_date+i).strftime("%d %b %Y")
37 #label << (start_date+i).strftime("%d")
41 #label << (start_date+i).strftime("%d")
38 else
42 else
@@ -2,86 +2,92
2 %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg
2 %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg
3 .container-fluid
3 .container-fluid
4 %a.navbar-brand{href: list_main_path}
4 %a.navbar-brand{href: list_main_path}
5 %span.mi.mi-bs home
5 %span.mi.mi-bs home
6 MAIN
6 MAIN
7 %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} }
7 %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} }
8 %span.navbar-toggler-icon
8 %span.navbar-toggler-icon
9 .collapse.navbar-collapse#navbar-collapse
9 .collapse.navbar-collapse#navbar-collapse
10 %ul.navbar-nav.me-auto.mb-2.mb-lg-0
10 %ul.navbar-nav.me-auto.mb-2.mb-lg-0
11 / submission
11 / submission
12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
13 %li.nav-item.dropdown.mx-2
13 %li.nav-item.dropdown.mx-2
14 - %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"}
14 + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"}
15 = "#{I18n.t 'menu.submissions'}"
15 = "#{I18n.t 'menu.submissions'}"
16 %ul.dropdown-menu
16 %ul.dropdown-menu
17 - %li= link_to 'View', submissions_path, class:'dropdown-item'
17 + %li= link_to 'View', submissions_path, class: 'dropdown-item '+active_class_when(controller: :submissions)
18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
19 / hall of fame
19 / hall of fame
20 - if GraderConfiguration['right.user_hall_of_fame']
20 - if GraderConfiguration['right.user_hall_of_fame']
21 - %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'
21 + %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'+active_class_when(controller: :report, action: :problem_hof)
22 / display MODE button (with countdown in contest mode)
22 / display MODE button (with countdown in contest mode)
23 - if GraderConfiguration.analysis_mode?
23 - if GraderConfiguration.analysis_mode?
24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
25 - elsif GraderConfiguration.time_limit_mode?
25 - elsif GraderConfiguration.time_limit_mode?
26 - if @current_user.contest_finished?
26 - if @current_user.contest_finished?
27 %div.btn.btn-danger#countdown= "Contest is over"
27 %div.btn.btn-danger#countdown= "Contest is over"
28 - elsif !@current_user.contest_started?
28 - elsif !@current_user.contest_started?
29 %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
29 %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
30 - else
30 - else
31 %div.btn.btn-primary#countdown asdf
31 %div.btn.btn-primary#countdown asdf
32 :javascript
32 :javascript
33 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
33 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
34 / admin section
34 / admin section
35 - if (@current_user!=nil) and (session[:admin])
35 - if (@current_user!=nil) and (session[:admin])
36 / management
36 / management
37 %li.nav-item.dropdown.mx-2
37 %li.nav-item.dropdown.mx-2
38 - %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
38 + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
39 Manage
39 Manage
40 %ul.dropdown-menu
40 %ul.dropdown-menu
41 - %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'
41 + %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'+active_class_when(controller: :announcements)
42 - %li= link_to 'Problems', problems_path, class: 'dropdown-item'
42 + %li= link_to 'Problems', problems_path, class: 'dropdown-item'+active_class_when(controller: :problems)
43 - %li= link_to 'Tags', tags_path, class: 'dropdown-item'
43 + %li= link_to 'Tags', tags_path, class: 'dropdown-item'+active_class_when(controller: :tags)
44 - %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'
44 + %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'+active_class_when(controller: :user_admin)
45 - %li= link_to 'User Groups', groups_path, class: 'dropdown-item'
45 + %li= link_to 'User Groups', groups_path, class: 'dropdown-item'+active_class_when(controller: :groups)
46 - %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'
46 + %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'+active_class_when(controller: :graders)
47 - %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'
47 + %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages)
48 %li
48 %li
49 %hr.dropdown-divider
49 %hr.dropdown-divider
50 - %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'
50 + %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'+active_class_when(controller: :grader_configuration)
51 %li
51 %li
52 %hr.dropdown-divider
52 %hr.dropdown-divider
53 - %li= link_to 'Sites', sites_path, class: 'dropdown-item'
53 + %li= link_to 'Sites', sites_path, class: 'dropdown-item'+active_class_when(controller: :sites)
54 - %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'
54 + %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'+active_class_when(controller: :contest_management)
55 -#
55 -#
56 / report
56 / report
57 %li.nav-item.dropdown.mx-2
57 %li.nav-item.dropdown.mx-2
58 - %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
58 + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
59 Report
59 Report
60 %ul.dropdown-menu
60 %ul.dropdown-menu
61 - %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'
61 + %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :current_score)
62 - %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'
62 + %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :max_score)
63 - %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'
63 + %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :submission)
64 - %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'
64 + %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :login)
65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
66 =link_to "#{ungraded} backlogs!",
66 =link_to "#{ungraded} backlogs!",
67 graders_list_path,
67 graders_list_path,
68 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
68 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
69 / announcement
69 / announcement
70 - @nav_announcement.each do |ann|
70 - @nav_announcement.each do |ann|
71 %p.navbar-text
71 %p.navbar-text
72 = ann.body.html_safe
72 = ann.body.html_safe
73 %ul.navbar-nav
73 %ul.navbar-nav
74 %li.nav-item
74 %li.nav-item
75 %a.nav-link{href: help_main_path}
75 %a.nav-link{href: help_main_path}
76 %span.mi.mi-bs.md-18 help
76 %span.mi.mi-bs.md-18 help
77 %li.nav-item
77 %li.nav-item
78 %a.nav-link{href: messages_path}
78 %a.nav-link{href: messages_path}
79 %span.mi.mi-bs.md-18 chat
79 %span.mi.mi-bs.md-18 chat
80 - if GraderConfiguration['system.user_setting_enabled']
80 - if GraderConfiguration['system.user_setting_enabled']
81 %li.nav-item
81 %li.nav-item
82 %a.nav-link{href: profile_users_path}
82 %a.nav-link{href: profile_users_path}
83 %span.mi.mi-bs.md-18 settings
83 %span.mi.mi-bs.md-18 settings
84 %li.nav-item
84 %li.nav-item
85 %a.nav-link{href: login_main_path}
85 %a.nav-link{href: login_main_path}
86 %span.mi.mi-bs.md-18 exit_to_app
86 %span.mi.mi-bs.md-18 exit_to_app
87 = @current_user.full_name
87 = @current_user.full_name
88 + :javascript
89 + $('.active-with-children').each( (index,obj) => {
90 + if ($(obj).siblings('.dropdown-menu').has('.active').length > 0) {
91 + $(obj).addClass('active')
92 + }
93 + } )
@@ -1,55 +1,78
1 - = error_messages_for 'problem'
1 + = simple_form_for problem do |form|
2 - / [form:problem]
2 + .row
3 - .form-group
3 + .col-md-6
4 - %label{:for => "problem_name"} Name
4 + = form.input :name
5 - = text_field 'problem', 'name', class: 'form-control'
5 + = form.input :full_name
6 - %small
6 + = form.input :full_score
7 - Do not directly edit the problem name, unless you know what you are doing. If you want to change the name, use the name change button in the problem management menu instead.
7 + = form.input :tag_ids, collection: Tag.all, class: 'select2'
8 - .form-group
8 + = form.input :date_added
9 - %label{:for => "problem_full_name"} Full name
9 + = form.input :available
10 - = text_field 'problem', 'full_name', class: 'form-control'
10 + = form.input :test_allowed
11 - .form-group
11 + = form.input :output_only
12 - %label{:for => "problem_full_score"} Full score
12 + = form.input :description, as: :text
13 - = text_field 'problem', 'full_score', class: 'form-control'
13 + = form.input :markdown
14 - .form-group
14 + = form.input :url
15 - %label{:for => "problem_full_score"} Tags
15 + = form.input :statement
16 - = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'})
16 + %p
17 - .form-group
17 + - if @problem.statement.attached?
18 - %label{:for => "problem_date_added"} Date added
18 + %a{href: get_statement_problem_path(@problem)} [Download current Statement]
19 - = date_select 'problem', 'date_added', class: 'form-control'
19 + - else
20 - - # TODO: these should be put in model Problem, but I can't think of
20 + no statement attached to this problem
21 - - # nice default values for them. These values look fine only
21 + = form.submit :submit, class: 'btn btn-primary'
22 - - # in this case (of lazily adding new problems).
22 + -#
23 - - @problem.available = true if @problem!=nil and @problem.available==nil
23 + = error_messages_for 'problem'
24 - - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil
24 +
25 - - @problem.output_only = false if @problem!=nil and @problem.output_only==nil
25 + / [form:problem]
26 - .checkbox
26 + .form-group
27 - %label{:for => "problem_available"}
27 + %label{:for => "problem_name"} Name
28 - = check_box :problem, :available
28 + = text_field 'problem', 'name', class: 'form-control'
29 - Available?
29 + %small
30 - .checkbox
30 + Do not directly edit the problem name, unless you know what you are doing. If you want to change the name, use the name change button in the problem management menu instead.
31 - %label{:for => "problem_test_allowed"}
31 + .form-group
32 - = check_box :problem, :test_allowed
32 + %label{:for => "problem_full_name"} Full name
33 - Test allowed?
33 + = text_field 'problem', 'full_name', class: 'form-control'
34 - .checkbox
34 + .form-group
35 - %label{:for => "problem_output_only"}
35 + %label{:for => "problem_full_score"} Full score
36 - = check_box :problem, :output_only
36 + = text_field 'problem', 'full_score', class: 'form-control'
37 - Output only?
37 + .form-group
38 - = error_messages_for 'description'
38 + %label{:for => "problem_full_score"} Tags
39 - .form-group
39 + = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'})
40 - %label{:for => "description_body"} Description
40 + .form-group
41 - %br/
41 + %label{:for => "problem_date_added"} Date added
42 - = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control'
42 + = date_select 'problem', 'date_added', class: 'form-control'
43 - .form-group
43 + - # TODO: these should be put in model Problem, but I can't think of
44 - %label{:for => "description_markdowned"} Markdowned?
44 + - # nice default values for them. These values look fine only
45 - = select "description", |
45 + - # in this case (of lazily adding new problems).
46 - "markdowned", |
46 + - @problem.available = true if @problem!=nil and @problem.available==nil
47 - [['True',true],['False',false]], |
47 + - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil
48 - {:selected => (@description) ? @description.markdowned : false } |
48 + - @problem.output_only = false if @problem!=nil and @problem.output_only==nil
49 - .form-group
49 + .checkbox
50 - %label{:for => "problem_url"} URL
50 + %label{:for => "problem_available"}
51 - %br/
51 + = check_box :problem, :available
52 - = text_field 'problem', 'url',class: 'form-control'
52 + Available?
53 - %p
53 + .checkbox
54 - Task PDF #{file_field_tag 'file'}
54 + %label{:for => "problem_test_allowed"}
55 - / [eoform:problem]
55 + = check_box :problem, :test_allowed
56 + Test allowed?
57 + .checkbox
58 + %label{:for => "problem_output_only"}
59 + = check_box :problem, :output_only
60 + Output only?
61 + = error_messages_for 'description'
62 + .form-group
63 + %label{:for => "description_body"} Description
64 + %br/
65 + = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control'
66 + .form-group
67 + %label{:for => "description_markdowned"} Markdowned?
68 + = select "description", |
69 + "markdowned", |
70 + [['True',true],['False',false]], |
71 + {:selected => (@description) ? @description.markdowned : false } |
72 + .form-group
73 + %label{:for => "problem_url"} URL
74 + %br/
75 + = text_field 'problem', 'url',class: 'form-control'
76 + %p
77 + Task PDF #{file_field_tag 'file'}
78 + / [eoform:problem]
@@ -1,14 +1,6
1 - .container-fluid
1 + %h1 Editing Problem
2 - = form_for @problem,url:{action: 'update'},html: {multipart: true} do
2 +
3 - .row
3 + = render 'form', problem: @problem
4 - .col-md-6
4 + .row.my-3
5 - %h1 Editing problem
5 + .col-md-4
6 - = render :partial => 'form'
6 + = link_to 'Back', problems_path, class: 'btn btn-secondary'
7 - .row
8 - .col-md-4
9 - = submit_tag 'Edit', class: 'btn btn-primary btn-block'
10 - .col-md-4
11 - = link_to 'Show', {:action => 'show', :id => @problem}, class: 'btn btn-default btn-block'
12 - .col-md-4
13 - = link_to 'Back', problems_path, class: 'btn btn-default btn-block'
14 - .div{style: 'height: 5em'}
@@ -28,38 +28,40
28 %th Date added
28 %th Date added
29 %th.text-center
29 %th.text-center
30 Avail?
30 Avail?
31 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?]
31 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?]
32 %th.text-center
32 %th.text-center
33 View Data?
33 View Data?
34 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?]
34 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?]
35 %th.text-center
35 %th.text-center
36 Test?
36 Test?
37 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?]
37 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?]
38 - if GraderConfiguration.multicontests?
38 - if GraderConfiguration.multicontests?
39 %th Contests
39 %th Contests
40 + %th.text-center
41 + %th.text-center
42 + %th.text-center
40 - for problem in @problems
43 - for problem in @problems
41 %tr{:class => "#{(problem.available) ? "bg-success bg-opacity-25" : "bg-opacity-25"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
44 %tr{:class => "#{(problem.available) ? "bg-success bg-opacity-25" : "bg-opacity-25"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
42 - @problem=problem
45 - @problem=problem
43 %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1
46 %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1
44 %td
47 %td
45 = problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
48 = problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
46 = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem
49 = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem
47 %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1
50 %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1
48 %td
51 %td
49 - problem.tags.each do |t|
52 - problem.tags.each do |t|
50 - #%button.btn.btn-default.btn-sm= t.name
53 - #%button.btn.btn-default.btn-sm= t.name
51 %span.label.label-default= t.name
54 %span.label.label-default= t.name
52 %td= link_to "Submit", direct_edit_problem_submissions_path(problem,@current_user.id), class: 'btn btn-sm btn-primary'
55 %td= link_to "Submit", direct_edit_problem_submissions_path(problem,@current_user.id), class: 'btn btn-sm btn-primary'
53 %td= problem.date_added
56 %td= problem.date_added
54 %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}")
57 %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}")
55 %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}")
58 %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}")
56 %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}")
59 %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}")
57 - if GraderConfiguration.multicontests?
60 - if GraderConfiguration.multicontests?
58 %td
61 %td
59 = problem.contests.collect { |c| c.name }.join(', ')
62 = problem.contests.collect { |c| c.name }.join(', ')
60 %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-sm btn-block'
63 %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-sm btn-block'
61 - %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-info btn-sm btn-block'
62 %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-sm btn-block'
64 %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-sm btn-block'
63 %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-sm btn-block'
65 %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-sm btn-block'
64 %br/
66 %br/
65 = link_to '[New problem]', :action => 'new'
67 = link_to '[New problem]', :action => 'new'
@@ -103,25 +103,25
103 # defaulting to :span.
103 # defaulting to :span.
104 # config.item_wrapper_tag = :span
104 # config.item_wrapper_tag = :span
105
105
106 # You can define a class to use in all item wrappers. Defaulting to none.
106 # You can define a class to use in all item wrappers. Defaulting to none.
107 # config.item_wrapper_class = nil
107 # config.item_wrapper_class = nil
108
108
109 # How the label text should be generated altogether with the required text.
109 # How the label text should be generated altogether with the required text.
110 # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
110 # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" }
111
111
112 # You can define the class to use on all labels. Default is nil.
112 # You can define the class to use on all labels. Default is nil.
113 # config.label_class = nil
113 # config.label_class = nil
114
114
115 - # You can define the default class to be used on forms. Can be overriden
115 + # You can define the default class to be used on forms. Can be overridden
116 # with `html: { :class }`. Defaulting to none.
116 # with `html: { :class }`. Defaulting to none.
117 # config.default_form_class = nil
117 # config.default_form_class = nil
118
118
119 # You can define which elements should obtain additional classes
119 # You can define which elements should obtain additional classes
120 # config.generate_additional_classes_for = [:wrapper, :label, :input]
120 # config.generate_additional_classes_for = [:wrapper, :label, :input]
121
121
122 # Whether attributes are required by default (or not). Default is true.
122 # Whether attributes are required by default (or not). Default is true.
123 # config.required_by_default = true
123 # config.required_by_default = true
124
124
125 # Tell browsers whether to use the native HTML5 validations (novalidate form option).
125 # Tell browsers whether to use the native HTML5 validations (novalidate form option).
126 # These validations are enabled in SimpleForm's internal config but disabled by default
126 # These validations are enabled in SimpleForm's internal config but disabled by default
127 # in this configuration, which is recommended due to some quirks from different browsers.
127 # in this configuration, which is recommended due to some quirks from different browsers.
@@ -1,19 +1,17
1 # frozen_string_literal: true
1 # frozen_string_literal: true
2
2
3 - # Please do not make direct changes to this file!
3 + # These defaults are defined and maintained by the community at
4 - # This generator is maintained by the community around simple_form-bootstrap:
4 + # https://github.com/heartcombo/simple_form-bootstrap
5 - # https://github.com/rafaelfranca/simple_form-bootstrap
5 + # Please submit feedback, changes and tests only there.
6 - # All future development, tests, and organization should happen there.
7 - # Background history: https://github.com/heartcombo/simple_form/issues/1561
8
6
9 # Uncomment this and change the path if necessary to include your own
7 # Uncomment this and change the path if necessary to include your own
10 # components.
8 # components.
11 # See https://github.com/heartcombo/simple_form#custom-components
9 # See https://github.com/heartcombo/simple_form#custom-components
12 # to know more about custom components.
10 # to know more about custom components.
13 # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
11 # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f }
14
12
15 # Use this setup block to configure all options available in SimpleForm.
13 # Use this setup block to configure all options available in SimpleForm.
16 SimpleForm.setup do |config|
14 SimpleForm.setup do |config|
17 # Default class for buttons
15 # Default class for buttons
18 config.button_class = 'btn'
16 config.button_class = 'btn'
19
17
@@ -34,407 +32,341
34 config.include_default_input_wrapper_class = false
32 config.include_default_input_wrapper_class = false
35
33
36 # CSS class to add for error notification helper.
34 # CSS class to add for error notification helper.
37 config.error_notification_class = 'alert alert-danger'
35 config.error_notification_class = 'alert alert-danger'
38
36
39 # Method used to tidy up errors. Specify any Rails Array method.
37 # Method used to tidy up errors. Specify any Rails Array method.
40 # :first lists the first message for each field.
38 # :first lists the first message for each field.
41 # :to_sentence to list all errors for each field.
39 # :to_sentence to list all errors for each field.
42 config.error_method = :to_sentence
40 config.error_method = :to_sentence
43
41
44 # add validation classes to `input_field`
42 # add validation classes to `input_field`
45 config.input_field_error_class = 'is-invalid'
43 config.input_field_error_class = 'is-invalid'
46 - config.input_field_valid_class = 'is-valid'
44 + config.input_field_valid_class = 'is-valid-xxx'
47
45
48
46
49 # vertical forms
47 # vertical forms
50 #
48 #
51 # vertical default_wrapper
49 # vertical default_wrapper
52 - config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
50 + config.wrappers :vertical_form, class: 'mb-3' do |b|
53 b.use :html5
51 b.use :html5
54 b.use :placeholder
52 b.use :placeholder
55 b.optional :maxlength
53 b.optional :maxlength
56 b.optional :minlength
54 b.optional :minlength
57 b.optional :pattern
55 b.optional :pattern
58 b.optional :min_max
56 b.optional :min_max
59 b.optional :readonly
57 b.optional :readonly
60 - b.use :label
58 + b.use :label, class: 'form-label'
61 - b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
59 + b.use :input, class: 'form-control', error_class: 'is-invalid'
62 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
60 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
63 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
61 + b.use :hint, wrap_with: { class: 'form-text' }
64 end
62 end
65
63
66 # vertical input for boolean
64 # vertical input for boolean
67 - config.wrappers :vertical_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
65 + config.wrappers :vertical_boolean, tag: 'fieldset', class: 'mb-3' do |b|
68 b.use :html5
66 b.use :html5
69 b.optional :readonly
67 b.optional :readonly
70 - b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
68 + b.wrapper :form_check_wrapper, class: 'form-check' do |bb|
71 - bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
69 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
72 bb.use :label, class: 'form-check-label'
70 bb.use :label, class: 'form-check-label'
73 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
71 + bb.use :full_error, wrap_with: { class: 'invalid-feedback' }
74 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
72 + bb.use :hint, wrap_with: { class: 'form-text' }
75 end
73 end
76 end
74 end
77
75
78 # vertical input for radio buttons and check boxes
76 # vertical input for radio buttons and check boxes
79 - config.wrappers :vertical_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
77 + config.wrappers :vertical_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'fieldset', class: 'mb-3' do |b|
80 b.use :html5
78 b.use :html5
81 b.optional :readonly
79 b.optional :readonly
82 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
80 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
83 ba.use :label_text
81 ba.use :label_text
84 end
82 end
85 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
83 + b.use :input, class: 'form-check-input', error_class: 'is-invalid'
86 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
84 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
87 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
85 + b.use :hint, wrap_with: { class: 'form-text' }
88 end
86 end
89
87
90 # vertical input for inline radio buttons and check boxes
88 # vertical input for inline radio buttons and check boxes
91 - config.wrappers :vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
89 + config.wrappers :vertical_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'fieldset', class: 'mb-3' do |b|
92 b.use :html5
90 b.use :html5
93 b.optional :readonly
91 b.optional :readonly
94 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
92 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
95 ba.use :label_text
93 ba.use :label_text
96 end
94 end
97 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
95 + b.use :input, class: 'form-check-input', error_class: 'is-invalid'
98 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
96 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
99 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
97 + b.use :hint, wrap_with: { class: 'form-text' }
100 end
98 end
101
99
102 # vertical file input
100 # vertical file input
103 - config.wrappers :vertical_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
101 + config.wrappers :vertical_file, class: 'mb-3' do |b|
104 b.use :html5
102 b.use :html5
105 b.use :placeholder
103 b.use :placeholder
106 b.optional :maxlength
104 b.optional :maxlength
107 b.optional :minlength
105 b.optional :minlength
108 b.optional :readonly
106 b.optional :readonly
109 - b.use :label
107 + b.use :label, class: 'form-label'
110 - b.use :input, class: 'form-control-file', error_class: 'is-invalid', valid_class: 'is-valid'
108 + b.use :input, class: 'form-control', error_class: 'is-invalid'
111 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
109 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
112 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
110 + b.use :hint, wrap_with: { class: 'form-text' }
111 + end
112 +
113 + # vertical select input
114 + config.wrappers :vertical_select, class: 'mb-3' do |b|
115 + b.use :html5
116 + b.optional :readonly
117 + b.use :label, class: 'form-label'
118 + b.use :input, class: 'form-select', error_class: 'is-invalid'
119 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
120 + b.use :hint, wrap_with: { class: 'form-text' }
113 end
121 end
114
122
115 # vertical multi select
123 # vertical multi select
116 - config.wrappers :vertical_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
124 + config.wrappers :vertical_multi_select, class: 'mb-3' do |b|
117 b.use :html5
125 b.use :html5
118 b.optional :readonly
126 b.optional :readonly
119 - b.use :label
127 + b.use :label, class: 'form-label'
120 - b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
128 + b.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
121 - ba.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
129 + ba.use :input, class: 'form-select mx-1', error_class: 'is-invalid'
122 end
130 end
123 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
131 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
124 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
132 + b.use :hint, wrap_with: { class: 'form-text' }
125 end
133 end
126
134
127 # vertical range input
135 # vertical range input
128 - config.wrappers :vertical_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
136 + config.wrappers :vertical_range, class: 'mb-3' do |b|
129 b.use :html5
137 b.use :html5
130 b.use :placeholder
138 b.use :placeholder
131 b.optional :readonly
139 b.optional :readonly
132 b.optional :step
140 b.optional :step
133 - b.use :label
141 + b.use :label, class: 'form-label'
134 - b.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
142 + b.use :input, class: 'form-range', error_class: 'is-invalid'
135 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
143 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
136 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
144 + b.use :hint, wrap_with: { class: 'form-text' }
137 end
145 end
138
146
139
147
140 # horizontal forms
148 # horizontal forms
141 #
149 #
142 # horizontal default_wrapper
150 # horizontal default_wrapper
143 - config.wrappers :horizontal_form, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
151 + config.wrappers :horizontal_form, class: 'row mb-3' do |b|
144 b.use :html5
152 b.use :html5
145 b.use :placeholder
153 b.use :placeholder
146 b.optional :maxlength
154 b.optional :maxlength
147 b.optional :minlength
155 b.optional :minlength
148 b.optional :pattern
156 b.optional :pattern
149 b.optional :min_max
157 b.optional :min_max
150 b.optional :readonly
158 b.optional :readonly
151 b.use :label, class: 'col-sm-3 col-form-label'
159 b.use :label, class: 'col-sm-3 col-form-label'
152 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
160 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
153 - ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
161 + ba.use :input, class: 'form-control', error_class: 'is-invalid'
154 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
162 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
155 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
163 + ba.use :hint, wrap_with: { class: 'form-text' }
156 end
164 end
157 end
165 end
158
166
159 # horizontal input for boolean
167 # horizontal input for boolean
160 - config.wrappers :horizontal_boolean, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
168 + config.wrappers :horizontal_boolean, class: 'row mb-3' do |b|
161 b.use :html5
169 b.use :html5
162 b.optional :readonly
170 b.optional :readonly
163 - b.wrapper tag: 'label', class: 'col-sm-3' do |ba|
171 + b.wrapper :grid_wrapper, class: 'col-sm-9 offset-sm-3' do |wr|
164 - ba.use :label_text
172 + wr.wrapper :form_check_wrapper, class: 'form-check' do |bb|
165 - end
173 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
166 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |wr|
167 - wr.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
168 - bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
169 bb.use :label, class: 'form-check-label'
174 bb.use :label, class: 'form-check-label'
170 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
175 + bb.use :full_error, wrap_with: { class: 'invalid-feedback' }
171 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
176 + bb.use :hint, wrap_with: { class: 'form-text' }
172 end
177 end
173 end
178 end
174 end
179 end
175
180
176 # horizontal input for radio buttons and check boxes
181 # horizontal input for radio buttons and check boxes
177 - config.wrappers :horizontal_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
182 + config.wrappers :horizontal_collection, item_wrapper_class: 'form-check', item_label_class: 'form-check-label', class: 'row mb-3' do |b|
178 b.use :html5
183 b.use :html5
179 b.optional :readonly
184 b.optional :readonly
180 b.use :label, class: 'col-sm-3 col-form-label pt-0'
185 b.use :label, class: 'col-sm-3 col-form-label pt-0'
181 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
186 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
182 - ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
187 + ba.use :input, class: 'form-check-input', error_class: 'is-invalid'
183 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
188 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
184 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
189 + ba.use :hint, wrap_with: { class: 'form-text' }
185 end
190 end
186 end
191 end
187
192
188 # horizontal input for inline radio buttons and check boxes
193 # horizontal input for inline radio buttons and check boxes
189 - config.wrappers :horizontal_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
194 + config.wrappers :horizontal_collection_inline, item_wrapper_class: 'form-check form-check-inline', item_label_class: 'form-check-label', class: 'row mb-3' do |b|
190 b.use :html5
195 b.use :html5
191 b.optional :readonly
196 b.optional :readonly
192 b.use :label, class: 'col-sm-3 col-form-label pt-0'
197 b.use :label, class: 'col-sm-3 col-form-label pt-0'
193 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
198 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
194 - ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
199 + ba.use :input, class: 'form-check-input', error_class: 'is-invalid'
195 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
200 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
196 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
201 + ba.use :hint, wrap_with: { class: 'form-text' }
197 end
202 end
198 end
203 end
199
204
200 # horizontal file input
205 # horizontal file input
201 - config.wrappers :horizontal_file, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
206 + config.wrappers :horizontal_file, class: 'row mb-3' do |b|
202 b.use :html5
207 b.use :html5
203 b.use :placeholder
208 b.use :placeholder
204 b.optional :maxlength
209 b.optional :maxlength
205 b.optional :minlength
210 b.optional :minlength
206 b.optional :readonly
211 b.optional :readonly
207 b.use :label, class: 'col-sm-3 col-form-label'
212 b.use :label, class: 'col-sm-3 col-form-label'
208 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
213 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
209 - ba.use :input, error_class: 'is-invalid', valid_class: 'is-valid'
214 + ba.use :input, class: 'form-control', error_class: 'is-invalid'
210 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
215 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
211 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
216 + ba.use :hint, wrap_with: { class: 'form-text' }
217 + end
218 + end
219 +
220 + # horizontal select input
221 + config.wrappers :horizontal_select, class: 'row mb-3' do |b|
222 + b.use :html5
223 + b.optional :readonly
224 + b.use :label, class: 'col-sm-3 col-form-label'
225 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
226 + ba.use :input, class: 'form-select', error_class: 'is-invalid'
227 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
228 + ba.use :hint, wrap_with: { class: 'form-text' }
212 end
229 end
213 end
230 end
214
231
215 # horizontal multi select
232 # horizontal multi select
216 - config.wrappers :horizontal_multi_select, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
233 + config.wrappers :horizontal_multi_select, class: 'row mb-3' do |b|
217 b.use :html5
234 b.use :html5
218 b.optional :readonly
235 b.optional :readonly
219 b.use :label, class: 'col-sm-3 col-form-label'
236 b.use :label, class: 'col-sm-3 col-form-label'
220 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
237 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
221 - ba.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |bb|
238 + ba.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |bb|
222 - bb.use :input, class: 'form-control mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
239 + bb.use :input, class: 'form-select mx-1', error_class: 'is-invalid'
223 end
240 end
224 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
241 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
225 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
242 + ba.use :hint, wrap_with: { class: 'form-text' }
226 end
243 end
227 end
244 end
228
245
229 # horizontal range input
246 # horizontal range input
230 - config.wrappers :horizontal_range, tag: 'div', class: 'form-group row', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
247 + config.wrappers :horizontal_range, class: 'row mb-3' do |b|
231 b.use :html5
248 b.use :html5
232 b.use :placeholder
249 b.use :placeholder
233 b.optional :readonly
250 b.optional :readonly
234 b.optional :step
251 b.optional :step
235 - b.use :label, class: 'col-sm-3 col-form-label'
252 + b.use :label, class: 'col-sm-3 col-form-label pt-0'
236 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
253 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
237 - ba.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
254 + ba.use :input, class: 'form-range', error_class: 'is-invalid'
238 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
255 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
239 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
256 + ba.use :hint, wrap_with: { class: 'form-text' }
240 end
257 end
241 end
258 end
242
259
243
260
244 # inline forms
261 # inline forms
245 #
262 #
246 # inline default_wrapper
263 # inline default_wrapper
247 - config.wrappers :inline_form, tag: 'span', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
264 + config.wrappers :inline_form, class: 'col-12' do |b|
248 b.use :html5
265 b.use :html5
249 b.use :placeholder
266 b.use :placeholder
250 b.optional :maxlength
267 b.optional :maxlength
251 b.optional :minlength
268 b.optional :minlength
252 b.optional :pattern
269 b.optional :pattern
253 b.optional :min_max
270 b.optional :min_max
254 b.optional :readonly
271 b.optional :readonly
255 - b.use :label, class: 'sr-only'
272 + b.use :label, class: 'visually-hidden'
256
273
257 - b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
274 + b.use :input, class: 'form-control', error_class: 'is-invalid'
258 - b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
275 + b.use :error, wrap_with: { class: 'invalid-feedback' }
259 - b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
276 + b.optional :hint, wrap_with: { class: 'form-text' }
260 end
277 end
261
278
262 # inline input for boolean
279 # inline input for boolean
263 - config.wrappers :inline_boolean, tag: 'span', class: 'form-check mb-2 mr-sm-2', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
280 + config.wrappers :inline_boolean, class: 'col-12' do |b|
264 b.use :html5
281 b.use :html5
265 b.optional :readonly
282 b.optional :readonly
266 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
283 + b.wrapper :form_check_wrapper, class: 'form-check' do |bb|
267 - b.use :label, class: 'form-check-label'
284 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
268 - b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
285 + bb.use :label, class: 'form-check-label'
269 - b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
286 + bb.use :error, wrap_with: { class: 'invalid-feedback' }
287 + bb.optional :hint, wrap_with: { class: 'form-text' }
288 + end
270 end
289 end
271
290
272
291
273 # bootstrap custom forms
292 # bootstrap custom forms
274 #
293 #
275 - # custom input for boolean
276 - config.wrappers :custom_boolean, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
277 - b.use :html5
278 - b.optional :readonly
279 - b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-checkbox' do |bb|
280 - bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
281 - bb.use :label, class: 'custom-control-label'
282 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
283 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
284 - end
285 - end
286 -
287 # custom input switch for boolean
294 # custom input switch for boolean
288 - config.wrappers :custom_boolean_switch, tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
295 + config.wrappers :custom_boolean_switch, class: 'mb-3' do |b|
289 - b.use :html5
290 - b.optional :readonly
291 - b.wrapper :form_check_wrapper, tag: 'div', class: 'custom-control custom-switch' do |bb|
292 - bb.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
293 - bb.use :label, class: 'custom-control-label'
294 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
295 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
296 - end
297 - end
298 -
299 - # custom input for radio buttons and check boxes
300 - config.wrappers :custom_collection, item_wrapper_class: 'custom-control', item_label_class: 'custom-control-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
301 - b.use :html5
302 - b.optional :readonly
303 - b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
304 - ba.use :label_text
305 - end
306 - b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
307 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
308 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
309 - end
310 -
311 - # custom input for inline radio buttons and check boxes
312 - config.wrappers :custom_collection_inline, item_wrapper_class: 'custom-control custom-control-inline', item_label_class: 'custom-control-label', tag: 'fieldset', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
313 b.use :html5
296 b.use :html5
314 b.optional :readonly
297 b.optional :readonly
315 - b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
298 + b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check form-switch' do |bb|
316 - ba.use :label_text
299 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
317 - end
300 + bb.use :label, class: 'form-check-label'
318 - b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
301 + bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
319 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
302 + bb.use :hint, wrap_with: { class: 'form-text' }
320 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
321 - end
322 -
323 - # custom file input
324 - config.wrappers :custom_file, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
325 - b.use :html5
326 - b.use :placeholder
327 - b.optional :maxlength
328 - b.optional :minlength
329 - b.optional :readonly
330 - b.use :label
331 - b.wrapper :custom_file_wrapper, tag: 'div', class: 'custom-file' do |ba|
332 - ba.use :input, class: 'custom-file-input', error_class: 'is-invalid', valid_class: 'is-valid'
333 - ba.use :label, class: 'custom-file-label'
334 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
335 end
303 end
336 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
337 - end
338 -
339 - # custom multi select
340 - config.wrappers :custom_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
341 - b.use :html5
342 - b.optional :readonly
343 - b.use :label
344 - b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
345 - ba.use :input, class: 'custom-select mx-1', error_class: 'is-invalid', valid_class: 'is-valid'
346 - end
347 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
348 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
349 - end
350 -
351 - # custom range input
352 - config.wrappers :custom_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
353 - b.use :html5
354 - b.use :placeholder
355 - b.optional :readonly
356 - b.optional :step
357 - b.use :label
358 - b.use :input, class: 'custom-range', error_class: 'is-invalid', valid_class: 'is-valid'
359 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
360 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
361 end
304 end
362
305
363
306
364 # Input Group - custom component
307 # Input Group - custom component
365 - # see example app and config at https://github.com/rafaelfranca/simple_form-bootstrap
308 + # see example app and config at https://github.com/heartcombo/simple_form-bootstrap
366 - # config.wrappers :input_group, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
309 + config.wrappers :input_group, class: 'mb-3' do |b|
367 - # b.use :html5
368 - # b.use :placeholder
369 - # b.optional :maxlength
370 - # b.optional :minlength
371 - # b.optional :pattern
372 - # b.optional :min_max
373 - # b.optional :readonly
374 - # b.use :label
375 - # b.wrapper :input_group_tag, tag: 'div', class: 'input-group' do |ba|
376 - # ba.optional :prepend
377 - # ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
378 - # ba.optional :append
379 - # end
380 - # b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
381 - # b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
382 - # end
383 -
384 -
385 - # Floating Labels form
386 - #
387 - # floating labels default_wrapper
388 - config.wrappers :floating_labels_form, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
389 b.use :html5
310 b.use :html5
390 b.use :placeholder
311 b.use :placeholder
391 b.optional :maxlength
312 b.optional :maxlength
392 b.optional :minlength
313 b.optional :minlength
393 b.optional :pattern
314 b.optional :pattern
394 b.optional :min_max
315 b.optional :min_max
395 b.optional :readonly
316 b.optional :readonly
396 - b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
317 + b.use :label, class: 'form-label'
318 + b.wrapper :input_group_tag, class: 'input-group' do |ba|
319 + ba.optional :prepend
320 + ba.use :input, class: 'form-control', error_class: 'is-invalid'
321 + ba.optional :append
322 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
323 + end
324 + b.use :hint, wrap_with: { class: 'form-text' }
325 + end
326 +
327 +
328 + # Floating Labels form
329 + #
330 + # floating labels default_wrapper
331 + config.wrappers :floating_labels_form, class: 'form-floating mb-3' do |b|
332 + b.use :html5
333 + b.use :placeholder
334 + b.optional :maxlength
335 + b.optional :minlength
336 + b.optional :pattern
337 + b.optional :min_max
338 + b.optional :readonly
339 + b.use :input, class: 'form-control', error_class: 'is-invalid'
397 b.use :label
340 b.use :label
398 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
341 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
399 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
342 + b.use :hint, wrap_with: { class: 'form-text' }
400 end
343 end
401
344
402 # custom multi select
345 # custom multi select
403 - config.wrappers :floating_labels_select, tag: 'div', class: 'form-label-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b|
346 + config.wrappers :floating_labels_select, class: 'form-floating mb-3' do |b|
404 b.use :html5
347 b.use :html5
405 b.optional :readonly
348 b.optional :readonly
406 - b.use :input, class: 'custom-select', error_class: 'is-invalid', valid_class: 'is-valid'
349 + b.use :input, class: 'form-select', error_class: 'is-invalid'
407 b.use :label
350 b.use :label
408 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
351 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
409 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
352 + b.use :hint, wrap_with: { class: 'form-text' }
410 end
353 end
411
354
412
355
413 # The default wrapper to be used by the FormBuilder.
356 # The default wrapper to be used by the FormBuilder.
414 config.default_wrapper = :vertical_form
357 config.default_wrapper = :vertical_form
415
358
416 # Custom wrappers for input types. This should be a hash containing an input
359 # Custom wrappers for input types. This should be a hash containing an input
417 # type as key and the wrapper that will be used for all inputs with specified type.
360 # type as key and the wrapper that will be used for all inputs with specified type.
418 config.wrapper_mappings = {
361 config.wrapper_mappings = {
419 boolean: :vertical_boolean,
362 boolean: :vertical_boolean,
420 check_boxes: :vertical_collection,
363 check_boxes: :vertical_collection,
421 date: :vertical_multi_select,
364 date: :vertical_multi_select,
422 datetime: :vertical_multi_select,
365 datetime: :vertical_multi_select,
423 file: :vertical_file,
366 file: :vertical_file,
424 radio_buttons: :vertical_collection,
367 radio_buttons: :vertical_collection,
425 range: :vertical_range,
368 range: :vertical_range,
426 - time: :vertical_multi_select
369 + time: :vertical_multi_select,
370 + select: :vertical_select
427 }
371 }
428 -
429 - # enable custom form wrappers
430 - # config.wrapper_mappings = {
431 - # boolean: :custom_boolean,
432 - # check_boxes: :custom_collection,
433 - # date: :custom_multi_select,
434 - # datetime: :custom_multi_select,
435 - # file: :custom_file,
436 - # radio_buttons: :custom_collection,
437 - # range: :custom_range,
438 - # time: :custom_multi_select
439 - # }
440 end
372 end
@@ -25,24 +25,25
25 resources :announcements do
25 resources :announcements do
26 member do
26 member do
27 get 'toggle','toggle_front'
27 get 'toggle','toggle_front'
28 end
28 end
29 end
29 end
30
30
31 resources :problems do
31 resources :problems do
32 member do
32 member do
33 get 'toggle'
33 get 'toggle'
34 get 'toggle_test'
34 get 'toggle_test'
35 get 'toggle_view_testcase'
35 get 'toggle_view_testcase'
36 get 'stat'
36 get 'stat'
37 + get 'get_statement'
37 end
38 end
38 collection do
39 collection do
39 get 'turn_all_off'
40 get 'turn_all_off'
40 get 'turn_all_on'
41 get 'turn_all_on'
41 get 'import'
42 get 'import'
42 get 'manage'
43 get 'manage'
43 get 'quick_create'
44 get 'quick_create'
44 post 'do_manage'
45 post 'do_manage'
45 post 'do_import'
46 post 'do_import'
46 end
47 end
47 end
48 end
48
49
@@ -1,79 +1,107
1 # This file is auto-generated from the current state of the database. Instead
1 # This file is auto-generated from the current state of the database. Instead
2 # of editing this file, please use the migrations feature of Active Record to
2 # of editing this file, please use the migrations feature of Active Record to
3 # incrementally modify your database, and then regenerate this schema definition.
3 # incrementally modify your database, and then regenerate this schema definition.
4 #
4 #
5 # This file is the source Rails uses to define your schema when running `bin/rails
5 # This file is the source Rails uses to define your schema when running `bin/rails
6 # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
6 # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to
7 # be faster and is potentially less error prone than running all of your
7 # be faster and is potentially less error prone than running all of your
8 # migrations from scratch. Old migrations may fail to apply correctly if those
8 # migrations from scratch. Old migrations may fail to apply correctly if those
9 # migrations use external dependencies or application code.
9 # migrations use external dependencies or application code.
10 #
10 #
11 # It's strongly recommended that you check this file into your version control system.
11 # It's strongly recommended that you check this file into your version control system.
12
12
13 - ActiveRecord::Schema[7.0].define(version: 2022_02_04_080936) do
13 + ActiveRecord::Schema[7.0].define(version: 2022_09_27_074644) do
14 - create_table "announcements", id: :integer, charset: "utf8", force: :cascade do |t|
14 + create_table "active_storage_attachments", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
15 + t.string "name", null: false
16 + t.string "record_type", null: false
17 + t.bigint "record_id", null: false
18 + t.bigint "blob_id", null: false
19 + t.datetime "created_at", null: false
20 + t.index ["blob_id"], name: "index_active_storage_attachments_on_blob_id"
21 + t.index ["record_type", "record_id", "name", "blob_id"], name: "index_active_storage_attachments_uniqueness", unique: true
22 + end
23 +
24 + create_table "active_storage_blobs", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
25 + t.string "key", null: false
26 + t.string "filename", null: false
27 + t.string "content_type"
28 + t.text "metadata"
29 + t.string "service_name", null: false
30 + t.bigint "byte_size", null: false
31 + t.string "checksum"
32 + t.datetime "created_at", null: false
33 + t.index ["key"], name: "index_active_storage_blobs_on_key", unique: true
34 + end
35 +
36 + create_table "active_storage_variant_records", charset: "utf8mb4", collation: "utf8mb4_0900_ai_ci", force: :cascade do |t|
37 + t.bigint "blob_id", null: false
38 + t.string "variation_digest", null: false
39 + t.index ["blob_id", "variation_digest"], name: "index_active_storage_variant_records_uniqueness", unique: true
40 + end
41 +
42 + create_table "announcements", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
15 t.string "author"
43 t.string "author"
16 - t.text "body", size: :medium
44 + t.text "body"
17 t.boolean "published"
45 t.boolean "published"
18 t.datetime "created_at", precision: nil, null: false
46 t.datetime "created_at", precision: nil, null: false
19 t.datetime "updated_at", precision: nil, null: false
47 t.datetime "updated_at", precision: nil, null: false
20 t.boolean "frontpage", default: false
48 t.boolean "frontpage", default: false
21 t.boolean "contest_only", default: false
49 t.boolean "contest_only", default: false
22 t.string "title"
50 t.string "title"
23 t.string "notes"
51 t.string "notes"
24 t.boolean "on_nav_bar", default: false
52 t.boolean "on_nav_bar", default: false
25 end
53 end
26
54
27 - create_table "contests", id: :integer, charset: "utf8", force: :cascade do |t|
55 + create_table "contests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
28 t.string "title"
56 t.string "title"
29 t.boolean "enabled"
57 t.boolean "enabled"
30 t.datetime "created_at", precision: nil, null: false
58 t.datetime "created_at", precision: nil, null: false
31 t.datetime "updated_at", precision: nil, null: false
59 t.datetime "updated_at", precision: nil, null: false
32 t.string "name"
60 t.string "name"
33 end
61 end
34
62
35 - create_table "contests_problems", id: false, charset: "utf8", force: :cascade do |t|
63 + create_table "contests_problems", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
36 t.integer "contest_id"
64 t.integer "contest_id"
37 t.integer "problem_id"
65 t.integer "problem_id"
38 end
66 end
39
67
40 - create_table "contests_users", id: false, charset: "utf8", force: :cascade do |t|
68 + create_table "contests_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
41 t.integer "contest_id"
69 t.integer "contest_id"
42 t.integer "user_id"
70 t.integer "user_id"
43 end
71 end
44
72
45 - create_table "countries", id: :integer, charset: "utf8", force: :cascade do |t|
73 + create_table "countries", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
46 t.string "name"
74 t.string "name"
47 t.datetime "created_at", precision: nil, null: false
75 t.datetime "created_at", precision: nil, null: false
48 t.datetime "updated_at", precision: nil, null: false
76 t.datetime "updated_at", precision: nil, null: false
49 end
77 end
50
78
51 - create_table "descriptions", id: :integer, charset: "utf8", force: :cascade do |t|
79 + create_table "descriptions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
52 - t.text "body", size: :medium
80 + t.text "body"
53 t.boolean "markdowned"
81 t.boolean "markdowned"
54 t.datetime "created_at", precision: nil, null: false
82 t.datetime "created_at", precision: nil, null: false
55 t.datetime "updated_at", precision: nil, null: false
83 t.datetime "updated_at", precision: nil, null: false
56 end
84 end
57
85
58 - create_table "grader_configurations", id: :integer, charset: "utf8", force: :cascade do |t|
86 + create_table "grader_configurations", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
59 t.string "key"
87 t.string "key"
60 t.string "value_type"
88 t.string "value_type"
61 t.string "value"
89 t.string "value"
62 t.datetime "created_at", precision: nil, null: false
90 t.datetime "created_at", precision: nil, null: false
63 t.datetime "updated_at", precision: nil, null: false
91 t.datetime "updated_at", precision: nil, null: false
64 - t.text "description", size: :medium
92 + t.text "description"
65 end
93 end
66
94
67 - create_table "grader_processes", id: :integer, charset: "utf8", force: :cascade do |t|
95 + create_table "grader_processes", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
68 t.string "host"
96 t.string "host"
69 t.integer "pid"
97 t.integer "pid"
70 t.string "mode"
98 t.string "mode"
71 t.boolean "active"
99 t.boolean "active"
72 t.datetime "created_at", precision: nil, null: false
100 t.datetime "created_at", precision: nil, null: false
73 t.datetime "updated_at", precision: nil, null: false
101 t.datetime "updated_at", precision: nil, null: false
74 t.integer "task_id"
102 t.integer "task_id"
75 t.string "task_type"
103 t.string "task_type"
76 t.boolean "terminated"
104 t.boolean "terminated"
77 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
105 t.index ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
78 end
106 end
79
107
@@ -86,240 +114,233
86 create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t|
114 create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t|
87 t.integer "problem_id", null: false
115 t.integer "problem_id", null: false
88 t.integer "group_id", null: false
116 t.integer "group_id", null: false
89 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
117 t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id"
90 end
118 end
91
119
92 create_table "groups_users", charset: "latin1", force: :cascade do |t|
120 create_table "groups_users", charset: "latin1", force: :cascade do |t|
93 t.integer "group_id", null: false
121 t.integer "group_id", null: false
94 t.integer "user_id", null: false
122 t.integer "user_id", null: false
95 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
123 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
96 end
124 end
97
125
98 - create_table "heart_beats", id: :integer, charset: "latin1", force: :cascade do |t|
126 + create_table "heart_beats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
99 t.integer "user_id"
127 t.integer "user_id"
100 t.string "ip_address"
128 t.string "ip_address"
101 t.datetime "created_at", precision: nil, null: false
129 t.datetime "created_at", precision: nil, null: false
102 t.datetime "updated_at", precision: nil, null: false
130 t.datetime "updated_at", precision: nil, null: false
103 t.string "status"
131 t.string "status"
104 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
132 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
105 end
133 end
106
134
107 - create_table "languages", id: :integer, charset: "utf8", force: :cascade do |t|
135 + create_table "languages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
108 t.string "name", limit: 10
136 t.string "name", limit: 10
109 t.string "pretty_name"
137 t.string "pretty_name"
110 t.string "ext", limit: 10
138 t.string "ext", limit: 10
111 t.string "common_ext"
139 t.string "common_ext"
112 end
140 end
113
141
114 - create_table "logins", id: :integer, charset: "latin1", force: :cascade do |t|
142 + create_table "logins", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
115 t.integer "user_id"
143 t.integer "user_id"
116 t.string "ip_address"
144 t.string "ip_address"
117 t.datetime "created_at", precision: nil, null: false
145 t.datetime "created_at", precision: nil, null: false
118 t.datetime "updated_at", precision: nil, null: false
146 t.datetime "updated_at", precision: nil, null: false
119 t.index ["user_id"], name: "index_logins_on_user_id"
147 t.index ["user_id"], name: "index_logins_on_user_id"
120 end
148 end
121
149
122 - create_table "messages", id: :integer, charset: "utf8", force: :cascade do |t|
150 + create_table "messages", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
123 t.integer "sender_id"
151 t.integer "sender_id"
124 t.integer "receiver_id"
152 t.integer "receiver_id"
125 t.integer "replying_message_id"
153 t.integer "replying_message_id"
126 - t.text "body", size: :medium
154 + t.text "body"
127 t.boolean "replied"
155 t.boolean "replied"
128 t.datetime "created_at", precision: nil, null: false
156 t.datetime "created_at", precision: nil, null: false
129 t.datetime "updated_at", precision: nil, null: false
157 t.datetime "updated_at", precision: nil, null: false
130 end
158 end
131
159
132 - create_table "problems", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
160 + create_table "problems", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
133 - t.string "name", limit: 100
161 + t.string "name", limit: 30
134 t.string "full_name"
162 t.string "full_name"
135 t.integer "full_score"
163 t.integer "full_score"
136 t.date "date_added"
164 t.date "date_added"
137 t.boolean "available"
165 t.boolean "available"
138 t.string "url"
166 t.string "url"
139 t.integer "description_id"
167 t.integer "description_id"
140 t.boolean "test_allowed"
168 t.boolean "test_allowed"
141 t.boolean "output_only"
169 t.boolean "output_only"
142 t.string "description_filename"
170 t.string "description_filename"
143 t.boolean "view_testcase"
171 t.boolean "view_testcase"
144 t.integer "difficulty"
172 t.integer "difficulty"
173 + t.text "description"
174 + t.boolean "markdown"
145 end
175 end
146
176
147 - create_table "problems_tags", id: :bigint, default: nil, charset: "latin1", force: :cascade do |t|
177 + create_table "problems_tags", id: :integer, charset: "latin1", force: :cascade do |t|
148 - t.bigint "problem_id"
178 + t.integer "problem_id"
149 t.integer "tag_id"
179 t.integer "tag_id"
150 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
180 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
151 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
181 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
152 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
182 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
153 end
183 end
154
184
155 - create_table "rights", id: :integer, charset: "utf8", force: :cascade do |t|
185 + create_table "rights", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
156 t.string "name"
186 t.string "name"
157 t.string "controller"
187 t.string "controller"
158 t.string "action"
188 t.string "action"
159 end
189 end
160
190
161 - create_table "rights_roles", id: false, charset: "utf8", force: :cascade do |t|
191 + create_table "rights_roles", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
162 t.integer "right_id"
192 t.integer "right_id"
163 t.integer "role_id"
193 t.integer "role_id"
164 t.index ["role_id"], name: "index_rights_roles_on_role_id"
194 t.index ["role_id"], name: "index_rights_roles_on_role_id"
165 end
195 end
166
196
167 - create_table "roles", id: :integer, charset: "utf8", force: :cascade do |t|
197 + create_table "roles", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
168 t.string "name"
198 t.string "name"
169 end
199 end
170
200
171 - create_table "roles_users", id: false, charset: "utf8", force: :cascade do |t|
201 + create_table "roles_users", id: false, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
172 t.integer "role_id"
202 t.integer "role_id"
173 t.integer "user_id"
203 t.integer "user_id"
174 t.index ["user_id"], name: "index_roles_users_on_user_id"
204 t.index ["user_id"], name: "index_roles_users_on_user_id"
175 end
205 end
176
206
177 - create_table "sessions", id: :integer, charset: "utf8", force: :cascade do |t|
207 + create_table "sessions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
178 t.string "session_id"
208 t.string "session_id"
179 - t.text "data", size: :medium
209 + t.text "data"
180 t.datetime "updated_at", precision: nil
210 t.datetime "updated_at", precision: nil
181 t.index ["session_id"], name: "index_sessions_on_session_id"
211 t.index ["session_id"], name: "index_sessions_on_session_id"
182 t.index ["updated_at"], name: "index_sessions_on_updated_at"
212 t.index ["updated_at"], name: "index_sessions_on_updated_at"
183 end
213 end
184
214
185 - create_table "sites", id: :integer, charset: "utf8", force: :cascade do |t|
215 + create_table "sites", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
186 t.string "name"
216 t.string "name"
187 t.boolean "started"
217 t.boolean "started"
188 t.datetime "start_time", precision: nil
218 t.datetime "start_time", precision: nil
189 t.datetime "created_at", precision: nil, null: false
219 t.datetime "created_at", precision: nil, null: false
190 t.datetime "updated_at", precision: nil, null: false
220 t.datetime "updated_at", precision: nil, null: false
191 t.integer "country_id"
221 t.integer "country_id"
192 t.string "password"
222 t.string "password"
193 end
223 end
194
224
195 - create_table "solutions", charset: "latin1", force: :cascade do |t|
225 + create_table "submission_view_logs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
196 - t.string "solution"
197 - t.bigint "problem_id"
198 - t.bigint "submission_id"
199 - t.integer "type"
200 - t.index ["problem_id"], name: "index_solutions_on_problem_id"
201 - t.index ["submission_id"], name: "index_solutions_on_submission_id"
202 - end
203 -
204 - create_table "submission_view_logs", id: :integer, charset: "latin1", force: :cascade do |t|
205 t.integer "user_id"
226 t.integer "user_id"
206 t.integer "submission_id"
227 t.integer "submission_id"
207 t.datetime "created_at", precision: nil, null: false
228 t.datetime "created_at", precision: nil, null: false
208 t.datetime "updated_at", precision: nil, null: false
229 t.datetime "updated_at", precision: nil, null: false
209 end
230 end
210
231
211 - create_table "submissions", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
232 + create_table "submissions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
212 t.integer "user_id"
233 t.integer "user_id"
213 t.integer "problem_id"
234 t.integer "problem_id"
214 t.integer "language_id"
235 t.integer "language_id"
215 t.text "source", size: :medium
236 t.text "source", size: :medium
216 t.binary "binary"
237 t.binary "binary"
217 t.datetime "submitted_at", precision: nil
238 t.datetime "submitted_at", precision: nil
218 t.datetime "compiled_at", precision: nil
239 t.datetime "compiled_at", precision: nil
219 - t.text "compiler_message", size: :medium
240 + t.text "compiler_message"
220 t.datetime "graded_at", precision: nil
241 t.datetime "graded_at", precision: nil
221 t.integer "points"
242 t.integer "points"
222 - t.text "grader_comment", size: :medium
243 + t.text "grader_comment"
223 t.integer "number"
244 t.integer "number"
224 t.string "source_filename"
245 t.string "source_filename"
225 t.float "max_runtime"
246 t.float "max_runtime"
226 t.integer "peak_memory"
247 t.integer "peak_memory"
227 t.integer "effective_code_length"
248 t.integer "effective_code_length"
228 t.string "ip_address"
249 t.string "ip_address"
229 t.integer "tag", default: 0
250 t.integer "tag", default: 0
230 t.index ["submitted_at"], name: "index_submissions_on_submitted_at"
251 t.index ["submitted_at"], name: "index_submissions_on_submitted_at"
231 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
252 t.index ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
232 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
253 t.index ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
233 end
254 end
234
255
235 create_table "tags", id: :integer, charset: "latin1", force: :cascade do |t|
256 create_table "tags", id: :integer, charset: "latin1", force: :cascade do |t|
236 t.string "name", null: false
257 t.string "name", null: false
237 t.text "description"
258 t.text "description"
238 t.boolean "public"
259 t.boolean "public"
239 t.datetime "created_at", precision: nil, null: false
260 t.datetime "created_at", precision: nil, null: false
240 t.datetime "updated_at", precision: nil, null: false
261 t.datetime "updated_at", precision: nil, null: false
241 end
262 end
242
263
243 - create_table "tasks", id: :integer, charset: "utf8", force: :cascade do |t|
264 + create_table "tasks", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
244 t.integer "submission_id"
265 t.integer "submission_id"
245 t.datetime "created_at", precision: nil
266 t.datetime "created_at", precision: nil
246 t.integer "status"
267 t.integer "status"
247 t.datetime "updated_at", precision: nil
268 t.datetime "updated_at", precision: nil
248 t.index ["status"], name: "index_tasks_on_status"
269 t.index ["status"], name: "index_tasks_on_status"
249 t.index ["submission_id"], name: "index_tasks_on_submission_id"
270 t.index ["submission_id"], name: "index_tasks_on_submission_id"
250 end
271 end
251
272
252 - create_table "test_pairs", id: :integer, charset: "utf8", force: :cascade do |t|
273 + create_table "test_pairs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
253 t.integer "problem_id"
274 t.integer "problem_id"
254 - t.text "input", size: :long
275 + t.text "input", size: :medium
255 - t.text "solution", size: :long
276 + t.text "solution", size: :medium
256 t.datetime "created_at", precision: nil, null: false
277 t.datetime "created_at", precision: nil, null: false
257 t.datetime "updated_at", precision: nil, null: false
278 t.datetime "updated_at", precision: nil, null: false
258 end
279 end
259
280
260 - create_table "test_requests", id: :integer, charset: "utf8", force: :cascade do |t|
281 + create_table "test_requests", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
261 t.integer "user_id"
282 t.integer "user_id"
262 t.integer "problem_id"
283 t.integer "problem_id"
263 t.integer "submission_id"
284 t.integer "submission_id"
264 t.string "input_file_name"
285 t.string "input_file_name"
265 t.string "output_file_name"
286 t.string "output_file_name"
266 t.string "running_stat"
287 t.string "running_stat"
267 t.integer "status"
288 t.integer "status"
268 t.datetime "updated_at", precision: nil, null: false
289 t.datetime "updated_at", precision: nil, null: false
269 t.datetime "submitted_at", precision: nil
290 t.datetime "submitted_at", precision: nil
270 t.datetime "compiled_at", precision: nil
291 t.datetime "compiled_at", precision: nil
271 - t.text "compiler_message", size: :medium
292 + t.text "compiler_message"
272 t.datetime "graded_at", precision: nil
293 t.datetime "graded_at", precision: nil
273 t.string "grader_comment"
294 t.string "grader_comment"
274 t.datetime "created_at", precision: nil, null: false
295 t.datetime "created_at", precision: nil, null: false
275 t.float "running_time"
296 t.float "running_time"
276 t.string "exit_status"
297 t.string "exit_status"
277 t.integer "memory_usage"
298 t.integer "memory_usage"
278 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
299 t.index ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
279 end
300 end
280
301
281 create_table "testcases", id: :integer, charset: "latin1", force: :cascade do |t|
302 create_table "testcases", id: :integer, charset: "latin1", force: :cascade do |t|
282 t.integer "problem_id"
303 t.integer "problem_id"
283 t.integer "num"
304 t.integer "num"
284 t.integer "group"
305 t.integer "group"
285 t.integer "score"
306 t.integer "score"
286 t.text "input", size: :long
307 t.text "input", size: :long
287 t.text "sol", size: :long
308 t.text "sol", size: :long
288 - t.datetime "created_at", precision: nil, null: false
309 + t.datetime "created_at", precision: nil
289 - t.datetime "updated_at", precision: nil, null: false
310 + t.datetime "updated_at", precision: nil
290 t.index ["problem_id"], name: "index_testcases_on_problem_id"
311 t.index ["problem_id"], name: "index_testcases_on_problem_id"
291 end
312 end
292
313
293 - create_table "user_contest_stats", id: :integer, charset: "utf8", force: :cascade do |t|
314 + create_table "user_contest_stats", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
294 t.integer "user_id"
315 t.integer "user_id"
295 t.datetime "started_at", precision: nil
316 t.datetime "started_at", precision: nil
296 t.datetime "created_at", precision: nil, null: false
317 t.datetime "created_at", precision: nil, null: false
297 t.datetime "updated_at", precision: nil, null: false
318 t.datetime "updated_at", precision: nil, null: false
298 t.boolean "forced_logout"
319 t.boolean "forced_logout"
299 end
320 end
300
321
301 - create_table "users", id: :integer, charset: "utf8", force: :cascade do |t|
322 + create_table "users", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
302 t.string "login", limit: 50
323 t.string "login", limit: 50
303 t.string "full_name"
324 t.string "full_name"
304 t.string "hashed_password"
325 t.string "hashed_password"
305 t.string "salt", limit: 5
326 t.string "salt", limit: 5
306 t.string "alias"
327 t.string "alias"
307 t.string "email"
328 t.string "email"
308 t.integer "site_id"
329 t.integer "site_id"
309 t.integer "country_id"
330 t.integer "country_id"
310 t.boolean "activated", default: false
331 t.boolean "activated", default: false
311 t.datetime "created_at", precision: nil
332 t.datetime "created_at", precision: nil
312 t.datetime "updated_at", precision: nil
333 t.datetime "updated_at", precision: nil
313 - t.string "section"
314 t.boolean "enabled", default: true
334 t.boolean "enabled", default: true
315 t.string "remark"
335 t.string "remark"
316 t.string "last_ip"
336 t.string "last_ip"
337 + t.string "section"
317 t.integer "default_language"
338 t.integer "default_language"
318 t.index ["login"], name: "index_users_on_login", unique: true
339 t.index ["login"], name: "index_users_on_login", unique: true
319 end
340 end
320
341
342 + add_foreign_key "active_storage_attachments", "active_storage_blobs", column: "blob_id"
343 + add_foreign_key "active_storage_variant_records", "active_storage_blobs", column: "blob_id"
321 add_foreign_key "problems_tags", "problems"
344 add_foreign_key "problems_tags", "problems"
322 add_foreign_key "problems_tags", "tags"
345 add_foreign_key "problems_tags", "tags"
323 - add_foreign_key "solutions", "problems"
324 - add_foreign_key "solutions", "submissions"
325 end
346 end
deleted file
You need to be logged in to leave comments. Login now