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
@@ -35,3 +35,4
35 35 /config/secrets.yml
36 36
37 37 /.byebug_history
38 + /storage/*
@@ -77,7 +77,8
77 77 #gem 'jquery-datatables-rails'
78 78
79 79 #----------- user interface -----------------
80 - gem 'simple_form'
80 + gem 'simple_form', git: 'https://github.com/heartcombo/simple_form', ref: '31fe255'
81 +
81 82 #select 2
82 83 #gem 'select2-rails'
83 84 #ace editor
@@ -1,3 +1,12
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 10 GIT
2 11 remote: https://github.com/mmotherwell/best_in_place
3 12 revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0
@@ -247,9 +256,6
247 256 rubyzip (>= 1.2.2, < 3.0)
248 257 websocket (~> 1.0)
249 258 sexp_processor (4.16.1)
250 - simple_form (5.1.0)
251 - actionpack (>= 5.2)
252 - activemodel (>= 5.2)
253 259 spring (2.1.1)
254 260 spring-watcher-listen (2.0.1)
255 261 listen (>= 2.7, < 4.0)
@@ -315,7 +321,7
315 321 rouge
316 322 sassc-rails
317 323 selenium-webdriver
318 - simple_form
324 + simple_form!
319 325 spring
320 326 spring-watcher-listen (~> 2.0.0)
321 327 sprockets-rails
@@ -59,10 +59,6
59 59 }
60 60 }
61 61
62 - input {
63 - font-family: Tahoma, "sans-serif";
64 - }
65 -
66 62 h1 {
67 63 color: #334488;
68 64 }
@@ -7,6 +7,7
7 7 before_action :current_user
8 8 before_action :nav_announcement
9 9 before_action :unique_visitor_id
10 + before_action :active_controller_action
10 11
11 12 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
12 13 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
@@ -29,6 +30,12
29 30 @nav_announcement = Announcement.where(on_nav_bar: true)
30 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 39 def admin_authorization
33 40 return false unless check_valid_login
34 41 user = User.includes(:roles).find(session[:user_id])
@@ -1,38 +1,49
1 1 class ProblemsController < ApplicationController
2 2
3 + include ActiveStorage::SetCurrent
4 +
3 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 7 before_action only: [:stat] do
5 8 authorization_by_roles(['admin','ta'])
6 9 end
7 10
11 +
8 12 def index
9 13 @problems = Problem.order(date_added: :desc)
10 14 end
11 15
12 16
13 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 37 end
16 38
17 39 def new
18 40 @problem = Problem.new
19 - @description = nil
20 41 end
21 42
22 43 def create
23 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 45 if @problem.save
34 - flash[:notice] = 'Problem was successfully created.'
35 - redirect_to action: :index
46 + redirect_to action: :index, notice: 'Problem was successfully created.'
36 47 else
37 48 render :action => 'new'
38 49 end
@@ -56,63 +67,31
56 67 end
57 68
58 69 def edit
59 - @problem = Problem.find(params[:id])
60 70 @description = @problem.description
61 71 end
62 72
63 73 def update
64 - @problem = Problem.find(params[:id])
65 - @description = @problem.description
66 - if @description.nil? and params[:description][:body]!=''
67 - @description = Description.new(description_params)
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
74 + if problem_params[:statement] && problem_params[:statement].content_type != 'application/pdf'
75 + flash[:error] = 'Error: Uploaded file is not PDF'
76 + render :action => 'edit'
77 + return
82 78 end
83 79 if @problem.update(problem_params)
84 - flash[:notice] = 'Problem was successfully updated.'
85 - unless params[:file] == nil or params[:file] == ''
86 - flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
87 - out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
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
80 + flash[:notice] = 'Problem was successfully updated. '
81 + flash[:notice] += 'A new statement PDF is uploaded' if problem_params[:statement]
82 + @problem.save
83 + redirect_to edit_problem_path(@problem)
104 84 else
105 85 render :action => 'edit'
106 86 end
107 87 end
108 88
109 89 def destroy
110 - p = Problem.find(params[:id]).destroy
90 + @problem.destroy
111 91 redirect_to action: :index
112 92 end
113 93
114 94 def toggle
115 - @problem = Problem.find(params[:id])
116 95 @problem.update(available: !(@problem.available) )
117 96 respond_to do |format|
118 97 format.js { }
@@ -120,7 +99,6
120 99 end
121 100
122 101 def toggle_test
123 - @problem = Problem.find(params[:id])
124 102 @problem.update(test_allowed: !(@problem.test_allowed?) )
125 103 respond_to do |format|
126 104 format.js { }
@@ -128,7 +106,6
128 106 end
129 107
130 108 def toggle_view_testcase
131 - @problem = Problem.find(params[:id])
132 109 @problem.update(view_testcase: !(@problem.view_testcase?) )
133 110 respond_to do |format|
134 111 format.js { }
@@ -152,7 +129,6
152 129 end
153 130
154 131 def stat
155 - @problem = Problem.find(params[:id])
156 132 unless @problem.available or session[:admin]
157 133 redirect_to :controller => 'main', :action => 'list'
158 134 return
@@ -295,8 +271,13
295 271
296 272 private
297 273
274 + def set_problem
275 + @problem = Problem.find(params[:id])
276 + end
277 +
298 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 281 end
301 282
302 283 def description_params
@@ -209,4 +209,15
209 209 BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
210 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 223 end
@@ -1,6 +1,7
1 1 class Problem < ApplicationRecord
2 2
3 - belongs_to :description
3 + #belongs_to :description
4 +
4 5 has_and_belongs_to_many :contests, :uniq => true
5 6
6 7 #has_and_belongs_to_many :groups
@@ -24,6 +25,9
24 25 DEFAULT_TIME_LIMIT = 1
25 26 DEFAULT_MEMORY_LIMIT = 32
26 27
28 + has_one_attached :statement
29 + has_many_attached :attachments
30 +
27 31 def get_jschart_history
28 32 start = 4.month.ago.beginning_of_day
29 33 start_date = start.to_date
@@ -11,14 +11,14
11 11 / submission
12 12 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
13 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 15 = "#{I18n.t 'menu.submissions'}"
16 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 18 %li= link_to 'Self Test', test_index_path, class:'dropdown-item'
19 19 / hall of fame
20 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 22 / display MODE button (with countdown in contest mode)
23 23 - if GraderConfiguration.analysis_mode?
24 24 %div.btn.btn-success#countdown= "ANALYSIS MODE"
@@ -35,33 +35,33
35 35 - if (@current_user!=nil) and (session[:admin])
36 36 / management
37 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 39 Manage
40 40 %ul.dropdown-menu
41 - %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'
42 - %li= link_to 'Problems', problems_path, class: 'dropdown-item'
43 - %li= link_to 'Tags', tags_path, class: 'dropdown-item'
44 - %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'
45 - %li= link_to 'User Groups', groups_path, class: 'dropdown-item'
46 - %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'
47 - %li= link_to 'Message ', console_messages_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'+active_class_when(controller: :problems)
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'+active_class_when(controller: :user_admin)
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'+active_class_when(controller: :graders)
47 + %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages)
48 48 %li
49 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 51 %li
52 52 %hr.dropdown-divider
53 - %li= link_to 'Sites', sites_path, class: 'dropdown-item'
54 - %li= link_to 'Contests', contest_management_index_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'+active_class_when(controller: :contest_management)
55 55 -#
56 56 / report
57 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 59 Report
60 60 %ul.dropdown-menu
61 - %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'
62 - %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'
63 - %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'
64 - %li= link_to 'Login Report', login_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'+active_class_when(controller: :report, action: :max_score)
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'+active_class_when(controller: :report, action: :login)
65 65 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
66 66 =link_to "#{ungraded} backlogs!",
67 67 graders_list_path,
@@ -85,3 +85,9
85 85 %a.nav-link{href: login_main_path}
86 86 %span.mi.mi-bs.md-18 exit_to_app
87 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'
2 - / [form:problem]
3 - .form-group
4 - %label{:for => "problem_name"} Name
5 - = text_field 'problem', 'name', class: 'form-control'
6 - %small
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.
8 - .form-group
9 - %label{:for => "problem_full_name"} Full name
10 - = text_field 'problem', 'full_name', class: 'form-control'
11 - .form-group
12 - %label{:for => "problem_full_score"} Full score
13 - = text_field 'problem', 'full_score', class: 'form-control'
14 - .form-group
15 - %label{:for => "problem_full_score"} Tags
16 - = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'})
17 - .form-group
18 - %label{:for => "problem_date_added"} Date added
19 - = date_select 'problem', 'date_added', class: 'form-control'
20 - - # TODO: these should be put in model Problem, but I can't think of
21 - - # nice default values for them. These values look fine only
22 - - # in this case (of lazily adding new problems).
23 - - @problem.available = true if @problem!=nil and @problem.available==nil
24 - - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil
25 - - @problem.output_only = false if @problem!=nil and @problem.output_only==nil
26 - .checkbox
27 - %label{:for => "problem_available"}
28 - = check_box :problem, :available
29 - Available?
30 - .checkbox
31 - %label{:for => "problem_test_allowed"}
32 - = check_box :problem, :test_allowed
33 - Test allowed?
34 - .checkbox
35 - %label{:for => "problem_output_only"}
36 - = check_box :problem, :output_only
37 - Output only?
38 - = error_messages_for 'description'
39 - .form-group
40 - %label{:for => "description_body"} Description
41 - %br/
42 - = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control'
43 - .form-group
44 - %label{:for => "description_markdowned"} Markdowned?
45 - = select "description", |
46 - "markdowned", |
47 - [['True',true],['False',false]], |
48 - {:selected => (@description) ? @description.markdowned : false } |
49 - .form-group
50 - %label{:for => "problem_url"} URL
51 - %br/
52 - = text_field 'problem', 'url',class: 'form-control'
53 - %p
54 - Task PDF #{file_field_tag 'file'}
55 - / [eoform:problem]
1 + = simple_form_for problem do |form|
2 + .row
3 + .col-md-6
4 + = form.input :name
5 + = form.input :full_name
6 + = form.input :full_score
7 + = form.input :tag_ids, collection: Tag.all, class: 'select2'
8 + = form.input :date_added
9 + = form.input :available
10 + = form.input :test_allowed
11 + = form.input :output_only
12 + = form.input :description, as: :text
13 + = form.input :markdown
14 + = form.input :url
15 + = form.input :statement
16 + %p
17 + - if @problem.statement.attached?
18 + %a{href: get_statement_problem_path(@problem)} [Download current Statement]
19 + - else
20 + no statement attached to this problem
21 + = form.submit :submit, class: 'btn btn-primary'
22 + -#
23 + = error_messages_for 'problem'
24 +
25 + / [form:problem]
26 + .form-group
27 + %label{:for => "problem_name"} Name
28 + = text_field 'problem', 'name', class: 'form-control'
29 + %small
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 + .form-group
32 + %label{:for => "problem_full_name"} Full name
33 + = text_field 'problem', 'full_name', class: 'form-control'
34 + .form-group
35 + %label{:for => "problem_full_score"} Full score
36 + = text_field 'problem', 'full_score', class: 'form-control'
37 + .form-group
38 + %label{:for => "problem_full_score"} Tags
39 + = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'})
40 + .form-group
41 + %label{:for => "problem_date_added"} Date added
42 + = date_select 'problem', 'date_added', class: 'form-control'
43 + - # TODO: these should be put in model Problem, but I can't think of
44 + - # nice default values for them. These values look fine only
45 + - # in this case (of lazily adding new problems).
46 + - @problem.available = true if @problem!=nil and @problem.available==nil
47 + - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil
48 + - @problem.output_only = false if @problem!=nil and @problem.output_only==nil
49 + .checkbox
50 + %label{:for => "problem_available"}
51 + = check_box :problem, :available
52 + Available?
53 + .checkbox
54 + %label{:for => "problem_test_allowed"}
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
2 - = form_for @problem,url:{action: 'update'},html: {multipart: true} do
3 - .row
4 - .col-md-6
5 - %h1 Editing problem
6 - = render :partial => 'form'
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'}
1 + %h1 Editing 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'
@@ -37,6 +37,9
37 37 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?]
38 38 - if GraderConfiguration.multicontests?
39 39 %th Contests
40 + %th.text-center
41 + %th.text-center
42 + %th.text-center
40 43 - for problem in @problems
41 44 %tr{:class => "#{(problem.available) ? "bg-success bg-opacity-25" : "bg-opacity-25"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
42 45 - @problem=problem
@@ -58,7 +61,6
58 61 %td
59 62 = problem.contests.collect { |c| c.name }.join(', ')
60 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 64 %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-sm btn-block'
63 65 %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-sm btn-block'
64 66 %br/
@@ -112,7 +112,7
112 112 # You can define the class to use on all labels. Default is nil.
113 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 116 # with `html: { :class }`. Defaulting to none.
117 117 # config.default_form_class = nil
118 118
@@ -1,10 +1,8
1 1 # frozen_string_literal: true
2 2
3 - # Please do not make direct changes to this file!
4 - # This generator is maintained by the community around simple_form-bootstrap:
5 - # https://github.com/rafaelfranca/simple_form-bootstrap
6 - # All future development, tests, and organization should happen there.
7 - # Background history: https://github.com/heartcombo/simple_form/issues/1561
3 + # These defaults are defined and maintained by the community at
4 + # https://github.com/heartcombo/simple_form-bootstrap
5 + # Please submit feedback, changes and tests only there.
8 6
9 7 # Uncomment this and change the path if necessary to include your own
10 8 # components.
@@ -43,13 +41,13
43 41
44 42 # add validation classes to `input_field`
45 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 47 # vertical forms
50 48 #
51 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 51 b.use :html5
54 52 b.use :placeholder
55 53 b.optional :maxlength
@@ -57,90 +55,100
57 55 b.optional :pattern
58 56 b.optional :min_max
59 57 b.optional :readonly
60 - b.use :label
61 - b.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
62 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
63 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
58 + b.use :label, class: 'form-label'
59 + b.use :input, class: 'form-control', error_class: 'is-invalid'
60 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
61 + b.use :hint, wrap_with: { class: 'form-text' }
64 62 end
65 63
66 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 66 b.use :html5
69 67 b.optional :readonly
70 - b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check' do |bb|
71 - bb.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
68 + b.wrapper :form_check_wrapper, class: 'form-check' do |bb|
69 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
72 70 bb.use :label, class: 'form-check-label'
73 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
74 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
71 + bb.use :full_error, wrap_with: { class: 'invalid-feedback' }
72 + bb.use :hint, wrap_with: { class: 'form-text' }
75 73 end
76 74 end
77 75
78 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 78 b.use :html5
81 79 b.optional :readonly
82 80 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
83 81 ba.use :label_text
84 82 end
85 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
86 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
87 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
83 + b.use :input, class: 'form-check-input', error_class: 'is-invalid'
84 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
85 + b.use :hint, wrap_with: { class: 'form-text' }
88 86 end
89 87
90 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 90 b.use :html5
93 91 b.optional :readonly
94 92 b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
95 93 ba.use :label_text
96 94 end
97 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
98 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
99 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
95 + b.use :input, class: 'form-check-input', error_class: 'is-invalid'
96 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
97 + b.use :hint, wrap_with: { class: 'form-text' }
100 98 end
101 99
102 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 102 b.use :html5
105 103 b.use :placeholder
106 104 b.optional :maxlength
107 105 b.optional :minlength
108 106 b.optional :readonly
109 - b.use :label
110 - b.use :input, class: 'form-control-file', error_class: 'is-invalid', valid_class: 'is-valid'
111 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
112 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
107 + b.use :label, class: 'form-label'
108 + b.use :input, class: 'form-control', error_class: 'is-invalid'
109 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
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 121 end
114 122
115 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 125 b.use :html5
118 126 b.optional :readonly
119 - b.use :label
120 - b.wrapper tag: 'div', 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'
127 + b.use :label, class: 'form-label'
128 + b.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |ba|
129 + ba.use :input, class: 'form-select mx-1', error_class: 'is-invalid'
122 130 end
123 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
124 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
131 + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
132 + b.use :hint, wrap_with: { class: 'form-text' }
125 133 end
126 134
127 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 137 b.use :html5
130 138 b.use :placeholder
131 139 b.optional :readonly
132 140 b.optional :step
133 - b.use :label
134 - b.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
135 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
136 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
141 + b.use :label, class: 'form-label'
142 + b.use :input, class: 'form-range', error_class: 'is-invalid'
143 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
144 + b.use :hint, wrap_with: { class: 'form-text' }
137 145 end
138 146
139 147
140 148 # horizontal forms
141 149 #
142 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 152 b.use :html5
145 153 b.use :placeholder
146 154 b.optional :maxlength
@@ -149,94 +157,103
149 157 b.optional :min_max
150 158 b.optional :readonly
151 159 b.use :label, class: 'col-sm-3 col-form-label'
152 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
153 - ba.use :input, class: 'form-control', error_class: 'is-invalid', valid_class: 'is-valid'
154 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
155 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
160 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
161 + ba.use :input, class: 'form-control', error_class: 'is-invalid'
162 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
163 + ba.use :hint, wrap_with: { class: 'form-text' }
156 164 end
157 165 end
158 166
159 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 169 b.use :html5
162 170 b.optional :readonly
163 - b.wrapper tag: 'label', class: 'col-sm-3' do |ba|
164 - ba.use :label_text
165 - end
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'
171 + b.wrapper :grid_wrapper, class: 'col-sm-9 offset-sm-3' do |wr|
172 + wr.wrapper :form_check_wrapper, class: 'form-check' do |bb|
173 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
169 174 bb.use :label, class: 'form-check-label'
170 - bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
171 - bb.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
175 + bb.use :full_error, wrap_with: { class: 'invalid-feedback' }
176 + bb.use :hint, wrap_with: { class: 'form-text' }
172 177 end
173 178 end
174 179 end
175 180
176 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 183 b.use :html5
179 184 b.optional :readonly
180 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|
182 - ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
183 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
184 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
186 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
187 + ba.use :input, class: 'form-check-input', error_class: 'is-invalid'
188 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
189 + ba.use :hint, wrap_with: { class: 'form-text' }
185 190 end
186 191 end
187 192
188 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 195 b.use :html5
191 196 b.optional :readonly
192 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|
194 - ba.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
195 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
196 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
198 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
199 + ba.use :input, class: 'form-check-input', error_class: 'is-invalid'
200 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
201 + ba.use :hint, wrap_with: { class: 'form-text' }
197 202 end
198 203 end
199 204
200 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 207 b.use :html5
203 208 b.use :placeholder
204 209 b.optional :maxlength
205 210 b.optional :minlength
206 211 b.optional :readonly
207 212 b.use :label, class: 'col-sm-3 col-form-label'
208 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
209 - ba.use :input, error_class: 'is-invalid', valid_class: 'is-valid'
210 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
211 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
213 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
214 + ba.use :input, class: 'form-control', error_class: 'is-invalid'
215 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
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 229 end
213 230 end
214 231
215 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 234 b.use :html5
218 235 b.optional :readonly
219 236 b.use :label, class: 'col-sm-3 col-form-label'
220 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
221 - ba.wrapper tag: 'div', 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'
237 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
238 + ba.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |bb|
239 + bb.use :input, class: 'form-select mx-1', error_class: 'is-invalid'
223 240 end
224 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
225 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
241 + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' }
242 + ba.use :hint, wrap_with: { class: 'form-text' }
226 243 end
227 244 end
228 245
229 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 248 b.use :html5
232 249 b.use :placeholder
233 250 b.optional :readonly
234 251 b.optional :step
235 - b.use :label, class: 'col-sm-3 col-form-label'
236 - b.wrapper :grid_wrapper, tag: 'div', class: 'col-sm-9' do |ba|
237 - ba.use :input, class: 'form-control-range', error_class: 'is-invalid', valid_class: 'is-valid'
238 - ba.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
239 - ba.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
252 + b.use :label, class: 'col-sm-3 col-form-label pt-0'
253 + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba|
254 + ba.use :input, class: 'form-range', error_class: 'is-invalid'
255 + ba.use :full_error, wrap_with: { class: 'invalid-feedback' }
256 + ba.use :hint, wrap_with: { class: 'form-text' }
240 257 end
241 258 end
242 259
@@ -244,7 +261,7
244 261 # inline forms
245 262 #
246 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 265 b.use :html5
249 266 b.use :placeholder
250 267 b.optional :maxlength
@@ -252,140 +269,44
252 269 b.optional :pattern
253 270 b.optional :min_max
254 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'
258 - b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
259 - b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
274 + b.use :input, class: 'form-control', error_class: 'is-invalid'
275 + b.use :error, wrap_with: { class: 'invalid-feedback' }
276 + b.optional :hint, wrap_with: { class: 'form-text' }
260 277 end
261 278
262 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 281 b.use :html5
265 282 b.optional :readonly
266 - b.use :input, class: 'form-check-input', error_class: 'is-invalid', valid_class: 'is-valid'
267 - b.use :label, class: 'form-check-label'
268 - b.use :error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
269 - b.optional :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
283 + b.wrapper :form_check_wrapper, class: 'form-check' do |bb|
284 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
285 + bb.use :label, class: 'form-check-label'
286 + bb.use :error, wrap_with: { class: 'invalid-feedback' }
287 + bb.optional :hint, wrap_with: { class: 'form-text' }
288 + end
270 289 end
271 290
272 291
273 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 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|
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|
295 + config.wrappers :custom_boolean_switch, class: 'mb-3' do |b|
313 296 b.use :html5
314 297 b.optional :readonly
315 - b.wrapper :legend_tag, tag: 'legend', class: 'col-form-label pt-0' do |ba|
316 - ba.use :label_text
317 - end
318 - b.use :input, class: 'custom-control-input', error_class: 'is-invalid', valid_class: 'is-valid'
319 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' }
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' }
298 + b.wrapper :form_check_wrapper, tag: 'div', class: 'form-check form-switch' do |bb|
299 + bb.use :input, class: 'form-check-input', error_class: 'is-invalid'
300 + bb.use :label, class: 'form-check-label'
301 + bb.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
302 + bb.use :hint, wrap_with: { class: 'form-text' }
335 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 304 end
362 305
363 306
364 307 # Input Group - custom component
365 - # see example app and config at https://github.com/rafaelfranca/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|
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|
308 + # see example app and config at https://github.com/heartcombo/simple_form-bootstrap
309 + config.wrappers :input_group, class: 'mb-3' do |b|
389 310 b.use :html5
390 311 b.use :placeholder
391 312 b.optional :maxlength
@@ -393,20 +314,42
393 314 b.optional :pattern
394 315 b.optional :min_max
395 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 340 b.use :label
398 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
399 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
341 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
342 + b.use :hint, wrap_with: { class: 'form-text' }
400 343 end
401 344
402 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 347 b.use :html5
405 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 350 b.use :label
408 - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback' }
409 - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' }
351 + b.use :full_error, wrap_with: { class: 'invalid-feedback' }
352 + b.use :hint, wrap_with: { class: 'form-text' }
410 353 end
411 354
412 355
@@ -423,18 +366,7
423 366 file: :vertical_file,
424 367 radio_buttons: :vertical_collection,
425 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 372 end
@@ -34,6 +34,7
34 34 get 'toggle_test'
35 35 get 'toggle_view_testcase'
36 36 get 'stat'
37 + get 'get_statement'
37 38 end
38 39 collection do
39 40 get 'turn_all_off'
@@ -10,10 +10,38
10 10 #
11 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
14 - create_table "announcements", id: :integer, charset: "utf8", force: :cascade do |t|
13 + ActiveRecord::Schema[7.0].define(version: 2022_09_27_074644) do
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 43 t.string "author"
16 - t.text "body", size: :medium
44 + t.text "body"
17 45 t.boolean "published"
18 46 t.datetime "created_at", precision: nil, null: false
19 47 t.datetime "updated_at", precision: nil, null: false
@@ -24,7 +52,7
24 52 t.boolean "on_nav_bar", default: false
25 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 56 t.string "title"
29 57 t.boolean "enabled"
30 58 t.datetime "created_at", precision: nil, null: false
@@ -32,39 +60,39
32 60 t.string "name"
33 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 64 t.integer "contest_id"
37 65 t.integer "problem_id"
38 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 69 t.integer "contest_id"
42 70 t.integer "user_id"
43 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 74 t.string "name"
47 75 t.datetime "created_at", precision: nil, null: false
48 76 t.datetime "updated_at", precision: nil, null: false
49 77 end
50 78
51 - create_table "descriptions", id: :integer, charset: "utf8", force: :cascade do |t|
52 - t.text "body", size: :medium
79 + create_table "descriptions", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
80 + t.text "body"
53 81 t.boolean "markdowned"
54 82 t.datetime "created_at", precision: nil, null: false
55 83 t.datetime "updated_at", precision: nil, null: false
56 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 87 t.string "key"
60 88 t.string "value_type"
61 89 t.string "value"
62 90 t.datetime "created_at", precision: nil, null: false
63 91 t.datetime "updated_at", precision: nil, null: false
64 - t.text "description", size: :medium
92 + t.text "description"
65 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 96 t.string "host"
69 97 t.integer "pid"
70 98 t.string "mode"
@@ -95,7 +123,7
95 123 t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id"
96 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 127 t.integer "user_id"
100 128 t.string "ip_address"
101 129 t.datetime "created_at", precision: nil, null: false
@@ -104,14 +132,14
104 132 t.index ["updated_at"], name: "index_heart_beats_on_updated_at"
105 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 136 t.string "name", limit: 10
109 137 t.string "pretty_name"
110 138 t.string "ext", limit: 10
111 139 t.string "common_ext"
112 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 143 t.integer "user_id"
116 144 t.string "ip_address"
117 145 t.datetime "created_at", precision: nil, null: false
@@ -119,18 +147,18
119 147 t.index ["user_id"], name: "index_logins_on_user_id"
120 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 151 t.integer "sender_id"
124 152 t.integer "receiver_id"
125 153 t.integer "replying_message_id"
126 - t.text "body", size: :medium
154 + t.text "body"
127 155 t.boolean "replied"
128 156 t.datetime "created_at", precision: nil, null: false
129 157 t.datetime "updated_at", precision: nil, null: false
130 158 end
131 159
132 - create_table "problems", id: :bigint, default: nil, charset: "utf8", force: :cascade do |t|
133 - t.string "name", limit: 100
160 + create_table "problems", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
161 + t.string "name", limit: 30
134 162 t.string "full_name"
135 163 t.integer "full_score"
136 164 t.date "date_added"
@@ -142,47 +170,49
142 170 t.string "description_filename"
143 171 t.boolean "view_testcase"
144 172 t.integer "difficulty"
173 + t.text "description"
174 + t.boolean "markdown"
145 175 end
146 176
147 - create_table "problems_tags", id: :bigint, default: nil, charset: "latin1", force: :cascade do |t|
148 - t.bigint "problem_id"
177 + create_table "problems_tags", id: :integer, charset: "latin1", force: :cascade do |t|
178 + t.integer "problem_id"
149 179 t.integer "tag_id"
150 180 t.index ["problem_id", "tag_id"], name: "index_problems_tags_on_problem_id_and_tag_id", unique: true
151 181 t.index ["problem_id"], name: "index_problems_tags_on_problem_id"
152 182 t.index ["tag_id"], name: "index_problems_tags_on_tag_id"
153 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 186 t.string "name"
157 187 t.string "controller"
158 188 t.string "action"
159 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 192 t.integer "right_id"
163 193 t.integer "role_id"
164 194 t.index ["role_id"], name: "index_rights_roles_on_role_id"
165 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 198 t.string "name"
169 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 202 t.integer "role_id"
173 203 t.integer "user_id"
174 204 t.index ["user_id"], name: "index_roles_users_on_user_id"
175 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 208 t.string "session_id"
179 - t.text "data", size: :medium
209 + t.text "data"
180 210 t.datetime "updated_at", precision: nil
181 211 t.index ["session_id"], name: "index_sessions_on_session_id"
182 212 t.index ["updated_at"], name: "index_sessions_on_updated_at"
183 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 216 t.string "name"
187 217 t.boolean "started"
188 218 t.datetime "start_time", precision: nil
@@ -192,23 +222,14
192 222 t.string "password"
193 223 end
194 224
195 - create_table "solutions", charset: "latin1", 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|
225 + create_table "submission_view_logs", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t|
205 226 t.integer "user_id"
206 227 t.integer "submission_id"
207 228 t.datetime "created_at", precision: nil, null: false
208 229 t.datetime "updated_at", precision: nil, null: false
209 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 233 t.integer "user_id"
213 234 t.integer "problem_id"
214 235 t.integer "language_id"
@@ -216,10 +237,10
216 237 t.binary "binary"
217 238 t.datetime "submitted_at", precision: nil
218 239 t.datetime "compiled_at", precision: nil
219 - t.text "compiler_message", size: :medium
240 + t.text "compiler_message"
220 241 t.datetime "graded_at", precision: nil
221 242 t.integer "points"
222 - t.text "grader_comment", size: :medium
243 + t.text "grader_comment"
223 244 t.integer "number"
224 245 t.string "source_filename"
225 246 t.float "max_runtime"
@@ -240,7 +261,7
240 261 t.datetime "updated_at", precision: nil, null: false
241 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 265 t.integer "submission_id"
245 266 t.datetime "created_at", precision: nil
246 267 t.integer "status"
@@ -249,15 +270,15
249 270 t.index ["submission_id"], name: "index_tasks_on_submission_id"
250 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 274 t.integer "problem_id"
254 - t.text "input", size: :long
255 - t.text "solution", size: :long
275 + t.text "input", size: :medium
276 + t.text "solution", size: :medium
256 277 t.datetime "created_at", precision: nil, null: false
257 278 t.datetime "updated_at", precision: nil, null: false
258 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 282 t.integer "user_id"
262 283 t.integer "problem_id"
263 284 t.integer "submission_id"
@@ -268,7 +289,7
268 289 t.datetime "updated_at", precision: nil, null: false
269 290 t.datetime "submitted_at", precision: nil
270 291 t.datetime "compiled_at", precision: nil
271 - t.text "compiler_message", size: :medium
292 + t.text "compiler_message"
272 293 t.datetime "graded_at", precision: nil
273 294 t.string "grader_comment"
274 295 t.datetime "created_at", precision: nil, null: false
@@ -285,12 +306,12
285 306 t.integer "score"
286 307 t.text "input", size: :long
287 308 t.text "sol", size: :long
288 - t.datetime "created_at", precision: nil, null: false
289 - t.datetime "updated_at", precision: nil, null: false
309 + t.datetime "created_at", precision: nil
310 + t.datetime "updated_at", precision: nil
290 311 t.index ["problem_id"], name: "index_testcases_on_problem_id"
291 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 315 t.integer "user_id"
295 316 t.datetime "started_at", precision: nil
296 317 t.datetime "created_at", precision: nil, null: false
@@ -298,7 +319,7
298 319 t.boolean "forced_logout"
299 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 323 t.string "login", limit: 50
303 324 t.string "full_name"
304 325 t.string "hashed_password"
@@ -310,16 +331,16
310 331 t.boolean "activated", default: false
311 332 t.datetime "created_at", precision: nil
312 333 t.datetime "updated_at", precision: nil
313 - t.string "section"
314 334 t.boolean "enabled", default: true
315 335 t.string "remark"
316 336 t.string "last_ip"
337 + t.string "section"
317 338 t.integer "default_language"
318 339 t.index ["login"], name: "index_users_on_login", unique: true
319 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 344 add_foreign_key "problems_tags", "problems"
322 345 add_foreign_key "problems_tags", "tags"
323 - add_foreign_key "solutions", "problems"
324 - add_foreign_key "solutions", "submissions"
325 346 end
deleted file
You need to be logged in to leave comments. Login now