Description:
modernize problem
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
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 |
@@ -1,37 +1,38 | |||||
|
1 | # See http://help.github.com/ignore-files/ for more about ignoring files. |
|
1 | # See http://help.github.com/ignore-files/ for more about ignoring files. |
|
2 | # |
|
2 | # |
|
3 | # If you find yourself ignoring temporary files generated by your text editor |
|
3 | # If you find yourself ignoring temporary files generated by your text editor |
|
4 | # or operating system, you probably want to add a global ignore instead: |
|
4 | # or operating system, you probably want to add a global ignore instead: |
|
5 | # git config --global core.excludesfile ~/.gitignore_global |
|
5 | # git config --global core.excludesfile ~/.gitignore_global |
|
6 |
|
6 | ||
|
7 | # Ignore bundler config |
|
7 | # Ignore bundler config |
|
8 | /.bundle |
|
8 | /.bundle |
|
9 |
|
9 | ||
|
10 | # Ignore the default SQLite database. |
|
10 | # Ignore the default SQLite database. |
|
11 | /db/*.sqlite3 |
|
11 | /db/*.sqlite3 |
|
12 |
|
12 | ||
|
13 | # Ignore all logfiles and tempfiles. |
|
13 | # Ignore all logfiles and tempfiles. |
|
14 | /log/*.log |
|
14 | /log/*.log |
|
15 | /tmp |
|
15 | /tmp |
|
16 |
|
16 | ||
|
17 | *~ |
|
17 | *~ |
|
18 |
|
18 | ||
|
19 | /vendor/plugins/rails_upgrade |
|
19 | /vendor/plugins/rails_upgrade |
|
20 |
|
20 | ||
|
21 | #ignore public assets??? |
|
21 | #ignore public assets??? |
|
22 | /public/assets |
|
22 | /public/assets |
|
23 | /public |
|
23 | /public |
|
24 |
|
24 | ||
|
25 | /data |
|
25 | /data |
|
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/* |
@@ -1,123 +1,124 | |||||
|
1 | source 'https://rubygems.org' |
|
1 | source 'https://rubygems.org' |
|
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } |
|
2 | git_source(:github) { |repo| "https://github.com/#{repo}.git" } |
|
3 |
|
3 | ||
|
4 | ruby '3.1.2' |
|
4 | ruby '3.1.2' |
|
5 |
|
5 | ||
|
6 | #rails |
|
6 | #rails |
|
7 | gem 'rails', '~>7.0' |
|
7 | gem 'rails', '~>7.0' |
|
8 |
|
8 | ||
|
9 | # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] |
|
9 | # The original asset pipeline for Rails [https://github.com/rails/sprockets-rails] |
|
10 | gem "sprockets-rails" |
|
10 | gem "sprockets-rails" |
|
11 |
|
11 | ||
|
12 | gem 'puma' |
|
12 | gem 'puma' |
|
13 |
|
13 | ||
|
14 | # Reduces boot times through caching; required in config/boot.rb |
|
14 | # Reduces boot times through caching; required in config/boot.rb |
|
15 | gem 'bootsnap', require: false |
|
15 | gem 'bootsnap', require: false |
|
16 |
|
16 | ||
|
17 | # Bundle edge Rails instead: |
|
17 | # Bundle edge Rails instead: |
|
18 | # gem 'rails', :git => 'git://github.com/rails/rails.git' |
|
18 | # gem 'rails', :git => 'git://github.com/rails/rails.git' |
|
19 |
|
19 | ||
|
20 | #---------------- database --------------------- |
|
20 | #---------------- database --------------------- |
|
21 | #the database |
|
21 | #the database |
|
22 | gem 'mysql2' |
|
22 | gem 'mysql2' |
|
23 | #for testing |
|
23 | #for testing |
|
24 | gem 'sqlite3' |
|
24 | gem 'sqlite3' |
|
25 | #gem 'rails-controller-testing' |
|
25 | #gem 'rails-controller-testing' |
|
26 | #for dumping database into yaml |
|
26 | #for dumping database into yaml |
|
27 | #gem 'yaml_db' |
|
27 | #gem 'yaml_db' |
|
28 |
|
28 | ||
|
29 |
|
29 | ||
|
30 | #------------- assset pipeline ----------------- |
|
30 | #------------- assset pipeline ----------------- |
|
31 | # Gems used only for assets and not required |
|
31 | # Gems used only for assets and not required |
|
32 | # in production environments by default. |
|
32 | # in production environments by default. |
|
33 | #sass-rails is depricated |
|
33 | #sass-rails is depricated |
|
34 | #gem 'sass-rails' |
|
34 | #gem 'sass-rails' |
|
35 | gem 'sassc-rails' |
|
35 | gem 'sassc-rails' |
|
36 | gem 'coffee-rails' |
|
36 | gem 'coffee-rails' |
|
37 | gem 'material_icons' |
|
37 | gem 'material_icons' |
|
38 |
|
38 | ||
|
39 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes |
|
39 | # See https://github.com/sstephenson/execjs#readme for more supported runtimes |
|
40 | # gem 'therubyracer', :platforms => :ruby |
|
40 | # gem 'therubyracer', :platforms => :ruby |
|
41 |
|
41 | ||
|
42 | gem "importmap-rails", "~> 1.1" |
|
42 | gem "importmap-rails", "~> 1.1" |
|
43 | # gem 'uglifier' |
|
43 | # gem 'uglifier' |
|
44 |
|
44 | ||
|
45 | gem 'haml' |
|
45 | gem 'haml' |
|
46 | gem 'haml-rails' |
|
46 | gem 'haml-rails' |
|
47 |
|
47 | ||
|
48 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks |
|
48 | # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks |
|
49 | #gem 'turbolinks', '~> 5' |
|
49 | #gem 'turbolinks', '~> 5' |
|
50 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder |
|
50 | # Build JSON APIs with ease. Read more: https://github.com/rails/jbuilder |
|
51 | gem 'jbuilder' |
|
51 | gem 'jbuilder' |
|
52 |
|
52 | ||
|
53 |
|
53 | ||
|
54 | #in-place editor |
|
54 | #in-place editor |
|
55 | gem 'best_in_place', git: "https://github.com/mmotherwell/best_in_place" |
|
55 | gem 'best_in_place', git: "https://github.com/mmotherwell/best_in_place" |
|
56 |
|
56 | ||
|
57 | # jquery addition |
|
57 | # jquery addition |
|
58 | gem 'jquery-rails' |
|
58 | gem 'jquery-rails' |
|
59 | #gem 'jquery-ui-rails' |
|
59 | #gem 'jquery-ui-rails' |
|
60 | #gem 'jquery-timepicker-addon-rails' |
|
60 | #gem 'jquery-timepicker-addon-rails' |
|
61 | #gem 'jquery-tablesorter' |
|
61 | #gem 'jquery-tablesorter' |
|
62 | #gem 'jquery-countdown-rails' |
|
62 | #gem 'jquery-countdown-rails' |
|
63 |
|
63 | ||
|
64 | #syntax highlighter |
|
64 | #syntax highlighter |
|
65 | gem 'rouge' |
|
65 | gem 'rouge' |
|
66 |
|
66 | ||
|
67 | #bootstrap add-ons |
|
67 | #bootstrap add-ons |
|
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 ----------------------- |
|
93 | gem 'minitest-reporters' |
|
94 | gem 'minitest-reporters' |
|
94 |
|
95 | ||
|
95 | #---------------- for console -------------------- |
|
96 | #---------------- for console -------------------- |
|
96 | gem 'fuzzy-string-match' |
|
97 | gem 'fuzzy-string-match' |
|
97 |
|
98 | ||
|
98 |
|
99 | ||
|
99 | group :development, :test do |
|
100 | group :development, :test do |
|
100 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console |
|
101 | # Call 'byebug' anywhere in the code to stop execution and get a debugger console |
|
101 | gem 'byebug' |
|
102 | gem 'byebug' |
|
102 | end |
|
103 | end |
|
103 |
|
104 | ||
|
104 | group :development do |
|
105 | group :development do |
|
105 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code. |
|
106 | # Access an interactive console on exception pages or by calling 'console' anywhere in the code. |
|
106 | gem 'web-console', '>= 3.3.0' |
|
107 | gem 'web-console', '>= 3.3.0' |
|
107 | gem 'listen', '>= 3.0.5', '< 3.2' |
|
108 | gem 'listen', '>= 3.0.5', '< 3.2' |
|
108 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring |
|
109 | # Spring speeds up development by keeping your application running in the background. Read more: https://github.com/rails/spring |
|
109 | gem 'spring' |
|
110 | gem 'spring' |
|
110 | gem 'spring-watcher-listen', '~> 2.0.0' |
|
111 | gem 'spring-watcher-listen', '~> 2.0.0' |
|
111 |
|
112 | ||
|
112 | # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] |
|
113 | # Add speed badges [https://github.com/MiniProfiler/rack-mini-profiler] |
|
113 | # gem "rack-mini-profiler" |
|
114 | # gem "rack-mini-profiler" |
|
114 | end |
|
115 | end |
|
115 |
|
116 | ||
|
116 | group :test do |
|
117 | group :test do |
|
117 | # Adds support for Capybara system testing and selenium driver |
|
118 | # Adds support for Capybara system testing and selenium driver |
|
118 | gem 'capybara' |
|
119 | gem 'capybara' |
|
119 | gem 'selenium-webdriver' |
|
120 | gem 'selenium-webdriver' |
|
120 | gem 'webdrivers' |
|
121 | gem 'webdrivers' |
|
121 | end |
|
122 | end |
|
122 |
|
123 | ||
|
123 |
|
124 |
@@ -1,96 +1,105 | |||||
|
|
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) |
|
13 | ZenTest (~> 4.3) |
|
22 | ZenTest (~> 4.3) |
|
14 | ZenTest (4.12.1) |
|
23 | ZenTest (4.12.1) |
|
15 | ace-rails-ap (4.4) |
|
24 | ace-rails-ap (4.4) |
|
16 | actioncable (7.0.4) |
|
25 | actioncable (7.0.4) |
|
17 | actionpack (= 7.0.4) |
|
26 | actionpack (= 7.0.4) |
|
18 | activesupport (= 7.0.4) |
|
27 | activesupport (= 7.0.4) |
|
19 | nio4r (~> 2.0) |
|
28 | nio4r (~> 2.0) |
|
20 | websocket-driver (>= 0.6.1) |
|
29 | websocket-driver (>= 0.6.1) |
|
21 | actionmailbox (7.0.4) |
|
30 | actionmailbox (7.0.4) |
|
22 | actionpack (= 7.0.4) |
|
31 | actionpack (= 7.0.4) |
|
23 | activejob (= 7.0.4) |
|
32 | activejob (= 7.0.4) |
|
24 | activerecord (= 7.0.4) |
|
33 | activerecord (= 7.0.4) |
|
25 | activestorage (= 7.0.4) |
|
34 | activestorage (= 7.0.4) |
|
26 | activesupport (= 7.0.4) |
|
35 | activesupport (= 7.0.4) |
|
27 | mail (>= 2.7.1) |
|
36 | mail (>= 2.7.1) |
|
28 | net-imap |
|
37 | net-imap |
|
29 | net-pop |
|
38 | net-pop |
|
30 | net-smtp |
|
39 | net-smtp |
|
31 | actionmailer (7.0.4) |
|
40 | actionmailer (7.0.4) |
|
32 | actionpack (= 7.0.4) |
|
41 | actionpack (= 7.0.4) |
|
33 | actionview (= 7.0.4) |
|
42 | actionview (= 7.0.4) |
|
34 | activejob (= 7.0.4) |
|
43 | activejob (= 7.0.4) |
|
35 | activesupport (= 7.0.4) |
|
44 | activesupport (= 7.0.4) |
|
36 | mail (~> 2.5, >= 2.5.4) |
|
45 | mail (~> 2.5, >= 2.5.4) |
|
37 | net-imap |
|
46 | net-imap |
|
38 | net-pop |
|
47 | net-pop |
|
39 | net-smtp |
|
48 | net-smtp |
|
40 | rails-dom-testing (~> 2.0) |
|
49 | rails-dom-testing (~> 2.0) |
|
41 | actionpack (7.0.4) |
|
50 | actionpack (7.0.4) |
|
42 | actionview (= 7.0.4) |
|
51 | actionview (= 7.0.4) |
|
43 | activesupport (= 7.0.4) |
|
52 | activesupport (= 7.0.4) |
|
44 | rack (~> 2.0, >= 2.2.0) |
|
53 | rack (~> 2.0, >= 2.2.0) |
|
45 | rack-test (>= 0.6.3) |
|
54 | rack-test (>= 0.6.3) |
|
46 | rails-dom-testing (~> 2.0) |
|
55 | rails-dom-testing (~> 2.0) |
|
47 | rails-html-sanitizer (~> 1.0, >= 1.2.0) |
|
56 | rails-html-sanitizer (~> 1.0, >= 1.2.0) |
|
48 | actiontext (7.0.4) |
|
57 | actiontext (7.0.4) |
|
49 | actionpack (= 7.0.4) |
|
58 | actionpack (= 7.0.4) |
|
50 | activerecord (= 7.0.4) |
|
59 | activerecord (= 7.0.4) |
|
51 | activestorage (= 7.0.4) |
|
60 | activestorage (= 7.0.4) |
|
52 | activesupport (= 7.0.4) |
|
61 | activesupport (= 7.0.4) |
|
53 | globalid (>= 0.6.0) |
|
62 | globalid (>= 0.6.0) |
|
54 | nokogiri (>= 1.8.5) |
|
63 | nokogiri (>= 1.8.5) |
|
55 | actionview (7.0.4) |
|
64 | actionview (7.0.4) |
|
56 | activesupport (= 7.0.4) |
|
65 | activesupport (= 7.0.4) |
|
57 | builder (~> 3.1) |
|
66 | builder (~> 3.1) |
|
58 | erubi (~> 1.4) |
|
67 | erubi (~> 1.4) |
|
59 | rails-dom-testing (~> 2.0) |
|
68 | rails-dom-testing (~> 2.0) |
|
60 | rails-html-sanitizer (~> 1.1, >= 1.2.0) |
|
69 | rails-html-sanitizer (~> 1.1, >= 1.2.0) |
|
61 | activejob (7.0.4) |
|
70 | activejob (7.0.4) |
|
62 | activesupport (= 7.0.4) |
|
71 | activesupport (= 7.0.4) |
|
63 | globalid (>= 0.3.6) |
|
72 | globalid (>= 0.3.6) |
|
64 | activemodel (7.0.4) |
|
73 | activemodel (7.0.4) |
|
65 | activesupport (= 7.0.4) |
|
74 | activesupport (= 7.0.4) |
|
66 | activerecord (7.0.4) |
|
75 | activerecord (7.0.4) |
|
67 | activemodel (= 7.0.4) |
|
76 | activemodel (= 7.0.4) |
|
68 | activesupport (= 7.0.4) |
|
77 | activesupport (= 7.0.4) |
|
69 | activestorage (7.0.4) |
|
78 | activestorage (7.0.4) |
|
70 | actionpack (= 7.0.4) |
|
79 | actionpack (= 7.0.4) |
|
71 | activejob (= 7.0.4) |
|
80 | activejob (= 7.0.4) |
|
72 | activerecord (= 7.0.4) |
|
81 | activerecord (= 7.0.4) |
|
73 | activesupport (= 7.0.4) |
|
82 | activesupport (= 7.0.4) |
|
74 | marcel (~> 1.0) |
|
83 | marcel (~> 1.0) |
|
75 | mini_mime (>= 1.1.0) |
|
84 | mini_mime (>= 1.1.0) |
|
76 | activesupport (7.0.4) |
|
85 | activesupport (7.0.4) |
|
77 | concurrent-ruby (~> 1.0, >= 1.0.2) |
|
86 | concurrent-ruby (~> 1.0, >= 1.0.2) |
|
78 | i18n (>= 1.6, < 2) |
|
87 | i18n (>= 1.6, < 2) |
|
79 | minitest (>= 5.1) |
|
88 | minitest (>= 5.1) |
|
80 | tzinfo (~> 2.0) |
|
89 | tzinfo (~> 2.0) |
|
81 | addressable (2.8.1) |
|
90 | addressable (2.8.1) |
|
82 | public_suffix (>= 2.0.2, < 6.0) |
|
91 | public_suffix (>= 2.0.2, < 6.0) |
|
83 | ansi (1.5.0) |
|
92 | ansi (1.5.0) |
|
84 | autoprefixer-rails (10.4.7.0) |
|
93 | autoprefixer-rails (10.4.7.0) |
|
85 | execjs (~> 2) |
|
94 | execjs (~> 2) |
|
86 | bindex (0.8.1) |
|
95 | bindex (0.8.1) |
|
87 | bootsnap (1.13.0) |
|
96 | bootsnap (1.13.0) |
|
88 | msgpack (~> 1.2) |
|
97 | msgpack (~> 1.2) |
|
89 | bootstrap (5.2.1) |
|
98 | bootstrap (5.2.1) |
|
90 | autoprefixer-rails (>= 9.1.0) |
|
99 | autoprefixer-rails (>= 9.1.0) |
|
91 | popper_js (>= 2.11.6, < 3) |
|
100 | popper_js (>= 2.11.6, < 3) |
|
92 | sassc-rails (>= 2.0.0) |
|
101 | sassc-rails (>= 2.0.0) |
|
93 | builder (3.2.4) |
|
102 | builder (3.2.4) |
|
94 | byebug (11.1.3) |
|
103 | byebug (11.1.3) |
|
95 | capybara (3.37.1) |
|
104 | capybara (3.37.1) |
|
96 | addressable |
|
105 | addressable |
@@ -154,177 +163,174 | |||||
|
154 | nokogiri (>= 1.5.9) |
|
163 | nokogiri (>= 1.5.9) |
|
155 | mail (2.7.1) |
|
164 | mail (2.7.1) |
|
156 | mini_mime (>= 0.1.1) |
|
165 | mini_mime (>= 0.1.1) |
|
157 | marcel (1.0.2) |
|
166 | marcel (1.0.2) |
|
158 | material_icons (2.2.1) |
|
167 | material_icons (2.2.1) |
|
159 | railties (>= 3.2) |
|
168 | railties (>= 3.2) |
|
160 | matrix (0.4.2) |
|
169 | matrix (0.4.2) |
|
161 | method_source (1.0.0) |
|
170 | method_source (1.0.0) |
|
162 | mini_mime (1.1.2) |
|
171 | mini_mime (1.1.2) |
|
163 | minitest (5.16.3) |
|
172 | minitest (5.16.3) |
|
164 | minitest-reporters (1.5.0) |
|
173 | minitest-reporters (1.5.0) |
|
165 | ansi |
|
174 | ansi |
|
166 | builder |
|
175 | builder |
|
167 | minitest (>= 5.0) |
|
176 | minitest (>= 5.0) |
|
168 | ruby-progressbar |
|
177 | ruby-progressbar |
|
169 | momentjs-rails (2.29.4.1) |
|
178 | momentjs-rails (2.29.4.1) |
|
170 | railties (>= 3.1) |
|
179 | railties (>= 3.1) |
|
171 | msgpack (1.5.6) |
|
180 | msgpack (1.5.6) |
|
172 | mysql2 (0.5.4) |
|
181 | mysql2 (0.5.4) |
|
173 | net-imap (0.2.3) |
|
182 | net-imap (0.2.3) |
|
174 | digest |
|
183 | digest |
|
175 | net-protocol |
|
184 | net-protocol |
|
176 | strscan |
|
185 | strscan |
|
177 | net-pop (0.1.1) |
|
186 | net-pop (0.1.1) |
|
178 | digest |
|
187 | digest |
|
179 | net-protocol |
|
188 | net-protocol |
|
180 | timeout |
|
189 | timeout |
|
181 | net-protocol (0.1.3) |
|
190 | net-protocol (0.1.3) |
|
182 | timeout |
|
191 | timeout |
|
183 | net-smtp (0.3.1) |
|
192 | net-smtp (0.3.1) |
|
184 | digest |
|
193 | digest |
|
185 | net-protocol |
|
194 | net-protocol |
|
186 | timeout |
|
195 | timeout |
|
187 | nio4r (2.5.8) |
|
196 | nio4r (2.5.8) |
|
188 | nokogiri (1.13.8-x86_64-linux) |
|
197 | nokogiri (1.13.8-x86_64-linux) |
|
189 | racc (~> 1.4) |
|
198 | racc (~> 1.4) |
|
190 | popper_js (2.11.6) |
|
199 | popper_js (2.11.6) |
|
191 | public_suffix (5.0.0) |
|
200 | public_suffix (5.0.0) |
|
192 | puma (5.6.5) |
|
201 | puma (5.6.5) |
|
193 | nio4r (~> 2.0) |
|
202 | nio4r (~> 2.0) |
|
194 | racc (1.6.0) |
|
203 | racc (1.6.0) |
|
195 | rack (2.2.4) |
|
204 | rack (2.2.4) |
|
196 | rack-test (2.0.2) |
|
205 | rack-test (2.0.2) |
|
197 | rack (>= 1.3) |
|
206 | rack (>= 1.3) |
|
198 | rails (7.0.4) |
|
207 | rails (7.0.4) |
|
199 | actioncable (= 7.0.4) |
|
208 | actioncable (= 7.0.4) |
|
200 | actionmailbox (= 7.0.4) |
|
209 | actionmailbox (= 7.0.4) |
|
201 | actionmailer (= 7.0.4) |
|
210 | actionmailer (= 7.0.4) |
|
202 | actionpack (= 7.0.4) |
|
211 | actionpack (= 7.0.4) |
|
203 | actiontext (= 7.0.4) |
|
212 | actiontext (= 7.0.4) |
|
204 | actionview (= 7.0.4) |
|
213 | actionview (= 7.0.4) |
|
205 | activejob (= 7.0.4) |
|
214 | activejob (= 7.0.4) |
|
206 | activemodel (= 7.0.4) |
|
215 | activemodel (= 7.0.4) |
|
207 | activerecord (= 7.0.4) |
|
216 | activerecord (= 7.0.4) |
|
208 | activestorage (= 7.0.4) |
|
217 | activestorage (= 7.0.4) |
|
209 | activesupport (= 7.0.4) |
|
218 | activesupport (= 7.0.4) |
|
210 | bundler (>= 1.15.0) |
|
219 | bundler (>= 1.15.0) |
|
211 | railties (= 7.0.4) |
|
220 | railties (= 7.0.4) |
|
212 | rails-dom-testing (2.0.3) |
|
221 | rails-dom-testing (2.0.3) |
|
213 | activesupport (>= 4.2.0) |
|
222 | activesupport (>= 4.2.0) |
|
214 | nokogiri (>= 1.6) |
|
223 | nokogiri (>= 1.6) |
|
215 | rails-html-sanitizer (1.4.3) |
|
224 | rails-html-sanitizer (1.4.3) |
|
216 | loofah (~> 2.3) |
|
225 | loofah (~> 2.3) |
|
217 | railties (7.0.4) |
|
226 | railties (7.0.4) |
|
218 | actionpack (= 7.0.4) |
|
227 | actionpack (= 7.0.4) |
|
219 | activesupport (= 7.0.4) |
|
228 | activesupport (= 7.0.4) |
|
220 | method_source |
|
229 | method_source |
|
221 | rake (>= 12.2) |
|
230 | rake (>= 12.2) |
|
222 | thor (~> 1.0) |
|
231 | thor (~> 1.0) |
|
223 | zeitwerk (~> 2.5) |
|
232 | zeitwerk (~> 2.5) |
|
224 | rake (13.0.6) |
|
233 | rake (13.0.6) |
|
225 | rb-fsevent (0.11.2) |
|
234 | rb-fsevent (0.11.2) |
|
226 | rb-inotify (0.10.1) |
|
235 | rb-inotify (0.10.1) |
|
227 | ffi (~> 1.0) |
|
236 | ffi (~> 1.0) |
|
228 | rdiscount (2.2.0.2) |
|
237 | rdiscount (2.2.0.2) |
|
229 | regexp_parser (2.5.0) |
|
238 | regexp_parser (2.5.0) |
|
230 | rexml (3.2.5) |
|
239 | rexml (3.2.5) |
|
231 | rouge (4.0.0) |
|
240 | rouge (4.0.0) |
|
232 | ruby-progressbar (1.11.0) |
|
241 | ruby-progressbar (1.11.0) |
|
233 | ruby_parser (3.19.1) |
|
242 | ruby_parser (3.19.1) |
|
234 | sexp_processor (~> 4.16) |
|
243 | sexp_processor (~> 4.16) |
|
235 | rubyzip (2.3.2) |
|
244 | rubyzip (2.3.2) |
|
236 | sassc (2.4.0) |
|
245 | sassc (2.4.0) |
|
237 | ffi (~> 1.9) |
|
246 | ffi (~> 1.9) |
|
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) |
|
265 | strscan (3.0.4) |
|
271 | strscan (3.0.4) |
|
266 | temple (0.8.2) |
|
272 | temple (0.8.2) |
|
267 | thor (1.2.1) |
|
273 | thor (1.2.1) |
|
268 | tilt (2.0.11) |
|
274 | tilt (2.0.11) |
|
269 | timeout (0.3.0) |
|
275 | timeout (0.3.0) |
|
270 | tzinfo (2.0.5) |
|
276 | tzinfo (2.0.5) |
|
271 | concurrent-ruby (~> 1.0) |
|
277 | concurrent-ruby (~> 1.0) |
|
272 | web-console (4.2.0) |
|
278 | web-console (4.2.0) |
|
273 | actionview (>= 6.0.0) |
|
279 | actionview (>= 6.0.0) |
|
274 | activemodel (>= 6.0.0) |
|
280 | activemodel (>= 6.0.0) |
|
275 | bindex (>= 0.4.0) |
|
281 | bindex (>= 0.4.0) |
|
276 | railties (>= 6.0.0) |
|
282 | railties (>= 6.0.0) |
|
277 | webdrivers (5.1.0) |
|
283 | webdrivers (5.1.0) |
|
278 | nokogiri (~> 1.6) |
|
284 | nokogiri (~> 1.6) |
|
279 | rubyzip (>= 1.3.0) |
|
285 | rubyzip (>= 1.3.0) |
|
280 | selenium-webdriver (~> 4.0) |
|
286 | selenium-webdriver (~> 4.0) |
|
281 | websocket (1.2.9) |
|
287 | websocket (1.2.9) |
|
282 | websocket-driver (0.7.5) |
|
288 | websocket-driver (0.7.5) |
|
283 | websocket-extensions (>= 0.1.0) |
|
289 | websocket-extensions (>= 0.1.0) |
|
284 | websocket-extensions (0.1.5) |
|
290 | websocket-extensions (0.1.5) |
|
285 | xpath (3.2.0) |
|
291 | xpath (3.2.0) |
|
286 | nokogiri (~> 1.8) |
|
292 | nokogiri (~> 1.8) |
|
287 | zeitwerk (2.6.0) |
|
293 | zeitwerk (2.6.0) |
|
288 |
|
294 | ||
|
289 | PLATFORMS |
|
295 | PLATFORMS |
|
290 | x86_64-linux |
|
296 | x86_64-linux |
|
291 |
|
297 | ||
|
292 | DEPENDENCIES |
|
298 | DEPENDENCIES |
|
293 | ace-rails-ap |
|
299 | ace-rails-ap |
|
294 | best_in_place! |
|
300 | best_in_place! |
|
295 | bootsnap |
|
301 | bootsnap |
|
296 | bootstrap (~> 5.2) |
|
302 | bootstrap (~> 5.2) |
|
297 | byebug |
|
303 | byebug |
|
298 | capybara |
|
304 | capybara |
|
299 | coffee-rails |
|
305 | coffee-rails |
|
300 | fuzzy-string-match |
|
306 | fuzzy-string-match |
|
301 | haml |
|
307 | haml |
|
302 | haml-rails |
|
308 | haml-rails |
|
303 | importmap-rails (~> 1.1) |
|
309 | importmap-rails (~> 1.1) |
|
304 | jbuilder |
|
310 | jbuilder |
|
305 | jquery-rails |
|
311 | jquery-rails |
|
306 | listen (>= 3.0.5, < 3.2) |
|
312 | listen (>= 3.0.5, < 3.2) |
|
307 |
|
313 | ||
|
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 |
@@ -1,161 +1,157 | |||||
|
1 |
|
1 | ||
|
2 | .secondnavbar { |
|
2 | .secondnavbar { |
|
3 | top: 50px; |
|
3 | top: 50px; |
|
4 | } |
|
4 | } |
|
5 |
|
5 | ||
|
6 |
|
6 | ||
|
7 | //for google material design |
|
7 | //for google material design |
|
8 | .mi-bs { |
|
8 | .mi-bs { |
|
9 | vertical-align: middle; |
|
9 | vertical-align: middle; |
|
10 | position: relative; |
|
10 | position: relative; |
|
11 | top: -3px; |
|
11 | top: -3px; |
|
12 | } |
|
12 | } |
|
13 |
|
13 | ||
|
14 | // --------------- bootstrap file upload ---------------------- |
|
14 | // --------------- bootstrap file upload ---------------------- |
|
15 | .btn-file { |
|
15 | .btn-file { |
|
16 | position: relative; |
|
16 | position: relative; |
|
17 | overflow: hidden; |
|
17 | overflow: hidden; |
|
18 | } |
|
18 | } |
|
19 |
|
19 | ||
|
20 | .btn-file input[type=file] { |
|
20 | .btn-file input[type=file] { |
|
21 | position: absolute; |
|
21 | position: absolute; |
|
22 | top: 0; |
|
22 | top: 0; |
|
23 | right: 0; |
|
23 | right: 0; |
|
24 | min-width: 100%; |
|
24 | min-width: 100%; |
|
25 | min-height: 100%; |
|
25 | min-height: 100%; |
|
26 | font-size: 100px; |
|
26 | font-size: 100px; |
|
27 | text-align: right; |
|
27 | text-align: right; |
|
28 | filter: alpha(opacity = 0); |
|
28 | filter: alpha(opacity = 0); |
|
29 | opacity: 0; |
|
29 | opacity: 0; |
|
30 | outline: none; |
|
30 | outline: none; |
|
31 | background: white; |
|
31 | background: white; |
|
32 | cursor: inherit; |
|
32 | cursor: inherit; |
|
33 | display: block; |
|
33 | display: block; |
|
34 | } |
|
34 | } |
|
35 |
|
35 | ||
|
36 | body { |
|
36 | body { |
|
37 | //font-size: 13px |
|
37 | //font-size: 13px |
|
38 | font-family: 'Noto Sans Thai', Tahoma, "sans-serif"; |
|
38 | font-family: 'Noto Sans Thai', Tahoma, "sans-serif"; |
|
39 | margin: 10px; |
|
39 | margin: 10px; |
|
40 | padding: 10px; |
|
40 | padding: 10px; |
|
41 | padding-top: 60px; |
|
41 | padding-top: 60px; |
|
42 | } |
|
42 | } |
|
43 |
|
43 | ||
|
44 | // ------------------ bootstrap sortable -------------------- |
|
44 | // ------------------ bootstrap sortable -------------------- |
|
45 | table.sortable th { |
|
45 | table.sortable th { |
|
46 | padding-right: 20px !important; |
|
46 | padding-right: 20px !important; |
|
47 |
|
47 | ||
|
48 | span.sign { |
|
48 | span.sign { |
|
49 | right: (-15px) !important; |
|
49 | right: (-15px) !important; |
|
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 | } |
|
78 |
|
74 | ||
|
79 | //#a |
|
75 | //#a |
|
80 | // color: #6666cc |
|
76 | // color: #6666cc |
|
81 | // text-decoration: none |
|
77 | // text-decoration: none |
|
82 | // |
|
78 | // |
|
83 | // &:link, &:visited |
|
79 | // &:link, &:visited |
|
84 | // color: #6666cc |
|
80 | // color: #6666cc |
|
85 | // text-decoration: none |
|
81 | // text-decoration: none |
|
86 | // |
|
82 | // |
|
87 | // &:hover, &:focus |
|
83 | // &:hover, &:focus |
|
88 | // color: #111166 |
|
84 | // color: #111166 |
|
89 | // text-decoration: none |
|
85 | // text-decoration: none |
|
90 |
|
86 | ||
|
91 | div { |
|
87 | div { |
|
92 | &.userbar { |
|
88 | &.userbar { |
|
93 | line-height: 1.5em; |
|
89 | line-height: 1.5em; |
|
94 | text-align: right; |
|
90 | text-align: right; |
|
95 | font-size: 12px; |
|
91 | font-size: 12px; |
|
96 | } |
|
92 | } |
|
97 |
|
93 | ||
|
98 | &.title { |
|
94 | &.title { |
|
99 | padding: 10px 0px; |
|
95 | padding: 10px 0px; |
|
100 | line-height: 1.5em; |
|
96 | line-height: 1.5em; |
|
101 | font-size: 13px; |
|
97 | font-size: 13px; |
|
102 |
|
98 | ||
|
103 | span.contest-over-msg { |
|
99 | span.contest-over-msg { |
|
104 | font-size: 15px; |
|
100 | font-size: 15px; |
|
105 | color: red; |
|
101 | color: red; |
|
106 | } |
|
102 | } |
|
107 |
|
103 | ||
|
108 | table { |
|
104 | table { |
|
109 | width: 100%; |
|
105 | width: 100%; |
|
110 | font-weight: bold; |
|
106 | font-weight: bold; |
|
111 | } |
|
107 | } |
|
112 |
|
108 | ||
|
113 | td { |
|
109 | td { |
|
114 | &.left-col { |
|
110 | &.left-col { |
|
115 | text-align: left; |
|
111 | text-align: left; |
|
116 | vertical-align: top; |
|
112 | vertical-align: top; |
|
117 | color: #444444; |
|
113 | color: #444444; |
|
118 | } |
|
114 | } |
|
119 |
|
115 | ||
|
120 | &.right-col { |
|
116 | &.right-col { |
|
121 | text-align: right; |
|
117 | text-align: right; |
|
122 | vertical-align: top; |
|
118 | vertical-align: top; |
|
123 | font-size: 18px; |
|
119 | font-size: 18px; |
|
124 | color: #116699; |
|
120 | color: #116699; |
|
125 | } |
|
121 | } |
|
126 | } |
|
122 | } |
|
127 | } |
|
123 | } |
|
128 | } |
|
124 | } |
|
129 |
|
125 | ||
|
130 | table.info { |
|
126 | table.info { |
|
131 | margin: 10px 0; |
|
127 | margin: 10px 0; |
|
132 | border: 1px solid #666666; |
|
128 | border: 1px solid #666666; |
|
133 | border-collapse: collapse; |
|
129 | border-collapse: collapse; |
|
134 | font-size: 12px; |
|
130 | font-size: 12px; |
|
135 |
|
131 | ||
|
136 | th { |
|
132 | th { |
|
137 | border: 1px solid #666666; |
|
133 | border: 1px solid #666666; |
|
138 | line-height: 1.5em; |
|
134 | line-height: 1.5em; |
|
139 | padding: 0 0.5em; |
|
135 | padding: 0 0.5em; |
|
140 | } |
|
136 | } |
|
141 |
|
137 | ||
|
142 | td { |
|
138 | td { |
|
143 | border-left: 1px solid #666666; |
|
139 | border-left: 1px solid #666666; |
|
144 | border-right: 1px solid #666666; |
|
140 | border-right: 1px solid #666666; |
|
145 | line-height: 1.5em; |
|
141 | line-height: 1.5em; |
|
146 | padding: 0 0.5em; |
|
142 | padding: 0 0.5em; |
|
147 | } |
|
143 | } |
|
148 | } |
|
144 | } |
|
149 |
|
145 | ||
|
150 | tr { |
|
146 | tr { |
|
151 | &.info-head { |
|
147 | &.info-head { |
|
152 | background: #777777; |
|
148 | background: #777777; |
|
153 | color: white; |
|
149 | color: white; |
|
154 | } |
|
150 | } |
|
155 |
|
151 | ||
|
156 | &.info-odd { |
|
152 | &.info-odd { |
|
157 | background: #eeeeee; |
|
153 | background: #eeeeee; |
|
158 | } |
|
154 | } |
|
159 |
|
155 | ||
|
160 | &.info-even { |
|
156 | &.info-even { |
|
161 | background: #fcfcfc; |
|
157 | background: #fcfcfc; |
@@ -1,127 +1,134 | |||||
|
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) |
|
44 | return false unless check_valid_login |
|
51 | return false unless check_valid_login |
|
45 | user = User.find(session[:user_id]) |
|
52 | user = User.find(session[:user_id]) |
|
46 | return true if user.admin? |
|
53 | return true if user.admin? |
|
47 | roles.each do |r| |
|
54 | roles.each do |r| |
|
48 | return true if user.has_role?(r) |
|
55 | return true if user.has_role?(r) |
|
49 | end |
|
56 | end |
|
50 | unauthorized_redirect |
|
57 | unauthorized_redirect |
|
51 | end |
|
58 | end |
|
52 |
|
59 | ||
|
53 | def authorization_by_roles(allowed_roles) |
|
60 | def authorization_by_roles(allowed_roles) |
|
54 | return false unless check_valid_login |
|
61 | return false unless check_valid_login |
|
55 | unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) } |
|
62 | unless @current_user.roles.detect { |role| allowed_roles.member?(role.name) } |
|
56 | unauthorized_redirect |
|
63 | unauthorized_redirect |
|
57 | return false |
|
64 | return false |
|
58 | end |
|
65 | end |
|
59 | end |
|
66 | end |
|
60 |
|
67 | ||
|
61 | def testcase_authorization |
|
68 | def testcase_authorization |
|
62 | #admin always has privileged |
|
69 | #admin always has privileged |
|
63 | if @current_user.admin? |
|
70 | if @current_user.admin? |
|
64 | return true |
|
71 | return true |
|
65 | end |
|
72 | end |
|
66 |
|
73 | ||
|
67 | unauthorized_redirect unless GraderConfiguration["right.view_testcase"] |
|
74 | unauthorized_redirect unless GraderConfiguration["right.view_testcase"] |
|
68 | end |
|
75 | end |
|
69 |
|
76 | ||
|
70 | def unique_visitor_id |
|
77 | def unique_visitor_id |
|
71 | unless cookies.encrypted[:uuid] |
|
78 | unless cookies.encrypted[:uuid] |
|
72 | value = SecureRandom.uuid |
|
79 | value = SecureRandom.uuid |
|
73 | cookies.encrypted[:uuid] = { value: value, expires: 20.year } |
|
80 | cookies.encrypted[:uuid] = { value: value, expires: 20.year } |
|
74 | end |
|
81 | end |
|
75 | end |
|
82 | end |
|
76 |
|
83 | ||
|
77 | protected |
|
84 | protected |
|
78 |
|
85 | ||
|
79 | #redirect to root (and also force logout) |
|
86 | #redirect to root (and also force logout) |
|
80 | #if the user is not logged_in or the system is in "ADMIN ONLY" mode |
|
87 | #if the user is not logged_in or the system is in "ADMIN ONLY" mode |
|
81 | def check_valid_login |
|
88 | def check_valid_login |
|
82 | #check if logged in |
|
89 | #check if logged in |
|
83 | unless session[:user_id] |
|
90 | unless session[:user_id] |
|
84 | if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY] |
|
91 | if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY] |
|
85 | unauthorized_redirect('You need to login but you cannot log in at this time') |
|
92 | unauthorized_redirect('You need to login but you cannot log in at this time') |
|
86 | else |
|
93 | else |
|
87 | unauthorized_redirect('You need to login') |
|
94 | unauthorized_redirect('You need to login') |
|
88 | end |
|
95 | end |
|
89 | return false |
|
96 | return false |
|
90 | end |
|
97 | end |
|
91 |
|
98 | ||
|
92 | # check if run in single user mode |
|
99 | # check if run in single user mode |
|
93 | if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY] |
|
100 | if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY] |
|
94 | if @current_user==nil || (!@current_user.admin?) |
|
101 | if @current_user==nil || (!@current_user.admin?) |
|
95 | unauthorized_redirect('You cannot log in at this time') |
|
102 | unauthorized_redirect('You cannot log in at this time') |
|
96 | return false |
|
103 | return false |
|
97 | end |
|
104 | end |
|
98 | end |
|
105 | end |
|
99 |
|
106 | ||
|
100 | # check if the user is enabled |
|
107 | # check if the user is enabled |
|
101 | unless @current_user.enabled? || @current_user.admin? |
|
108 | unless @current_user.enabled? || @current_user.admin? |
|
102 | unauthorized_redirect 'Your account is disabled' |
|
109 | unauthorized_redirect 'Your account is disabled' |
|
103 | return false |
|
110 | return false |
|
104 | end |
|
111 | end |
|
105 |
|
112 | ||
|
106 | # check if user ip is allowed |
|
113 | # check if user ip is allowed |
|
107 | unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY] |
|
114 | unless @current_user.admin? || GraderConfiguration[WHITELIST_IGNORE_CONF_KEY] |
|
108 | unless is_request_ip_allowed? |
|
115 | unless is_request_ip_allowed? |
|
109 | unauthorized_redirect 'Your IP is not allowed to login at this time.' |
|
116 | unauthorized_redirect 'Your IP is not allowed to login at this time.' |
|
110 | return false |
|
117 | return false |
|
111 | end |
|
118 | end |
|
112 | end |
|
119 | end |
|
113 |
|
120 | ||
|
114 | if GraderConfiguration.multicontests? |
|
121 | if GraderConfiguration.multicontests? |
|
115 | return true if @current_user.admin? |
|
122 | return true if @current_user.admin? |
|
116 | begin |
|
123 | begin |
|
117 | if @current_user.contest_stat(true).forced_logout |
|
124 | if @current_user.contest_stat(true).forced_logout |
|
118 | flash[:notice] = 'You have been automatically logged out.' |
|
125 | flash[:notice] = 'You have been automatically logged out.' |
|
119 | redirect_to :controller => 'main', :action => 'index' |
|
126 | redirect_to :controller => 'main', :action => 'index' |
|
120 | end |
|
127 | end |
|
121 | rescue |
|
128 | rescue |
|
122 | end |
|
129 | end |
|
123 | end |
|
130 | end |
|
124 | return true |
|
131 | return true |
|
125 | end |
|
132 | end |
|
126 |
|
133 | ||
|
127 | #redirect to root (and also force logout) |
|
134 | #redirect to root (and also force logout) |
@@ -1,306 +1,287 | |||||
|
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 |
- |
|
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.' |
|
||
|
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 |
|
|
82 | @problem.save |
|
102 | - end |
|
83 | + redirect_to edit_problem_path(@problem) |
|
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 |
|
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 |
|
168 | @histogram[:data][d.to_i] += 1 if d < range |
|
144 | @histogram[:data][d.to_i] += 1 if d < range |
|
169 | user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max |
|
145 | user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max |
|
170 | end |
|
146 | end |
|
171 | @histogram[:summary][:max] = [@histogram[:data].max,1].max |
|
147 | @histogram[:summary][:max] = [@histogram[:data].max,1].max |
|
172 |
|
148 | ||
|
173 | @summary = { attempt: user.count, solve: 0 } |
|
149 | @summary = { attempt: user.count, solve: 0 } |
|
174 | user.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
150 | user.each_value { |v| @summary[:solve] += 1 if v == 1 } |
|
175 | end |
|
151 | end |
|
176 |
|
152 | ||
|
177 | def manage |
|
153 | def manage |
|
178 | @problems = Problem.order(date_added: :desc) |
|
154 | @problems = Problem.order(date_added: :desc) |
|
179 | end |
|
155 | end |
|
180 |
|
156 | ||
|
181 | def do_manage |
|
157 | def do_manage |
|
182 | if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false |
|
158 | if params.has_key? 'change_date_added' and params[:date_added].strip.empty? == false |
|
183 | change_date_added |
|
159 | change_date_added |
|
184 | elsif params.has_key? 'add_to_contest' |
|
160 | elsif params.has_key? 'add_to_contest' |
|
185 | add_to_contest |
|
161 | add_to_contest |
|
186 | elsif params.has_key? 'enable_problem' |
|
162 | elsif params.has_key? 'enable_problem' |
|
187 | set_available(true) |
|
163 | set_available(true) |
|
188 | elsif params.has_key? 'disable_problem' |
|
164 | elsif params.has_key? 'disable_problem' |
|
189 | set_available(false) |
|
165 | set_available(false) |
|
190 | elsif params.has_key? 'add_group' |
|
166 | elsif params.has_key? 'add_group' |
|
191 | group = Group.find(params[:group_id]) |
|
167 | group = Group.find(params[:group_id]) |
|
192 | ok = [] |
|
168 | ok = [] |
|
193 | failed = [] |
|
169 | failed = [] |
|
194 | get_problems_from_params.each do |p| |
|
170 | get_problems_from_params.each do |p| |
|
195 | begin |
|
171 | begin |
|
196 | group.problems << p |
|
172 | group.problems << p |
|
197 | ok << p.full_name |
|
173 | ok << p.full_name |
|
198 | rescue => e |
|
174 | rescue => e |
|
199 | failed << p.full_name |
|
175 | failed << p.full_name |
|
200 | end |
|
176 | end |
|
201 | end |
|
177 | end |
|
202 | flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0 |
|
178 | flash[:success] = "The following problems are added to the group #{group.name}: " + ok.join(', ') if ok.count > 0 |
|
203 | flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0 |
|
179 | flash[:alert] = "The following problems are already in the group #{group.name}: " + failed.join(', ') if failed.count > 0 |
|
204 | elsif params.has_key? 'add_tags' |
|
180 | elsif params.has_key? 'add_tags' |
|
205 | get_problems_from_params.each do |p| |
|
181 | get_problems_from_params.each do |p| |
|
206 | p.tag_ids += params[:tag_ids] |
|
182 | p.tag_ids += params[:tag_ids] |
|
207 | end |
|
183 | end |
|
208 | end |
|
184 | end |
|
209 |
|
185 | ||
|
210 | redirect_to :action => 'manage' |
|
186 | redirect_to :action => 'manage' |
|
211 | end |
|
187 | end |
|
212 |
|
188 | ||
|
213 | def import |
|
189 | def import |
|
214 | @allow_test_pair_import = allow_test_pair_import? |
|
190 | @allow_test_pair_import = allow_test_pair_import? |
|
215 | end |
|
191 | end |
|
216 |
|
192 | ||
|
217 | def do_import |
|
193 | def do_import |
|
218 | old_problem = Problem.find_by_name(params[:name]) |
|
194 | old_problem = Problem.find_by_name(params[:name]) |
|
219 | if !allow_test_pair_import? and params.has_key? :import_to_db |
|
195 | if !allow_test_pair_import? and params.has_key? :import_to_db |
|
220 | params.delete :import_to_db |
|
196 | params.delete :import_to_db |
|
221 | end |
|
197 | end |
|
222 | @problem, import_log = Problem.create_from_import_form_params(params, |
|
198 | @problem, import_log = Problem.create_from_import_form_params(params, |
|
223 | old_problem) |
|
199 | old_problem) |
|
224 |
|
200 | ||
|
225 | if !@problem.errors.empty? |
|
201 | if !@problem.errors.empty? |
|
226 | render :action => 'import' and return |
|
202 | render :action => 'import' and return |
|
227 | end |
|
203 | end |
|
228 |
|
204 | ||
|
229 | if old_problem!=nil |
|
205 | if old_problem!=nil |
|
230 | flash[:notice] = "The test data has been replaced for problem #{@problem.name}" |
|
206 | flash[:notice] = "The test data has been replaced for problem #{@problem.name}" |
|
231 | end |
|
207 | end |
|
232 | @log = import_log |
|
208 | @log = import_log |
|
233 | end |
|
209 | end |
|
234 |
|
210 | ||
|
235 | def remove_contest |
|
211 | def remove_contest |
|
236 | problem = Problem.find(params[:id]) |
|
212 | problem = Problem.find(params[:id]) |
|
237 | contest = Contest.find(params[:contest_id]) |
|
213 | contest = Contest.find(params[:contest_id]) |
|
238 | if problem!=nil and contest!=nil |
|
214 | if problem!=nil and contest!=nil |
|
239 | problem.contests.delete(contest) |
|
215 | problem.contests.delete(contest) |
|
240 | end |
|
216 | end |
|
241 | redirect_to :action => 'manage' |
|
217 | redirect_to :action => 'manage' |
|
242 | end |
|
218 | end |
|
243 |
|
219 | ||
|
244 | ################################## |
|
220 | ################################## |
|
245 | protected |
|
221 | protected |
|
246 |
|
222 | ||
|
247 | def allow_test_pair_import? |
|
223 | def allow_test_pair_import? |
|
248 | if defined? ALLOW_TEST_PAIR_IMPORT |
|
224 | if defined? ALLOW_TEST_PAIR_IMPORT |
|
249 | return ALLOW_TEST_PAIR_IMPORT |
|
225 | return ALLOW_TEST_PAIR_IMPORT |
|
250 | else |
|
226 | else |
|
251 | return false |
|
227 | return false |
|
252 | end |
|
228 | end |
|
253 | end |
|
229 | end |
|
254 |
|
230 | ||
|
255 | def change_date_added |
|
231 | def change_date_added |
|
256 | problems = get_problems_from_params |
|
232 | problems = get_problems_from_params |
|
257 | date = Date.parse(params[:date_added]) |
|
233 | date = Date.parse(params[:date_added]) |
|
258 | problems.each do |p| |
|
234 | problems.each do |p| |
|
259 | p.date_added = date |
|
235 | p.date_added = date |
|
260 | p.save |
|
236 | p.save |
|
261 | end |
|
237 | end |
|
262 | end |
|
238 | end |
|
263 |
|
239 | ||
|
264 | def add_to_contest |
|
240 | def add_to_contest |
|
265 | problems = get_problems_from_params |
|
241 | problems = get_problems_from_params |
|
266 | contest = Contest.find(params[:contest][:id]) |
|
242 | contest = Contest.find(params[:contest][:id]) |
|
267 | if contest!=nil and contest.enabled |
|
243 | if contest!=nil and contest.enabled |
|
268 | problems.each do |p| |
|
244 | problems.each do |p| |
|
269 | p.contests << contest |
|
245 | p.contests << contest |
|
270 | end |
|
246 | end |
|
271 | end |
|
247 | end |
|
272 | end |
|
248 | end |
|
273 |
|
249 | ||
|
274 | def set_available(avail) |
|
250 | def set_available(avail) |
|
275 | problems = get_problems_from_params |
|
251 | problems = get_problems_from_params |
|
276 | problems.each do |p| |
|
252 | problems.each do |p| |
|
277 | p.available = avail |
|
253 | p.available = avail |
|
278 | p.save |
|
254 | p.save |
|
279 | end |
|
255 | end |
|
280 | end |
|
256 | end |
|
281 |
|
257 | ||
|
282 | def get_problems_from_params |
|
258 | def get_problems_from_params |
|
283 | problems = [] |
|
259 | problems = [] |
|
284 | params.keys.each do |k| |
|
260 | params.keys.each do |k| |
|
285 | if k.index('prob-')==0 |
|
261 | if k.index('prob-')==0 |
|
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, |
|
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 |
@@ -116,97 +116,108 | |||||
|
116 | btn_block = option[:block] || 'btn-block' |
|
116 | btn_block = option[:block] || 'btn-block' |
|
117 | link_to (on ? "Yes" : "No"), toggle_url, |
|
117 | link_to (on ? "Yes" : "No"), toggle_url, |
|
118 | {class: "btn #{btn_block} #{btn_size} btn-#{on ? 'success' : 'outline-secondary'} ajax-toggle", |
|
118 | {class: "btn #{btn_block} #{btn_size} btn-#{on ? 'success' : 'outline-secondary'} ajax-toggle", |
|
119 | id: id, |
|
119 | id: id, |
|
120 | data: {remote: true, method: 'get'}} |
|
120 | data: {remote: true, method: 'get'}} |
|
121 | end |
|
121 | end |
|
122 |
|
122 | ||
|
123 | def get_ace_mode(language) |
|
123 | def get_ace_mode(language) |
|
124 | # return ace mode string from Language |
|
124 | # return ace mode string from Language |
|
125 |
|
125 | ||
|
126 | case language.pretty_name |
|
126 | case language.pretty_name |
|
127 | when 'Pascal' |
|
127 | when 'Pascal' |
|
128 | 'ace/mode/pascal' |
|
128 | 'ace/mode/pascal' |
|
129 | when 'C++','C' |
|
129 | when 'C++','C' |
|
130 | 'ace/mode/c_cpp' |
|
130 | 'ace/mode/c_cpp' |
|
131 | when 'Ruby' |
|
131 | when 'Ruby' |
|
132 | 'ace/mode/ruby' |
|
132 | 'ace/mode/ruby' |
|
133 | when 'Python' |
|
133 | when 'Python' |
|
134 | 'ace/mode/python' |
|
134 | 'ace/mode/python' |
|
135 | when 'Java' |
|
135 | when 'Java' |
|
136 | 'ace/mode/java' |
|
136 | 'ace/mode/java' |
|
137 | else |
|
137 | else |
|
138 | 'ace/mode/c_cpp' |
|
138 | 'ace/mode/c_cpp' |
|
139 | end |
|
139 | end |
|
140 | end |
|
140 | end |
|
141 |
|
141 | ||
|
142 |
|
142 | ||
|
143 | def user_title_bar(user) |
|
143 | def user_title_bar(user) |
|
144 | header = '' |
|
144 | header = '' |
|
145 | time_left = '' |
|
145 | time_left = '' |
|
146 |
|
146 | ||
|
147 | # |
|
147 | # |
|
148 | # if the contest is over |
|
148 | # if the contest is over |
|
149 | if GraderConfiguration.time_limit_mode? |
|
149 | if GraderConfiguration.time_limit_mode? |
|
150 | if user.contest_finished? |
|
150 | if user.contest_finished? |
|
151 | header = <<CONTEST_OVER |
|
151 | header = <<CONTEST_OVER |
|
152 | <tr><td colspan="2" align="center"> |
|
152 | <tr><td colspan="2" align="center"> |
|
153 | <span class="contest-over-msg">THE CONTEST IS OVER</span> |
|
153 | <span class="contest-over-msg">THE CONTEST IS OVER</span> |
|
154 | </td></tr> |
|
154 | </td></tr> |
|
155 | CONTEST_OVER |
|
155 | CONTEST_OVER |
|
156 | end |
|
156 | end |
|
157 | if !user.contest_started? |
|
157 | if !user.contest_started? |
|
158 | time_left = " " + (t 'title_bar.contest_not_started') |
|
158 | time_left = " " + (t 'title_bar.contest_not_started') |
|
159 | else |
|
159 | else |
|
160 | time_left = " " + (t 'title_bar.remaining_time') + |
|
160 | time_left = " " + (t 'title_bar.remaining_time') + |
|
161 | " #{format_short_duration(user.contest_time_left)}" |
|
161 | " #{format_short_duration(user.contest_time_left)}" |
|
162 | end |
|
162 | end |
|
163 | end |
|
163 | end |
|
164 |
|
164 | ||
|
165 | # |
|
165 | # |
|
166 | # if the contest is in the anaysis mode |
|
166 | # if the contest is in the anaysis mode |
|
167 | if GraderConfiguration.analysis_mode? |
|
167 | if GraderConfiguration.analysis_mode? |
|
168 | header = <<ANALYSISMODE |
|
168 | header = <<ANALYSISMODE |
|
169 | <tr><td colspan="2" align="center"> |
|
169 | <tr><td colspan="2" align="center"> |
|
170 | <span class="contest-over-msg">ANALYSIS MODE</span> |
|
170 | <span class="contest-over-msg">ANALYSIS MODE</span> |
|
171 | </td></tr> |
|
171 | </td></tr> |
|
172 | ANALYSISMODE |
|
172 | ANALYSISMODE |
|
173 | end |
|
173 | end |
|
174 |
|
174 | ||
|
175 | contest_name = GraderConfiguration['contest.name'] |
|
175 | contest_name = GraderConfiguration['contest.name'] |
|
176 |
|
176 | ||
|
177 | # |
|
177 | # |
|
178 | # build real title bar |
|
178 | # build real title bar |
|
179 | result = <<TITLEBAR |
|
179 | result = <<TITLEBAR |
|
180 | <div class="title"> |
|
180 | <div class="title"> |
|
181 | <table> |
|
181 | <table> |
|
182 | #{header} |
|
182 | #{header} |
|
183 | <tr> |
|
183 | <tr> |
|
184 | <td class="left-col"> |
|
184 | <td class="left-col"> |
|
185 | <br/> |
|
185 | <br/> |
|
186 | </td> |
|
186 | </td> |
|
187 | <td class="right-col">#{contest_name}</td> |
|
187 | <td class="right-col">#{contest_name}</td> |
|
188 | </tr> |
|
188 | </tr> |
|
189 | </table> |
|
189 | </table> |
|
190 | </div> |
|
190 | </div> |
|
191 | TITLEBAR |
|
191 | TITLEBAR |
|
192 | result.html_safe |
|
192 | result.html_safe |
|
193 | end |
|
193 | end |
|
194 |
|
194 | ||
|
195 | def markdown(text) |
|
195 | def markdown(text) |
|
196 | markdown = RDiscount.new(text) |
|
196 | markdown = RDiscount.new(text) |
|
197 | markdown.to_html.html_safe |
|
197 | markdown.to_html.html_safe |
|
198 | end |
|
198 | end |
|
199 |
|
199 | ||
|
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 | ||
|
212 | end |
|
218 | end |
|
|
219 | + return class_name if ok && options.size > 0 | ||
|
|
220 | + return '' | ||
|
|
221 | + end | ||
|
|
222 | + | ||
|
|
223 | + end |
@@ -1,122 +1,126 | |||||
|
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 |
|
39 | #label << ' ' |
|
43 | #label << ' ' |
|
40 | #label << (start_date+i).strftime("%d") |
|
44 | #label << (start_date+i).strftime("%d") |
|
41 | end |
|
45 | end |
|
42 | label << (start_date+i).strftime("%d-%b") |
|
46 | label << (start_date+i).strftime("%d-%b") |
|
43 | value << (count[start_date+i] || 0) |
|
47 | value << (count[start_date+i] || 0) |
|
44 | i+=1 |
|
48 | i+=1 |
|
45 | end |
|
49 | end |
|
46 | return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']} |
|
50 | return {labels: label,datasets: [label:'sub',data: value, backgroundColor: 'rgba(54, 162, 235, 0.2)', borderColor: 'rgb(75, 192, 192)']} |
|
47 | end |
|
51 | end |
|
48 |
|
52 | ||
|
49 | def self.available_problems |
|
53 | def self.available_problems |
|
50 | available.order(date_added: :desc).order(:name) |
|
54 | available.order(date_added: :desc).order(:name) |
|
51 | #Problem.available.all(:order => "date_added DESC, name ASC") |
|
55 | #Problem.available.all(:order => "date_added DESC, name ASC") |
|
52 | end |
|
56 | end |
|
53 |
|
57 | ||
|
54 | def self.create_from_import_form_params(params, old_problem=nil) |
|
58 | def self.create_from_import_form_params(params, old_problem=nil) |
|
55 | org_problem = old_problem || Problem.new |
|
59 | org_problem = old_problem || Problem.new |
|
56 | import_params, problem = Problem.extract_params_and_check(params, |
|
60 | import_params, problem = Problem.extract_params_and_check(params, |
|
57 | org_problem) |
|
61 | org_problem) |
|
58 |
|
62 | ||
|
59 | if !problem.errors.empty? |
|
63 | if !problem.errors.empty? |
|
60 | return problem, 'Error importing' |
|
64 | return problem, 'Error importing' |
|
61 | end |
|
65 | end |
|
62 |
|
66 | ||
|
63 | problem.full_score = 100 |
|
67 | problem.full_score = 100 |
|
64 | problem.date_added = Time.new |
|
68 | problem.date_added = Time.new |
|
65 | problem.test_allowed = true |
|
69 | problem.test_allowed = true |
|
66 | problem.output_only = false |
|
70 | problem.output_only = false |
|
67 | problem.available = false |
|
71 | problem.available = false |
|
68 |
|
72 | ||
|
69 | if not problem.save |
|
73 | if not problem.save |
|
70 | return problem, 'Error importing' |
|
74 | return problem, 'Error importing' |
|
71 | end |
|
75 | end |
|
72 |
|
76 | ||
|
73 | import_to_db = params.has_key? :import_to_db |
|
77 | import_to_db = params.has_key? :import_to_db |
|
74 |
|
78 | ||
|
75 | importer = TestdataImporter.new(problem) |
|
79 | importer = TestdataImporter.new(problem) |
|
76 |
|
80 | ||
|
77 | if not importer.import_from_file(import_params[:file], |
|
81 | if not importer.import_from_file(import_params[:file], |
|
78 | import_params[:time_limit], |
|
82 | import_params[:time_limit], |
|
79 | import_params[:memory_limit], |
|
83 | import_params[:memory_limit], |
|
80 | import_params[:checker_name], |
|
84 | import_params[:checker_name], |
|
81 | import_to_db) |
|
85 | import_to_db) |
|
82 | problem.errors.add(:base,'Import error.') |
|
86 | problem.errors.add(:base,'Import error.') |
|
83 | end |
|
87 | end |
|
84 |
|
88 | ||
|
85 | return problem, importer.log_msg |
|
89 | return problem, importer.log_msg |
|
86 | end |
|
90 | end |
|
87 |
|
91 | ||
|
88 | def self.download_file_basedir |
|
92 | def self.download_file_basedir |
|
89 | return "#{Rails.root}/data/tasks" |
|
93 | return "#{Rails.root}/data/tasks" |
|
90 | end |
|
94 | end |
|
91 |
|
95 | ||
|
92 | def get_submission_stat |
|
96 | def get_submission_stat |
|
93 | result = Hash.new |
|
97 | result = Hash.new |
|
94 | #total number of submission |
|
98 | #total number of submission |
|
95 | result[:total_sub] = Submission.where(problem_id: self.id).count |
|
99 | result[:total_sub] = Submission.where(problem_id: self.id).count |
|
96 | result[:attempted_user] = Submission.where(problem_id: self.id).group(:user_id) |
|
100 | result[:attempted_user] = Submission.where(problem_id: self.id).group(:user_id) |
|
97 | result[:pass] = Submission.where(problem_id: self.id).where("points >= ?",self.full_score).count |
|
101 | result[:pass] = Submission.where(problem_id: self.id).where("points >= ?",self.full_score).count |
|
98 | return result |
|
102 | return result |
|
99 | end |
|
103 | end |
|
100 |
|
104 | ||
|
101 | def long_name |
|
105 | def long_name |
|
102 | "[#{name}] #{full_name}" |
|
106 | "[#{name}] #{full_name}" |
|
103 | end |
|
107 | end |
|
104 |
|
108 | ||
|
105 | protected |
|
109 | protected |
|
106 |
|
110 | ||
|
107 | def self.to_i_or_default(st, default) |
|
111 | def self.to_i_or_default(st, default) |
|
108 | if st!='' |
|
112 | if st!='' |
|
109 | result = st.to_i |
|
113 | result = st.to_i |
|
110 | end |
|
114 | end |
|
111 | result ||= default |
|
115 | result ||= default |
|
112 | end |
|
116 | end |
|
113 |
|
117 | ||
|
114 | def self.to_f_or_default(st, default) |
|
118 | def self.to_f_or_default(st, default) |
|
115 | if st!='' |
|
119 | if st!='' |
|
116 | result = st.to_f |
|
120 | result = st.to_f |
|
117 | end |
|
121 | end |
|
118 | result ||= default |
|
122 | result ||= default |
|
119 | end |
|
123 | end |
|
120 |
|
124 | ||
|
121 | def self.extract_params_and_check(params, problem) |
|
125 | def self.extract_params_and_check(params, problem) |
|
122 | time_limit = Problem.to_f_or_default(params[:time_limit], |
|
126 | time_limit = Problem.to_f_or_default(params[:time_limit], |
@@ -1,87 +1,93 | |||||
|
1 | %header |
|
1 | %header |
|
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'}, |
|
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 | + = 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 | + -# | ||
|
1 | = error_messages_for 'problem' |
|
23 | = error_messages_for 'problem' |
|
|
24 | + | ||
|
2 |
|
|
25 | / [form:problem] |
|
3 | .form-group |
|
26 | .form-group |
|
4 | %label{:for => "problem_name"} Name |
|
27 | %label{:for => "problem_name"} Name |
|
5 | = text_field 'problem', 'name', class: 'form-control' |
|
28 | = text_field 'problem', 'name', class: 'form-control' |
|
6 | %small |
|
29 | %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. |
|
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. |
|
8 | .form-group |
|
31 | .form-group |
|
9 | %label{:for => "problem_full_name"} Full name |
|
32 | %label{:for => "problem_full_name"} Full name |
|
10 | = text_field 'problem', 'full_name', class: 'form-control' |
|
33 | = text_field 'problem', 'full_name', class: 'form-control' |
|
11 | .form-group |
|
34 | .form-group |
|
12 | %label{:for => "problem_full_score"} Full score |
|
35 | %label{:for => "problem_full_score"} Full score |
|
13 | = text_field 'problem', 'full_score', class: 'form-control' |
|
36 | = text_field 'problem', 'full_score', class: 'form-control' |
|
14 | .form-group |
|
37 | .form-group |
|
15 | %label{:for => "problem_full_score"} Tags |
|
38 | %label{:for => "problem_full_score"} Tags |
|
16 | = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'}) |
|
39 | = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'}) |
|
17 | .form-group |
|
40 | .form-group |
|
18 | %label{:for => "problem_date_added"} Date added |
|
41 | %label{:for => "problem_date_added"} Date added |
|
19 | = date_select 'problem', 'date_added', class: 'form-control' |
|
42 | = date_select 'problem', 'date_added', class: 'form-control' |
|
20 |
|
|
43 | - # TODO: these should be put in model Problem, but I can't think of |
|
21 |
|
|
44 | - # nice default values for them. These values look fine only |
|
22 |
|
|
45 | - # in this case (of lazily adding new problems). |
|
23 |
|
|
46 | - @problem.available = true if @problem!=nil and @problem.available==nil |
|
24 |
|
|
47 | - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil |
|
25 |
|
|
48 | - @problem.output_only = false if @problem!=nil and @problem.output_only==nil |
|
26 | .checkbox |
|
49 | .checkbox |
|
27 | %label{:for => "problem_available"} |
|
50 | %label{:for => "problem_available"} |
|
28 | = check_box :problem, :available |
|
51 | = check_box :problem, :available |
|
29 | Available? |
|
52 | Available? |
|
30 | .checkbox |
|
53 | .checkbox |
|
31 | %label{:for => "problem_test_allowed"} |
|
54 | %label{:for => "problem_test_allowed"} |
|
32 | = check_box :problem, :test_allowed |
|
55 | = check_box :problem, :test_allowed |
|
33 | Test allowed? |
|
56 | Test allowed? |
|
34 | .checkbox |
|
57 | .checkbox |
|
35 | %label{:for => "problem_output_only"} |
|
58 | %label{:for => "problem_output_only"} |
|
36 | = check_box :problem, :output_only |
|
59 | = check_box :problem, :output_only |
|
37 | Output only? |
|
60 | Output only? |
|
38 |
|
|
61 | = error_messages_for 'description' |
|
39 | .form-group |
|
62 | .form-group |
|
40 | %label{:for => "description_body"} Description |
|
63 | %label{:for => "description_body"} Description |
|
41 | %br/ |
|
64 | %br/ |
|
42 | = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control' |
|
65 | = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control' |
|
43 | .form-group |
|
66 | .form-group |
|
44 | %label{:for => "description_markdowned"} Markdowned? |
|
67 | %label{:for => "description_markdowned"} Markdowned? |
|
45 | = select "description", | |
|
68 | = select "description", | |
|
46 | "markdowned", | |
|
69 | "markdowned", | |
|
47 | [['True',true],['False',false]], | |
|
70 | [['True',true],['False',false]], | |
|
48 | {:selected => (@description) ? @description.markdowned : false } | |
|
71 | {:selected => (@description) ? @description.markdowned : false } | |
|
49 | .form-group |
|
72 | .form-group |
|
50 | %label{:for => "problem_url"} URL |
|
73 | %label{:for => "problem_url"} URL |
|
51 | %br/ |
|
74 | %br/ |
|
52 | = text_field 'problem', 'url',class: 'form-control' |
|
75 | = text_field 'problem', 'url',class: 'form-control' |
|
53 | %p |
|
76 | %p |
|
54 | Task PDF #{file_field_tag 'file'} |
|
77 | Task PDF #{file_field_tag 'file'} |
|
55 |
|
|
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 |
|
||
|
6 | - = render :partial => 'form' |
|
||
|
7 | - .row |
|
||
|
8 |
|
|
5 | .col-md-4 |
|
9 | - = submit_tag 'Edit', class: 'btn btn-primary btn-block' |
|
6 | + = link_to 'Back', problems_path, class: 'btn btn-secondary' |
|
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,65 +1,67 | |||||
|
1 | - content_for :head do |
|
1 | - content_for :head do |
|
2 | = stylesheet_link_tag 'problems' |
|
2 | = stylesheet_link_tag 'problems' |
|
3 | %h1 Problems |
|
3 | %h1 Problems |
|
4 | %p |
|
4 | %p |
|
5 | = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-success btn-sm' |
|
5 | = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-success btn-sm' |
|
6 | = link_to 'New problem', new_problem_path, class: 'btn btn-success btn-sm' |
|
6 | = link_to 'New problem', new_problem_path, class: 'btn btn-success btn-sm' |
|
7 | = link_to 'Bulk Manage', { action: 'manage'}, class: 'btn btn-info btn-sm' |
|
7 | = link_to 'Bulk Manage', { action: 'manage'}, class: 'btn btn-info btn-sm' |
|
8 | = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-secondary btn-sm' |
|
8 | = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-secondary btn-sm' |
|
9 | = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-secondary btn-sm' |
|
9 | = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-secondary btn-sm' |
|
10 | .submitbox |
|
10 | .submitbox |
|
11 | = form_tag action: 'quick_create', controller: 'problems' do |
|
11 | = form_tag action: 'quick_create', controller: 'problems' do |
|
12 | %b Quick New: |
|
12 | %b Quick New: |
|
13 | %label{:for => "problem_name"} Name |
|
13 | %label{:for => "problem_name"} Name |
|
14 | = text_field 'problem', 'name' |
|
14 | = text_field 'problem', 'name' |
|
15 | | |
|
15 | | |
|
16 | %label{:for => "problem_full_name"} Full name |
|
16 | %label{:for => "problem_full_name"} Full name |
|
17 | = text_field 'problem', 'full_name' |
|
17 | = text_field 'problem', 'full_name' |
|
18 | = submit_tag "Create" |
|
18 | = submit_tag "Create" |
|
19 | %table.table.table-condense.table-hover |
|
19 | %table.table.table-condense.table-hover |
|
20 | %thead |
|
20 | %thead |
|
21 | %th Name |
|
21 | %th Name |
|
22 | %th Full name |
|
22 | %th Full name |
|
23 | %th.text-right Full score |
|
23 | %th.text-right Full score |
|
24 | %th Tags |
|
24 | %th Tags |
|
25 | %th |
|
25 | %th |
|
26 | Submit |
|
26 | Submit |
|
27 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Admin can always submit to any problem' } [?] |
|
27 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Admin can always submit to any problem' } [?] |
|
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' |
@@ -19,158 +19,158 | |||||
|
19 | # Any of these extensions can be disabled for a |
|
19 | # Any of these extensions can be disabled for a |
|
20 | # given input by passing: `f.input EXTENSION_NAME => false`. |
|
20 | # given input by passing: `f.input EXTENSION_NAME => false`. |
|
21 | # You can make any of these extensions optional by |
|
21 | # You can make any of these extensions optional by |
|
22 | # renaming `b.use` to `b.optional`. |
|
22 | # renaming `b.use` to `b.optional`. |
|
23 |
|
23 | ||
|
24 | # Determines whether to use HTML5 (:email, :url, ...) |
|
24 | # Determines whether to use HTML5 (:email, :url, ...) |
|
25 | # and required attributes |
|
25 | # and required attributes |
|
26 | b.use :html5 |
|
26 | b.use :html5 |
|
27 |
|
27 | ||
|
28 | # Calculates placeholders automatically from I18n |
|
28 | # Calculates placeholders automatically from I18n |
|
29 | # You can also pass a string as f.input placeholder: "Placeholder" |
|
29 | # You can also pass a string as f.input placeholder: "Placeholder" |
|
30 | b.use :placeholder |
|
30 | b.use :placeholder |
|
31 |
|
31 | ||
|
32 | ## Optional extensions |
|
32 | ## Optional extensions |
|
33 | # They are disabled unless you pass `f.input EXTENSION_NAME => true` |
|
33 | # They are disabled unless you pass `f.input EXTENSION_NAME => true` |
|
34 | # to the input. If so, they will retrieve the values from the model |
|
34 | # to the input. If so, they will retrieve the values from the model |
|
35 | # if any exists. If you want to enable any of those |
|
35 | # if any exists. If you want to enable any of those |
|
36 | # extensions by default, you can change `b.optional` to `b.use`. |
|
36 | # extensions by default, you can change `b.optional` to `b.use`. |
|
37 |
|
37 | ||
|
38 | # Calculates maxlength from length validations for string inputs |
|
38 | # Calculates maxlength from length validations for string inputs |
|
39 | # and/or database column lengths |
|
39 | # and/or database column lengths |
|
40 | b.optional :maxlength |
|
40 | b.optional :maxlength |
|
41 |
|
41 | ||
|
42 | # Calculate minlength from length validations for string inputs |
|
42 | # Calculate minlength from length validations for string inputs |
|
43 | b.optional :minlength |
|
43 | b.optional :minlength |
|
44 |
|
44 | ||
|
45 | # Calculates pattern from format validations for string inputs |
|
45 | # Calculates pattern from format validations for string inputs |
|
46 | b.optional :pattern |
|
46 | b.optional :pattern |
|
47 |
|
47 | ||
|
48 | # Calculates min and max from length validations for numeric inputs |
|
48 | # Calculates min and max from length validations for numeric inputs |
|
49 | b.optional :min_max |
|
49 | b.optional :min_max |
|
50 |
|
50 | ||
|
51 | # Calculates readonly automatically from readonly attributes |
|
51 | # Calculates readonly automatically from readonly attributes |
|
52 | b.optional :readonly |
|
52 | b.optional :readonly |
|
53 |
|
53 | ||
|
54 | ## Inputs |
|
54 | ## Inputs |
|
55 | # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid' |
|
55 | # b.use :input, class: 'input', error_class: 'is-invalid', valid_class: 'is-valid' |
|
56 | b.use :label_input |
|
56 | b.use :label_input |
|
57 | b.use :hint, wrap_with: { tag: :span, class: :hint } |
|
57 | b.use :hint, wrap_with: { tag: :span, class: :hint } |
|
58 | b.use :error, wrap_with: { tag: :span, class: :error } |
|
58 | b.use :error, wrap_with: { tag: :span, class: :error } |
|
59 |
|
59 | ||
|
60 | ## full_messages_for |
|
60 | ## full_messages_for |
|
61 | # If you want to display the full error message for the attribute, you can |
|
61 | # If you want to display the full error message for the attribute, you can |
|
62 | # use the component :full_error, like: |
|
62 | # use the component :full_error, like: |
|
63 | # |
|
63 | # |
|
64 | # b.use :full_error, wrap_with: { tag: :span, class: :error } |
|
64 | # b.use :full_error, wrap_with: { tag: :span, class: :error } |
|
65 | end |
|
65 | end |
|
66 |
|
66 | ||
|
67 | # The default wrapper to be used by the FormBuilder. |
|
67 | # The default wrapper to be used by the FormBuilder. |
|
68 | config.default_wrapper = :default |
|
68 | config.default_wrapper = :default |
|
69 |
|
69 | ||
|
70 | # Define the way to render check boxes / radio buttons with labels. |
|
70 | # Define the way to render check boxes / radio buttons with labels. |
|
71 | # Defaults to :nested for bootstrap config. |
|
71 | # Defaults to :nested for bootstrap config. |
|
72 | # inline: input + label |
|
72 | # inline: input + label |
|
73 | # nested: label > input |
|
73 | # nested: label > input |
|
74 | config.boolean_style = :nested |
|
74 | config.boolean_style = :nested |
|
75 |
|
75 | ||
|
76 | # Default class for buttons |
|
76 | # Default class for buttons |
|
77 | config.button_class = 'btn' |
|
77 | config.button_class = 'btn' |
|
78 |
|
78 | ||
|
79 | # Method used to tidy up errors. Specify any Rails Array method. |
|
79 | # Method used to tidy up errors. Specify any Rails Array method. |
|
80 | # :first lists the first message for each field. |
|
80 | # :first lists the first message for each field. |
|
81 | # Use :to_sentence to list all errors for each field. |
|
81 | # Use :to_sentence to list all errors for each field. |
|
82 | # config.error_method = :first |
|
82 | # config.error_method = :first |
|
83 |
|
83 | ||
|
84 | # Default tag used for error notification helper. |
|
84 | # Default tag used for error notification helper. |
|
85 | config.error_notification_tag = :div |
|
85 | config.error_notification_tag = :div |
|
86 |
|
86 | ||
|
87 | # CSS class to add for error notification helper. |
|
87 | # CSS class to add for error notification helper. |
|
88 | config.error_notification_class = 'error_notification' |
|
88 | config.error_notification_class = 'error_notification' |
|
89 |
|
89 | ||
|
90 | # Series of attempts to detect a default label method for collection. |
|
90 | # Series of attempts to detect a default label method for collection. |
|
91 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] |
|
91 | # config.collection_label_methods = [ :to_label, :name, :title, :to_s ] |
|
92 |
|
92 | ||
|
93 | # Series of attempts to detect a default value method for collection. |
|
93 | # Series of attempts to detect a default value method for collection. |
|
94 | # config.collection_value_methods = [ :id, :to_s ] |
|
94 | # config.collection_value_methods = [ :id, :to_s ] |
|
95 |
|
95 | ||
|
96 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. |
|
96 | # You can wrap a collection of radio/check boxes in a pre-defined tag, defaulting to none. |
|
97 | # config.collection_wrapper_tag = nil |
|
97 | # config.collection_wrapper_tag = nil |
|
98 |
|
98 | ||
|
99 | # You can define the class to use on all collection wrappers. Defaulting to none. |
|
99 | # You can define the class to use on all collection wrappers. Defaulting to none. |
|
100 | # config.collection_wrapper_class = nil |
|
100 | # config.collection_wrapper_class = nil |
|
101 |
|
101 | ||
|
102 | # You can wrap each item in a collection of radio/check boxes with a tag, |
|
102 | # You can wrap each item in a collection of radio/check boxes with a tag, |
|
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. |
|
128 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, |
|
128 | # To stop SimpleForm from generating the novalidate option, enabling the HTML5 validations, |
|
129 | # change this configuration to true. |
|
129 | # change this configuration to true. |
|
130 | config.browser_validations = false |
|
130 | config.browser_validations = false |
|
131 |
|
131 | ||
|
132 | # Custom mappings for input types. This should be a hash containing a regexp |
|
132 | # Custom mappings for input types. This should be a hash containing a regexp |
|
133 | # to match as key, and the input type that will be used when the field name |
|
133 | # to match as key, and the input type that will be used when the field name |
|
134 | # matches the regexp as value. |
|
134 | # matches the regexp as value. |
|
135 | # config.input_mappings = { /count/ => :integer } |
|
135 | # config.input_mappings = { /count/ => :integer } |
|
136 |
|
136 | ||
|
137 | # Custom wrappers for input types. This should be a hash containing an input |
|
137 | # Custom wrappers for input types. This should be a hash containing an input |
|
138 | # type as key and the wrapper that will be used for all inputs with specified type. |
|
138 | # type as key and the wrapper that will be used for all inputs with specified type. |
|
139 | # config.wrapper_mappings = { string: :prepend } |
|
139 | # config.wrapper_mappings = { string: :prepend } |
|
140 |
|
140 | ||
|
141 | # Namespaces where SimpleForm should look for custom input classes that |
|
141 | # Namespaces where SimpleForm should look for custom input classes that |
|
142 | # override default inputs. |
|
142 | # override default inputs. |
|
143 | # config.custom_inputs_namespaces << "CustomInputs" |
|
143 | # config.custom_inputs_namespaces << "CustomInputs" |
|
144 |
|
144 | ||
|
145 | # Default priority for time_zone inputs. |
|
145 | # Default priority for time_zone inputs. |
|
146 | # config.time_zone_priority = nil |
|
146 | # config.time_zone_priority = nil |
|
147 |
|
147 | ||
|
148 | # Default priority for country inputs. |
|
148 | # Default priority for country inputs. |
|
149 | # config.country_priority = nil |
|
149 | # config.country_priority = nil |
|
150 |
|
150 | ||
|
151 | # When false, do not use translations for labels. |
|
151 | # When false, do not use translations for labels. |
|
152 | # config.translate_labels = true |
|
152 | # config.translate_labels = true |
|
153 |
|
153 | ||
|
154 | # Automatically discover new inputs in Rails' autoload path. |
|
154 | # Automatically discover new inputs in Rails' autoload path. |
|
155 | # config.inputs_discovery = true |
|
155 | # config.inputs_discovery = true |
|
156 |
|
156 | ||
|
157 | # Cache SimpleForm inputs discovery |
|
157 | # Cache SimpleForm inputs discovery |
|
158 | # config.cache_discovery = !Rails.env.development? |
|
158 | # config.cache_discovery = !Rails.env.development? |
|
159 |
|
159 | ||
|
160 | # Default class for inputs |
|
160 | # Default class for inputs |
|
161 | # config.input_class = nil |
|
161 | # config.input_class = nil |
|
162 |
|
162 | ||
|
163 | # Define the default class of the input wrapper of the boolean input. |
|
163 | # Define the default class of the input wrapper of the boolean input. |
|
164 | config.boolean_label_class = 'checkbox' |
|
164 | config.boolean_label_class = 'checkbox' |
|
165 |
|
165 | ||
|
166 | # Defines if the default input wrapper class should be included in radio |
|
166 | # Defines if the default input wrapper class should be included in radio |
|
167 | # collection wrappers. |
|
167 | # collection wrappers. |
|
168 | # config.include_default_input_wrapper_class = true |
|
168 | # config.include_default_input_wrapper_class = true |
|
169 |
|
169 | ||
|
170 | # Defines which i18n scope will be used in Simple Form. |
|
170 | # Defines which i18n scope will be used in Simple Form. |
|
171 | # config.i18n_scope = 'simple_form' |
|
171 | # config.i18n_scope = 'simple_form' |
|
172 |
|
172 | ||
|
173 | # Defines validation classes to the input_field. By default it's nil. |
|
173 | # Defines validation classes to the input_field. By default it's nil. |
|
174 | # config.input_field_valid_class = 'is-valid' |
|
174 | # config.input_field_valid_class = 'is-valid' |
|
175 | # config.input_field_error_class = 'is-invalid' |
|
175 | # config.input_field_error_class = 'is-invalid' |
|
176 | end |
|
176 | end |
@@ -1,440 +1,372 | |||||
|
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 | ||
|
20 | # Define the default class of the input wrapper of the boolean input. |
|
18 | # Define the default class of the input wrapper of the boolean input. |
|
21 | config.boolean_label_class = 'form-check-label' |
|
19 | config.boolean_label_class = 'form-check-label' |
|
22 |
|
20 | ||
|
23 | # How the label text should be generated altogether with the required text. |
|
21 | # How the label text should be generated altogether with the required text. |
|
24 | config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" } |
|
22 | config.label_text = lambda { |label, required, explicit_label| "#{label} #{required}" } |
|
25 |
|
23 | ||
|
26 | # Define the way to render check boxes / radio buttons with labels. |
|
24 | # Define the way to render check boxes / radio buttons with labels. |
|
27 | config.boolean_style = :inline |
|
25 | config.boolean_style = :inline |
|
28 |
|
26 | ||
|
29 | # You can wrap each item in a collection of radio/check boxes with a tag |
|
27 | # You can wrap each item in a collection of radio/check boxes with a tag |
|
30 | config.item_wrapper_tag = :div |
|
28 | config.item_wrapper_tag = :div |
|
31 |
|
29 | ||
|
32 | # Defines if the default input wrapper class should be included in radio |
|
30 | # Defines if the default input wrapper class should be included in radio |
|
33 | # collection wrappers. |
|
31 | # collection wrappers. |
|
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' |
|
59 | + b.use :input, class: 'form-control', error_class: 'is-invalid' |
|
62 |
- b.use :full_error, wrap_with: { |
|
60 | + b.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
63 |
- b.use :hint, wrap_with: { |
|
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: ' |
|
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 |
|
68 | + b.wrapper :form_check_wrapper, class: 'form-check' do |bb| |
|
71 |
- bb.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
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: { |
|
71 | + bb.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
74 |
- bb.use :hint, wrap_with: { |
|
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: ' |
|
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' |
|
83 | + b.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
86 |
- b.use :full_error, wrap_with: { |
|
84 | + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
87 |
- b.use :hint, wrap_with: { |
|
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: ' |
|
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' |
|
95 | + b.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
98 |
- b.use :full_error, wrap_with: { |
|
96 | + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
99 |
- b.use :hint, wrap_with: { |
|
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 |
|
108 | + b.use :input, class: 'form-control', error_class: 'is-invalid' |
|
111 |
- b.use :full_error, wrap_with: { |
|
109 | + b.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
112 |
- b.use :hint, wrap_with: { |
|
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 |
|
128 | + b.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |ba| |
|
121 |
- ba.use :input, class: 'form-c |
|
129 | + ba.use :input, class: 'form-select mx-1', error_class: 'is-invalid' |
|
122 | end |
|
130 | end |
|
123 |
- b.use :full_error, wrap_with: { |
|
131 | + b.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
124 |
- b.use :hint, wrap_with: { |
|
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- |
|
142 | + b.use :input, class: 'form-range', error_class: 'is-invalid' |
|
135 |
- b.use :full_error, wrap_with: { |
|
143 | + b.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
136 |
- b.use :hint, wrap_with: { |
|
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 |
|
160 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
153 |
- ba.use :input, class: 'form-control', error_class: 'is-invalid' |
|
161 | + ba.use :input, class: 'form-control', error_class: 'is-invalid' |
|
154 |
- ba.use :full_error, wrap_with: { |
|
162 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
155 |
- ba.use :hint, wrap_with: { |
|
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 |
|
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: { |
|
175 | + bb.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
171 |
- bb.use :hint, wrap_with: { |
|
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', |
|
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 |
|
186 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
182 |
- ba.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
187 | + ba.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
183 |
- ba.use :full_error, wrap_with: { |
|
188 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
184 |
- ba.use :hint, wrap_with: { |
|
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', |
|
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 |
|
198 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
194 |
- ba.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
199 | + ba.use :input, class: 'form-check-input', error_class: 'is-invalid' |
|
195 |
- ba.use :full_error, wrap_with: { |
|
200 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
196 |
- ba.use :hint, wrap_with: { |
|
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 |
|
213 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
209 |
- ba.use :input, error_class: 'is-invalid' |
|
214 | + ba.use :input, class: 'form-control', error_class: 'is-invalid' |
|
210 |
- ba.use :full_error, wrap_with: { |
|
215 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
211 |
- ba.use :hint, wrap_with: { |
|
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 |
|
237 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
221 |
- ba.wrapper |
|
238 | + ba.wrapper class: 'd-flex flex-row justify-content-between align-items-center' do |bb| |
|
222 |
- bb.use :input, class: 'form-c |
|
239 | + bb.use :input, class: 'form-select mx-1', error_class: 'is-invalid' |
|
223 | end |
|
240 | end |
|
224 |
- ba.use :full_error, wrap_with: { |
|
241 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback d-block' } |
|
225 |
- ba.use :hint, wrap_with: { |
|
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 |
|
253 | + b.wrapper :grid_wrapper, class: 'col-sm-9' do |ba| |
|
237 |
- ba.use :input, class: 'form- |
|
254 | + ba.use :input, class: 'form-range', error_class: 'is-invalid' |
|
238 |
- ba.use :full_error, wrap_with: { |
|
255 | + ba.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
239 |
- ba.use :hint, wrap_with: { |
|
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: ' |
|
272 | + b.use :label, class: 'visually-hidden' |
|
256 |
|
273 | ||
|
257 |
- b.use :input, class: 'form-control', error_class: 'is-invalid' |
|
274 | + b.use :input, class: 'form-control', error_class: 'is-invalid' |
|
258 |
- b.use :error, wrap_with: { |
|
275 | + b.use :error, wrap_with: { class: 'invalid-feedback' } |
|
259 |
- b.optional :hint, wrap_with: { |
|
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 : |
|
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 : |
|
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 |
|
||
|
336 | - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' } |
|
||
|
337 | end |
|
303 | 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/ |
|
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: { |
|
341 | + b.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
399 |
- b.use :hint, wrap_with: { |
|
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, |
|
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: ' |
|
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: { |
|
351 | + b.use :full_error, wrap_with: { class: 'invalid-feedback' } |
|
409 |
- b.use :hint, wrap_with: { |
|
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 |
@@ -1,132 +1,133 | |||||
|
1 | Rails.application.routes.draw do |
|
1 | Rails.application.routes.draw do |
|
2 | resources :tags |
|
2 | resources :tags |
|
3 | get "sources/direct_edit" |
|
3 | get "sources/direct_edit" |
|
4 |
|
4 | ||
|
5 | root :to => 'main#login' |
|
5 | root :to => 'main#login' |
|
6 |
|
6 | ||
|
7 | #logins |
|
7 | #logins |
|
8 | match 'login/login', to: 'login#login', via: [:get,:post] |
|
8 | match 'login/login', to: 'login#login', via: [:get,:post] |
|
9 |
|
9 | ||
|
10 | resources :contests |
|
10 | resources :contests |
|
11 | resources :sites |
|
11 | resources :sites |
|
12 | resources :test |
|
12 | resources :test |
|
13 |
|
13 | ||
|
14 | resources :messages do |
|
14 | resources :messages do |
|
15 | member do |
|
15 | member do |
|
16 | get 'hide' |
|
16 | get 'hide' |
|
17 | post 'reply' |
|
17 | post 'reply' |
|
18 | end |
|
18 | end |
|
19 | collection do |
|
19 | collection do |
|
20 | get 'console' |
|
20 | get 'console' |
|
21 | get 'list_all' |
|
21 | get 'list_all' |
|
22 | end |
|
22 | end |
|
23 | end |
|
23 | end |
|
24 |
|
24 | ||
|
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 | ||
|
49 | resources :groups do |
|
50 | resources :groups do |
|
50 | member do |
|
51 | member do |
|
51 | post 'add_user', to: 'groups#add_user', as: 'add_user' |
|
52 | post 'add_user', to: 'groups#add_user', as: 'add_user' |
|
52 | delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user' |
|
53 | delete 'remove_user/:user_id', to: 'groups#remove_user', as: 'remove_user' |
|
53 | delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user' |
|
54 | delete 'remove_all_user', to: 'groups#remove_all_user', as: 'remove_all_user' |
|
54 | post 'add_problem', to: 'groups#add_problem', as: 'add_problem' |
|
55 | post 'add_problem', to: 'groups#add_problem', as: 'add_problem' |
|
55 | delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem' |
|
56 | delete 'remove_problem/:problem_id', to: 'groups#remove_problem', as: 'remove_problem' |
|
56 | delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem' |
|
57 | delete 'remove_all_problem', to: 'groups#remove_all_problem', as: 'remove_all_problem' |
|
57 | get 'toggle' |
|
58 | get 'toggle' |
|
58 | end |
|
59 | end |
|
59 | collection do |
|
60 | collection do |
|
60 |
|
61 | ||
|
61 | end |
|
62 | end |
|
62 | end |
|
63 | end |
|
63 |
|
64 | ||
|
64 | resources :testcases, only: [] do |
|
65 | resources :testcases, only: [] do |
|
65 | member do |
|
66 | member do |
|
66 | get 'download_input' |
|
67 | get 'download_input' |
|
67 | get 'download_sol' |
|
68 | get 'download_sol' |
|
68 | end |
|
69 | end |
|
69 | collection do |
|
70 | collection do |
|
70 | get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem' |
|
71 | get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem' |
|
71 | end |
|
72 | end |
|
72 | end |
|
73 | end |
|
73 |
|
74 | ||
|
74 | resources :grader_configuration, controller: 'configurations' do |
|
75 | resources :grader_configuration, controller: 'configurations' do |
|
75 | collection do |
|
76 | collection do |
|
76 | get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right' |
|
77 | get 'set_exam_right(/:value)', action: 'set_exam_right', as: 'set_exam_right' |
|
77 | end |
|
78 | end |
|
78 | end |
|
79 | end |
|
79 |
|
80 | ||
|
80 | resources :users do |
|
81 | resources :users do |
|
81 | member do |
|
82 | member do |
|
82 | get 'toggle_activate', 'toggle_enable' |
|
83 | get 'toggle_activate', 'toggle_enable' |
|
83 | get 'stat' |
|
84 | get 'stat' |
|
84 | end |
|
85 | end |
|
85 | collection do |
|
86 | collection do |
|
86 | get 'profile' |
|
87 | get 'profile' |
|
87 | post 'chg_passwd' |
|
88 | post 'chg_passwd' |
|
88 | post 'chg_default_language' |
|
89 | post 'chg_default_language' |
|
89 | end |
|
90 | end |
|
90 | end |
|
91 | end |
|
91 |
|
92 | ||
|
92 | resources :submissions do |
|
93 | resources :submissions do |
|
93 | member do |
|
94 | member do |
|
94 | get 'download' |
|
95 | get 'download' |
|
95 | get 'compiler_msg' |
|
96 | get 'compiler_msg' |
|
96 | get 'rejudge' |
|
97 | get 'rejudge' |
|
97 | get 'set_tag' |
|
98 | get 'set_tag' |
|
98 | end |
|
99 | end |
|
99 | collection do |
|
100 | collection do |
|
100 | get 'prob/:problem_id', to: 'submissions#index', as: 'problem' |
|
101 | get 'prob/:problem_id', to: 'submissions#index', as: 'problem' |
|
101 | get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem' |
|
102 | get 'direct_edit_problem/:problem_id(/:user_id)', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem' |
|
102 | get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status' |
|
103 | get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status' |
|
103 | end |
|
104 | end |
|
104 | end |
|
105 | end |
|
105 |
|
106 | ||
|
106 |
|
107 | ||
|
107 | #user admin |
|
108 | #user admin |
|
108 | resources :user_admin do |
|
109 | resources :user_admin do |
|
109 | collection do |
|
110 | collection do |
|
110 | match 'bulk_manage', via: [:get, :post] |
|
111 | match 'bulk_manage', via: [:get, :post] |
|
111 | get 'bulk_mail' |
|
112 | get 'bulk_mail' |
|
112 | get 'user_stat' |
|
113 | get 'user_stat' |
|
113 | get 'import' |
|
114 | get 'import' |
|
114 | get 'new_list' |
|
115 | get 'new_list' |
|
115 | get 'admin' |
|
116 | get 'admin' |
|
116 | get 'active' |
|
117 | get 'active' |
|
117 | get 'mass_mailing' |
|
118 | get 'mass_mailing' |
|
118 | match 'modify_role', via: [:get, :post] |
|
119 | match 'modify_role', via: [:get, :post] |
|
119 | match 'create_from_list', via: [:get, :post] |
|
120 | match 'create_from_list', via: [:get, :post] |
|
120 | match 'random_all_passwords', via: [:get, :post] |
|
121 | match 'random_all_passwords', via: [:get, :post] |
|
121 | end |
|
122 | end |
|
122 | member do |
|
123 | member do |
|
123 | get 'clear_last_ip' |
|
124 | get 'clear_last_ip' |
|
124 | end |
|
125 | end |
|
125 | end |
|
126 | end |
|
126 |
|
127 | ||
|
127 | resources :contest_management, only: [:index] do |
|
128 | resources :contest_management, only: [:index] do |
|
128 | collection do |
|
129 | collection do |
|
129 | get 'user_stat' |
|
130 | get 'user_stat' |
|
130 | get 'clear_stat' |
|
131 | get 'clear_stat' |
|
131 | get 'clear_all_stat' |
|
132 | get 'clear_all_stat' |
|
132 | get 'change_contest_mode' |
|
133 | get 'change_contest_mode' |
@@ -1,325 +1,346 | |||||
|
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 |
|
13 | + ActiveRecord::Schema[7.0].define(version: 2022_09_27_074644) do |
|
14 |
- create_table "a |
|
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" |
|
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" |
|
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" |
|
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 | ||
|
80 | create_table "groups", id: :integer, charset: "latin1", force: :cascade do |t| |
|
108 | create_table "groups", id: :integer, charset: "latin1", force: :cascade do |t| |
|
81 | t.string "name" |
|
109 | t.string "name" |
|
82 | t.string "description" |
|
110 | t.string "description" |
|
83 | t.boolean "enabled", default: true |
|
111 | t.boolean "enabled", default: true |
|
84 | end |
|
112 | end |
|
85 |
|
113 | ||
|
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: " |
|
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: " |
|
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" |
|
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: : |
|
160 | + create_table "problems", id: :integer, charset: "utf8mb3", collation: "utf8mb3_unicode_ci", force: :cascade do |t| |
|
133 |
- t.string "name", limit: |
|
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: : |
|
177 | + create_table "problems_tags", id: :integer, charset: "latin1", force: :cascade do |t| |
|
148 |
- t. |
|
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" |
|
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 "s |
|
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: : |
|
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" |
|
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" |
|
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: : |
|
275 | + t.text "input", size: :medium |
|
255 |
- t.text "solution", size: : |
|
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" |
|
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 |
|
309 | + t.datetime "created_at", precision: nil |
|
289 |
- t.datetime "updated_at", precision: nil |
|
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 |
modified file |
deleted file |
You need to be logged in to leave comments.
Login now