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 |
@@ -26,12 +26,13 | |||||
|
26 |
|
26 | ||
|
27 | #ignore .orig and .swp |
|
27 | #ignore .orig and .swp |
|
28 | *.orig |
|
28 | *.orig |
|
29 | *.swp |
|
29 | *.swp |
|
30 |
|
30 | ||
|
31 | #ignore rvm setting file |
|
31 | #ignore rvm setting file |
|
32 | #.ruby-gemset |
|
32 | #.ruby-gemset |
|
33 | #.ruby-version |
|
33 | #.ruby-version |
|
34 |
|
34 | ||
|
35 | /config/secrets.yml |
|
35 | /config/secrets.yml |
|
36 |
|
36 | ||
|
37 | /.byebug_history |
|
37 | /.byebug_history |
|
|
38 | + /storage/* |
@@ -68,25 +68,26 | |||||
|
68 | #gem 'bootstrap-sass', '~> 3.4.1' |
|
68 | #gem 'bootstrap-sass', '~> 3.4.1' |
|
69 | gem 'bootstrap', '~> 5.2' |
|
69 | gem 'bootstrap', '~> 5.2' |
|
70 | #gem 'bootstrap-switch-rails' |
|
70 | #gem 'bootstrap-switch-rails' |
|
71 | #gem 'bootstrap-toggle-rails' |
|
71 | #gem 'bootstrap-toggle-rails' |
|
72 | #gem 'autoprefixer-rails' |
|
72 | #gem 'autoprefixer-rails' |
|
73 | gem 'momentjs-rails' |
|
73 | gem 'momentjs-rails' |
|
74 | #gem 'rails_bootstrap_sortable' |
|
74 | #gem 'rails_bootstrap_sortable' |
|
75 | #gem 'bootstrap-datepicker-rails' |
|
75 | #gem 'bootstrap-datepicker-rails' |
|
76 | #gem 'bootstrap3-datetimepicker-rails', '~> 4.17.47' |
|
76 | #gem 'bootstrap3-datetimepicker-rails', '~> 4.17.47' |
|
77 | #gem 'jquery-datatables-rails' |
|
77 | #gem 'jquery-datatables-rails' |
|
78 |
|
78 | ||
|
79 | #----------- user interface ----------------- |
|
79 | #----------- user interface ----------------- |
|
80 | - gem 'simple_form' |
|
80 | + gem 'simple_form', git: 'https://github.com/heartcombo/simple_form', ref: '31fe255' |
|
|
81 | + | ||
|
81 | #select 2 |
|
82 | #select 2 |
|
82 | #gem 'select2-rails' |
|
83 | #gem 'select2-rails' |
|
83 | #ace editor |
|
84 | #ace editor |
|
84 | gem 'ace-rails-ap' |
|
85 | gem 'ace-rails-ap' |
|
85 | #paginator |
|
86 | #paginator |
|
86 | #gem 'will_paginate', '~> 3.0.7' |
|
87 | #gem 'will_paginate', '~> 3.0.7' |
|
87 |
|
88 | ||
|
88 | gem 'mail' |
|
89 | gem 'mail' |
|
89 | gem 'rdiscount' #markdown |
|
90 | gem 'rdiscount' #markdown |
|
90 |
|
91 | ||
|
91 |
|
92 | ||
|
92 | #---------------- testiing ----------------------- |
|
93 | #---------------- testiing ----------------------- |
@@ -1,12 +1,21 | |||||
|
|
1 | + GIT | ||
|
|
2 | + remote: https://github.com/heartcombo/simple_form | ||
|
|
3 | + revision: 31fe25504771bd6cd425b585a4e0ed652fba4521 | ||
|
|
4 | + ref: 31fe255 | ||
|
|
5 | + specs: | ||
|
|
6 | + simple_form (5.1.0) | ||
|
|
7 | + actionpack (>= 5.2) | ||
|
|
8 | + activemodel (>= 5.2) | ||
|
|
9 | + | ||
|
1 | GIT |
|
10 | GIT |
|
2 | remote: https://github.com/mmotherwell/best_in_place |
|
11 | remote: https://github.com/mmotherwell/best_in_place |
|
3 | revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0 |
|
12 | revision: 88eb3052623a9a6cd346864d2aca05021c2f80d0 |
|
4 | specs: |
|
13 | specs: |
|
5 | best_in_place (3.1.1) |
|
14 | best_in_place (3.1.1) |
|
6 | actionpack (>= 3.2) |
|
15 | actionpack (>= 3.2) |
|
7 | railties (>= 3.2) |
|
16 | railties (>= 3.2) |
|
8 |
|
17 | ||
|
9 | GEM |
|
18 | GEM |
|
10 | remote: https://rubygems.org/ |
|
19 | remote: https://rubygems.org/ |
|
11 | specs: |
|
20 | specs: |
|
12 | RubyInline (3.12.6) |
|
21 | RubyInline (3.12.6) |
@@ -238,27 +247,24 | |||||
|
238 | sassc-rails (2.1.2) |
|
247 | sassc-rails (2.1.2) |
|
239 | railties (>= 4.0.0) |
|
248 | railties (>= 4.0.0) |
|
240 | sassc (>= 2.0) |
|
249 | sassc (>= 2.0) |
|
241 | sprockets (> 3.0) |
|
250 | sprockets (> 3.0) |
|
242 | sprockets-rails |
|
251 | sprockets-rails |
|
243 | tilt |
|
252 | tilt |
|
244 | selenium-webdriver (4.4.0) |
|
253 | selenium-webdriver (4.4.0) |
|
245 | childprocess (>= 0.5, < 5.0) |
|
254 | childprocess (>= 0.5, < 5.0) |
|
246 | rexml (~> 3.2, >= 3.2.5) |
|
255 | rexml (~> 3.2, >= 3.2.5) |
|
247 | rubyzip (>= 1.2.2, < 3.0) |
|
256 | rubyzip (>= 1.2.2, < 3.0) |
|
248 | websocket (~> 1.0) |
|
257 | websocket (~> 1.0) |
|
249 | sexp_processor (4.16.1) |
|
258 | sexp_processor (4.16.1) |
|
250 | - simple_form (5.1.0) |
|
||
|
251 | - actionpack (>= 5.2) |
|
||
|
252 | - activemodel (>= 5.2) |
|
||
|
253 | spring (2.1.1) |
|
259 | spring (2.1.1) |
|
254 | spring-watcher-listen (2.0.1) |
|
260 | spring-watcher-listen (2.0.1) |
|
255 | listen (>= 2.7, < 4.0) |
|
261 | listen (>= 2.7, < 4.0) |
|
256 | spring (>= 1.2, < 3.0) |
|
262 | spring (>= 1.2, < 3.0) |
|
257 | sprockets (4.1.1) |
|
263 | sprockets (4.1.1) |
|
258 | concurrent-ruby (~> 1.0) |
|
264 | concurrent-ruby (~> 1.0) |
|
259 | rack (> 1, < 3) |
|
265 | rack (> 1, < 3) |
|
260 | sprockets-rails (3.4.2) |
|
266 | sprockets-rails (3.4.2) |
|
261 | actionpack (>= 5.2) |
|
267 | actionpack (>= 5.2) |
|
262 | activesupport (>= 5.2) |
|
268 | activesupport (>= 5.2) |
|
263 | sprockets (>= 3.0.0) |
|
269 | sprockets (>= 3.0.0) |
|
264 | sqlite3 (1.5.0-x86_64-linux) |
|
270 | sqlite3 (1.5.0-x86_64-linux) |
@@ -306,25 +312,25 | |||||
|
306 | listen (>= 3.0.5, < 3.2) |
|
312 | listen (>= 3.0.5, < 3.2) |
|
307 |
|
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 |
@@ -50,28 +50,24 | |||||
|
50 | } |
|
50 | } |
|
51 |
|
51 | ||
|
52 | &.text-right { |
|
52 | &.text-right { |
|
53 | padding-left: 20px !important; |
|
53 | padding-left: 20px !important; |
|
54 | padding-right: 8px !important; |
|
54 | padding-right: 8px !important; |
|
55 |
|
55 | ||
|
56 | &:after, span.sign { |
|
56 | &:after, span.sign { |
|
57 | left: (-15px) !important; |
|
57 | left: (-15px) !important; |
|
58 | } |
|
58 | } |
|
59 | } |
|
59 | } |
|
60 | } |
|
60 | } |
|
61 |
|
61 | ||
|
62 | - input { |
|
||
|
63 | - font-family: Tahoma, "sans-serif"; |
|
||
|
64 | - } |
|
||
|
65 | - |
|
||
|
66 | h1 { |
|
62 | h1 { |
|
67 | color: #334488; |
|
63 | color: #334488; |
|
68 | } |
|
64 | } |
|
69 |
|
65 | ||
|
70 | h2 { |
|
66 | h2 { |
|
71 | color: #5566bb; |
|
67 | color: #5566bb; |
|
72 | } |
|
68 | } |
|
73 |
|
69 | ||
|
74 | hr { |
|
70 | hr { |
|
75 | border-top: 1px solid #dddddd; |
|
71 | border-top: 1px solid #dddddd; |
|
76 | border-bottom: 1px solid #eeeeee; |
|
72 | border-bottom: 1px solid #eeeeee; |
|
77 | } |
|
73 | } |
@@ -1,43 +1,50 | |||||
|
1 | require 'ipaddr' |
|
1 | require 'ipaddr' |
|
2 | require "securerandom" |
|
2 | require "securerandom" |
|
3 |
|
3 | ||
|
4 | class ApplicationController < ActionController::Base |
|
4 | class ApplicationController < ActionController::Base |
|
5 | protect_from_forgery |
|
5 | protect_from_forgery |
|
6 |
|
6 | ||
|
7 | before_action :current_user |
|
7 | before_action :current_user |
|
8 | before_action :nav_announcement |
|
8 | before_action :nav_announcement |
|
9 | before_action :unique_visitor_id |
|
9 | before_action :unique_visitor_id |
|
|
10 | + before_action :active_controller_action | ||
|
10 |
|
11 | ||
|
11 | SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode' |
|
12 | SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode' |
|
12 | MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login' |
|
13 | MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login' |
|
13 | WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore' |
|
14 | WHITELIST_IGNORE_CONF_KEY = 'right.whitelist_ignore' |
|
14 | WHITELIST_IP_CONF_KEY = 'right.whitelist_ip' |
|
15 | WHITELIST_IP_CONF_KEY = 'right.whitelist_ip' |
|
15 |
|
16 | ||
|
16 | #report and redirect for unauthorized activities |
|
17 | #report and redirect for unauthorized activities |
|
17 | def unauthorized_redirect(notice = 'You are not authorized to view the page you requested') |
|
18 | def unauthorized_redirect(notice = 'You are not authorized to view the page you requested') |
|
18 | flash[:notice] = notice |
|
19 | flash[:notice] = notice |
|
19 | redirect_to login_main_path |
|
20 | redirect_to login_main_path |
|
20 | end |
|
21 | end |
|
21 |
|
22 | ||
|
22 | # Returns the current logged-in user (if any). |
|
23 | # Returns the current logged-in user (if any). |
|
23 | def current_user |
|
24 | def current_user |
|
24 | return nil unless session[:user_id] |
|
25 | return nil unless session[:user_id] |
|
25 | @current_user ||= User.find(session[:user_id]) |
|
26 | @current_user ||= User.find(session[:user_id]) |
|
26 | end |
|
27 | end |
|
27 |
|
28 | ||
|
28 | def nav_announcement |
|
29 | def nav_announcement |
|
29 | @nav_announcement = Announcement.where(on_nav_bar: true) |
|
30 | @nav_announcement = Announcement.where(on_nav_bar: true) |
|
30 | end |
|
31 | end |
|
31 |
|
32 | ||
|
|
33 | + def active_controller_action | ||
|
|
34 | + #so that we can override this value inside each action | ||
|
|
35 | + @active_controller = controller_name | ||
|
|
36 | + @active_action = action_name | ||
|
|
37 | + end | ||
|
|
38 | + | ||
|
32 | def admin_authorization |
|
39 | def admin_authorization |
|
33 | return false unless check_valid_login |
|
40 | return false unless check_valid_login |
|
34 | user = User.includes(:roles).find(session[:user_id]) |
|
41 | user = User.includes(:roles).find(session[:user_id]) |
|
35 | unless user.admin? |
|
42 | unless user.admin? |
|
36 | unauthorized_redirect |
|
43 | unauthorized_redirect |
|
37 | return false |
|
44 | return false |
|
38 | end |
|
45 | end |
|
39 | return true |
|
46 | return true |
|
40 | end |
|
47 | end |
|
41 |
|
48 | ||
|
42 | #admin always count as every roles |
|
49 | #admin always count as every roles |
|
43 | def role_authorization(roles) |
|
50 | def role_authorization(roles) |
@@ -1,167 +1,143 | |||||
|
1 | class ProblemsController < ApplicationController |
|
1 | class ProblemsController < ApplicationController |
|
2 |
|
2 | ||
|
|
3 | + include ActiveStorage::SetCurrent | ||
|
|
4 | + | ||
|
3 | before_action :admin_authorization, except: [:stat] |
|
5 | before_action :admin_authorization, except: [:stat] |
|
|
6 | + before_action :set_problem, only: [:show, :edit, :update, :destroy, :get_statement, :toggle, :toggle_test, :toggle_view_testcase, :stat] | ||
|
4 | before_action only: [:stat] do |
|
7 | before_action only: [:stat] do |
|
5 | authorization_by_roles(['admin','ta']) |
|
8 | authorization_by_roles(['admin','ta']) |
|
6 | end |
|
9 | end |
|
7 |
|
10 | ||
|
|
11 | + | ||
|
8 | def index |
|
12 | def index |
|
9 | @problems = Problem.order(date_added: :desc) |
|
13 | @problems = Problem.order(date_added: :desc) |
|
10 | end |
|
14 | end |
|
11 |
|
15 | ||
|
12 |
|
16 | ||
|
13 | def show |
|
17 | def show |
|
14 | - @problem = Problem.find(params[:id]) |
|
18 | + end |
|
|
19 | + | ||
|
|
20 | + #get statement download link | ||
|
|
21 | + def get_statement | ||
|
|
22 | + unless @current_user.can_view_problem? @problem | ||
|
|
23 | + redirect_to list_main_path, error: 'You are not authorized to access this file' | ||
|
|
24 | + return | ||
|
|
25 | + end | ||
|
|
26 | + | ||
|
|
27 | + if params[:ext]=='pdf' | ||
|
|
28 | + content_type = 'application/pdf' | ||
|
|
29 | + else | ||
|
|
30 | + content_type = 'application/octet-stream' | ||
|
|
31 | + end | ||
|
|
32 | + | ||
|
|
33 | + filename = @problem.statement.filename.to_s | ||
|
|
34 | + data =@problem.statement.download | ||
|
|
35 | + | ||
|
|
36 | + send_data data, stream: false, disposition: 'inline', filename: filename, type: content_type | ||
|
15 | end |
|
37 | end |
|
16 |
|
38 | ||
|
17 | def new |
|
39 | def new |
|
18 | @problem = Problem.new |
|
40 | @problem = Problem.new |
|
19 | - @description = nil |
|
||
|
20 | end |
|
41 | end |
|
21 |
|
42 | ||
|
22 | def create |
|
43 | def create |
|
23 | @problem = Problem.new(problem_params) |
|
44 | @problem = Problem.new(problem_params) |
|
24 | - @description = Description.new(description_params) |
|
||
|
25 | - if @description.body!='' |
|
||
|
26 | - if !@description.save |
|
||
|
27 | - render :action => new and return |
|
||
|
28 | - end |
|
||
|
29 | - else |
|
||
|
30 | - @description = nil |
|
||
|
31 | - end |
|
||
|
32 | - @problem.description = @description |
|
||
|
33 | if @problem.save |
|
45 | if @problem.save |
|
34 |
- |
|
46 | + redirect_to action: :index, notice: 'Problem was successfully created.' |
|
35 | - redirect_to action: :index |
|
||
|
36 | else |
|
47 | else |
|
37 | render :action => 'new' |
|
48 | render :action => 'new' |
|
38 | end |
|
49 | end |
|
39 | end |
|
50 | end |
|
40 |
|
51 | ||
|
41 | def quick_create |
|
52 | def quick_create |
|
42 | @problem = Problem.new(problem_params) |
|
53 | @problem = Problem.new(problem_params) |
|
43 | @problem.full_name = @problem.name if @problem.full_name == '' |
|
54 | @problem.full_name = @problem.name if @problem.full_name == '' |
|
44 | @problem.full_score = 100 |
|
55 | @problem.full_score = 100 |
|
45 | @problem.available = false |
|
56 | @problem.available = false |
|
46 | @problem.test_allowed = true |
|
57 | @problem.test_allowed = true |
|
47 | @problem.output_only = false |
|
58 | @problem.output_only = false |
|
48 | @problem.date_added = Time.new |
|
59 | @problem.date_added = Time.new |
|
49 | if @problem.save |
|
60 | if @problem.save |
|
50 | flash[:notice] = 'Problem was successfully created.' |
|
61 | flash[:notice] = 'Problem was successfully created.' |
|
51 | redirect_to action: :index |
|
62 | redirect_to action: :index |
|
52 | else |
|
63 | else |
|
53 | flash[:notice] = 'Error saving problem' |
|
64 | flash[:notice] = 'Error saving problem' |
|
54 | redirect_to action: :index |
|
65 | redirect_to action: :index |
|
55 | end |
|
66 | end |
|
56 | end |
|
67 | end |
|
57 |
|
68 | ||
|
58 | def edit |
|
69 | def edit |
|
59 | - @problem = Problem.find(params[:id]) |
|
||
|
60 | @description = @problem.description |
|
70 | @description = @problem.description |
|
61 | end |
|
71 | end |
|
62 |
|
72 | ||
|
63 | def update |
|
73 | def update |
|
64 | - @problem = Problem.find(params[:id]) |
|
74 | + if problem_params[:statement] && problem_params[:statement].content_type != 'application/pdf' |
|
65 | - @description = @problem.description |
|
75 | + flash[:error] = 'Error: Uploaded file is not PDF' |
|
66 | - if @description.nil? and params[:description][:body]!='' |
|
76 | + render :action => 'edit' |
|
67 | - @description = Description.new(description_params) |
|
77 | + return |
|
68 | - if !@description.save |
|
||
|
69 | - flash[:notice] = 'Error saving description' |
|
||
|
70 | - render :action => 'edit' and return |
|
||
|
71 | - end |
|
||
|
72 | - @problem.description = @description |
|
||
|
73 | - elsif @description |
|
||
|
74 | - if !@description.update(description_params) |
|
||
|
75 | - flash[:notice] = 'Error saving description' |
|
||
|
76 | - render :action => 'edit' and return |
|
||
|
77 | - end |
|
||
|
78 | - end |
|
||
|
79 | - if params[:file] and params[:file].content_type != 'application/pdf' |
|
||
|
80 | - flash[:notice] = 'Error: Uploaded file is not PDF' |
|
||
|
81 | - render :action => 'edit' and return |
|
||
|
82 | end |
|
78 | end |
|
83 | if @problem.update(problem_params) |
|
79 | if @problem.update(problem_params) |
|
84 | - flash[:notice] = 'Problem was successfully updated.' |
|
80 | + flash[:notice] = 'Problem was successfully updated. ' |
|
85 | - unless params[:file] == nil or params[:file] == '' |
|
81 | + flash[:notice] += 'A new statement PDF is uploaded' if problem_params[:statement] |
|
86 | - flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.' |
|
82 | + @problem.save |
|
87 | - out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}" |
|
83 | + redirect_to edit_problem_path(@problem) |
|
88 | - if not FileTest.exists? out_dirname |
|
||
|
89 | - Dir.mkdir out_dirname |
|
||
|
90 | - end |
|
||
|
91 | - |
|
||
|
92 | - out_filename = "#{out_dirname}/#{@problem.name}.pdf" |
|
||
|
93 | - if FileTest.exists? out_filename |
|
||
|
94 | - File.delete out_filename |
|
||
|
95 | - end |
|
||
|
96 | - |
|
||
|
97 | - File.open(out_filename,"wb") do |file| |
|
||
|
98 | - file.write(params[:file].read) |
|
||
|
99 | - end |
|
||
|
100 | - @problem.description_filename = "#{@problem.name}.pdf" |
|
||
|
101 | - @problem.save |
|
||
|
102 | - end |
|
||
|
103 | - redirect_to :action => 'show', :id => @problem |
|
||
|
104 | else |
|
84 | else |
|
105 | render :action => 'edit' |
|
85 | render :action => 'edit' |
|
106 | end |
|
86 | end |
|
107 | end |
|
87 | end |
|
108 |
|
88 | ||
|
109 | def destroy |
|
89 | def destroy |
|
110 |
- p |
|
90 | + @problem.destroy |
|
111 | redirect_to action: :index |
|
91 | redirect_to action: :index |
|
112 | end |
|
92 | end |
|
113 |
|
93 | ||
|
114 | def toggle |
|
94 | def toggle |
|
115 | - @problem = Problem.find(params[:id]) |
|
||
|
116 | @problem.update(available: !(@problem.available) ) |
|
95 | @problem.update(available: !(@problem.available) ) |
|
117 | respond_to do |format| |
|
96 | respond_to do |format| |
|
118 | format.js { } |
|
97 | format.js { } |
|
119 | end |
|
98 | end |
|
120 | end |
|
99 | end |
|
121 |
|
100 | ||
|
122 | def toggle_test |
|
101 | def toggle_test |
|
123 | - @problem = Problem.find(params[:id]) |
|
||
|
124 | @problem.update(test_allowed: !(@problem.test_allowed?) ) |
|
102 | @problem.update(test_allowed: !(@problem.test_allowed?) ) |
|
125 | respond_to do |format| |
|
103 | respond_to do |format| |
|
126 | format.js { } |
|
104 | format.js { } |
|
127 | end |
|
105 | end |
|
128 | end |
|
106 | end |
|
129 |
|
107 | ||
|
130 | def toggle_view_testcase |
|
108 | def toggle_view_testcase |
|
131 | - @problem = Problem.find(params[:id]) |
|
||
|
132 | @problem.update(view_testcase: !(@problem.view_testcase?) ) |
|
109 | @problem.update(view_testcase: !(@problem.view_testcase?) ) |
|
133 | respond_to do |format| |
|
110 | respond_to do |format| |
|
134 | format.js { } |
|
111 | format.js { } |
|
135 | end |
|
112 | end |
|
136 | end |
|
113 | end |
|
137 |
|
114 | ||
|
138 | def turn_all_off |
|
115 | def turn_all_off |
|
139 | Problem.available.all.each do |problem| |
|
116 | Problem.available.all.each do |problem| |
|
140 | problem.available = false |
|
117 | problem.available = false |
|
141 | problem.save |
|
118 | problem.save |
|
142 | end |
|
119 | end |
|
143 | redirect_to action: :index |
|
120 | redirect_to action: :index |
|
144 | end |
|
121 | end |
|
145 |
|
122 | ||
|
146 | def turn_all_on |
|
123 | def turn_all_on |
|
147 | Problem.where.not(available: true).each do |problem| |
|
124 | Problem.where.not(available: true).each do |problem| |
|
148 | problem.available = true |
|
125 | problem.available = true |
|
149 | problem.save |
|
126 | problem.save |
|
150 | end |
|
127 | end |
|
151 | redirect_to action: :index |
|
128 | redirect_to action: :index |
|
152 | end |
|
129 | end |
|
153 |
|
130 | ||
|
154 | def stat |
|
131 | def stat |
|
155 | - @problem = Problem.find(params[:id]) |
|
||
|
156 | unless @problem.available or session[:admin] |
|
132 | unless @problem.available or session[:admin] |
|
157 | redirect_to :controller => 'main', :action => 'list' |
|
133 | redirect_to :controller => 'main', :action => 'list' |
|
158 | return |
|
134 | return |
|
159 | end |
|
135 | end |
|
160 | @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id) |
|
136 | @submissions = Submission.includes(:user).includes(:language).where(problem_id: params[:id]).order(:user_id,:id) |
|
161 |
|
137 | ||
|
162 | #stat summary |
|
138 | #stat summary |
|
163 | range =65 |
|
139 | range =65 |
|
164 | @histogram = { data: Array.new(range,0), summary: {} } |
|
140 | @histogram = { data: Array.new(range,0), summary: {} } |
|
165 | user = Hash.new(0) |
|
141 | user = Hash.new(0) |
|
166 | @submissions.find_each do |sub| |
|
142 | @submissions.find_each do |sub| |
|
167 | d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
|
143 | d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60 |
@@ -286,21 +262,26 | |||||
|
286 | name, id, order = k.split('-') |
|
262 | name, id, order = k.split('-') |
|
287 | problems << Problem.find(id) |
|
263 | problems << Problem.find(id) |
|
288 | end |
|
264 | end |
|
289 | end |
|
265 | end |
|
290 | problems |
|
266 | problems |
|
291 | end |
|
267 | end |
|
292 |
|
268 | ||
|
293 | def get_problems_stat |
|
269 | def get_problems_stat |
|
294 | end |
|
270 | end |
|
295 |
|
271 | ||
|
296 | private |
|
272 | private |
|
297 |
|
273 | ||
|
|
274 | + def set_problem | ||
|
|
275 | + @problem = Problem.find(params[:id]) | ||
|
|
276 | + end | ||
|
|
277 | + | ||
|
298 | def problem_params |
|
278 | def problem_params |
|
299 |
- params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, |
|
279 | + params.require(:problem).permit(:name, :full_name, :full_score, :change_date_added, :date_added, :available, |
|
|
280 | + :test_allowed, :output_only, :url, :description, :statement, :description, tag_ids:[]) | ||
|
300 | end |
|
281 | end |
|
301 |
|
282 | ||
|
302 | def description_params |
|
283 | def description_params |
|
303 | params.require(:description).permit(:body, :markdowned) |
|
284 | params.require(:description).permit(:body, :markdowned) |
|
304 | end |
|
285 | end |
|
305 |
|
286 | ||
|
306 | end |
|
287 | end |
@@ -200,13 +200,24 | |||||
|
200 |
|
200 | ||
|
201 | BOOTSTRAP_FLASH_MSG = { |
|
201 | BOOTSTRAP_FLASH_MSG = { |
|
202 | success: 'alert-success', |
|
202 | success: 'alert-success', |
|
203 | error: 'alert-danger', |
|
203 | error: 'alert-danger', |
|
204 | alert: 'alert-danger', |
|
204 | alert: 'alert-danger', |
|
205 | notice: 'alert-info' |
|
205 | notice: 'alert-info' |
|
206 | } |
|
206 | } |
|
207 |
|
207 | ||
|
208 | def bootstrap_class_for(flash_type) |
|
208 | def bootstrap_class_for(flash_type) |
|
209 | BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s) |
|
209 | BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s) |
|
210 | end |
|
210 | end |
|
211 |
|
211 | ||
|
|
212 | + def active_class_when(options = {},cname = @active_controller, aname = @active_action) | ||
|
|
213 | + class_name = ' active ' | ||
|
|
214 | + ok = true | ||
|
|
215 | + options.each do |k,v| | ||
|
|
216 | + ok = false if k == :controller && v.to_s != cname | ||
|
|
217 | + ok = false if k == :action && v.to_s != aname | ||
|
|
218 | + end | ||
|
|
219 | + return class_name if ok && options.size > 0 | ||
|
|
220 | + return '' | ||
|
|
221 | + end | ||
|
|
222 | + | ||
|
212 | end |
|
223 | end |
@@ -1,38 +1,42 | |||||
|
1 | class Problem < ApplicationRecord |
|
1 | class Problem < ApplicationRecord |
|
2 |
|
2 | ||
|
3 | - belongs_to :description |
|
3 | + #belongs_to :description |
|
|
4 | + | ||
|
4 | has_and_belongs_to_many :contests, :uniq => true |
|
5 | has_and_belongs_to_many :contests, :uniq => true |
|
5 |
|
6 | ||
|
6 | #has_and_belongs_to_many :groups |
|
7 | #has_and_belongs_to_many :groups |
|
7 | has_many :groups_problems, class_name: 'GroupProblem' |
|
8 | has_many :groups_problems, class_name: 'GroupProblem' |
|
8 | has_many :groups, :through => :groups_problems |
|
9 | has_many :groups, :through => :groups_problems |
|
9 |
|
10 | ||
|
10 | has_many :problems_tags, class_name: 'ProblemTag' |
|
11 | has_many :problems_tags, class_name: 'ProblemTag' |
|
11 | has_many :tags, through: :problems_tags |
|
12 | has_many :tags, through: :problems_tags |
|
12 |
|
13 | ||
|
13 | has_many :test_pairs, :dependent => :delete_all |
|
14 | has_many :test_pairs, :dependent => :delete_all |
|
14 | has_many :testcases, :dependent => :destroy |
|
15 | has_many :testcases, :dependent => :destroy |
|
15 |
|
16 | ||
|
16 | has_many :submissions |
|
17 | has_many :submissions |
|
17 |
|
18 | ||
|
18 | validates_presence_of :name |
|
19 | validates_presence_of :name |
|
19 | validates_format_of :name, :with => /\A\w+\z/ |
|
20 | validates_format_of :name, :with => /\A\w+\z/ |
|
20 | validates_presence_of :full_name |
|
21 | validates_presence_of :full_name |
|
21 |
|
22 | ||
|
22 | scope :available, -> { where(available: true) } |
|
23 | scope :available, -> { where(available: true) } |
|
23 |
|
24 | ||
|
24 | DEFAULT_TIME_LIMIT = 1 |
|
25 | DEFAULT_TIME_LIMIT = 1 |
|
25 | DEFAULT_MEMORY_LIMIT = 32 |
|
26 | DEFAULT_MEMORY_LIMIT = 32 |
|
26 |
|
27 | ||
|
|
28 | + has_one_attached :statement | ||
|
|
29 | + has_many_attached :attachments | ||
|
|
30 | + | ||
|
27 | def get_jschart_history |
|
31 | def get_jschart_history |
|
28 | start = 4.month.ago.beginning_of_day |
|
32 | start = 4.month.ago.beginning_of_day |
|
29 | start_date = start.to_date |
|
33 | start_date = start.to_date |
|
30 | count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count |
|
34 | count = Submission.where(problem: self).where('submitted_at >= ?', start).group('DATE(submitted_at)').count |
|
31 | i = 0 |
|
35 | i = 0 |
|
32 | label = [] |
|
36 | label = [] |
|
33 | value = [] |
|
37 | value = [] |
|
34 | while (start_date + i < Time.zone.now.to_date) |
|
38 | while (start_date + i < Time.zone.now.to_date) |
|
35 | if (start_date+i).day == 1 |
|
39 | if (start_date+i).day == 1 |
|
36 | #label << (start_date+i).strftime("%d %b %Y") |
|
40 | #label << (start_date+i).strftime("%d %b %Y") |
|
37 | #label << (start_date+i).strftime("%d") |
|
41 | #label << (start_date+i).strftime("%d") |
|
38 | else |
|
42 | else |
@@ -2,86 +2,92 | |||||
|
2 | %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg |
|
2 | %nav.navbar.fixed-top.navbar-dark.bg-primary.navbar-expand-lg |
|
3 | .container-fluid |
|
3 | .container-fluid |
|
4 | %a.navbar-brand{href: list_main_path} |
|
4 | %a.navbar-brand{href: list_main_path} |
|
5 | %span.mi.mi-bs home |
|
5 | %span.mi.mi-bs home |
|
6 | MAIN |
|
6 | MAIN |
|
7 | %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} } |
|
7 | %button.navbar-toggler.collapsed{ type: :button, 'data-bs': {toggle: 'collapse', target: '#navbar-collapse'} } |
|
8 | %span.navbar-toggler-icon |
|
8 | %span.navbar-toggler-icon |
|
9 | .collapse.navbar-collapse#navbar-collapse |
|
9 | .collapse.navbar-collapse#navbar-collapse |
|
10 | %ul.navbar-nav.me-auto.mb-2.mb-lg-0 |
|
10 | %ul.navbar-nav.me-auto.mb-2.mb-lg-0 |
|
11 | / submission |
|
11 | / submission |
|
12 | - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user)) |
|
12 | - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user)) |
|
13 | %li.nav-item.dropdown.mx-2 |
|
13 | %li.nav-item.dropdown.mx-2 |
|
14 | - %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"} |
|
14 | + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {expanded:"false"}, role: "button"} |
|
15 | = "#{I18n.t 'menu.submissions'}" |
|
15 | = "#{I18n.t 'menu.submissions'}" |
|
16 | %ul.dropdown-menu |
|
16 | %ul.dropdown-menu |
|
17 | - %li= link_to 'View', submissions_path, class:'dropdown-item' |
|
17 | + %li= link_to 'View', submissions_path, class: 'dropdown-item '+active_class_when(controller: :submissions) |
|
18 | %li= link_to 'Self Test', test_index_path, class:'dropdown-item' |
|
18 | %li= link_to 'Self Test', test_index_path, class:'dropdown-item' |
|
19 | / hall of fame |
|
19 | / hall of fame |
|
20 | - if GraderConfiguration['right.user_hall_of_fame'] |
|
20 | - if GraderConfiguration['right.user_hall_of_fame'] |
|
21 | - %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2' |
|
21 | + %li= link_to "#{I18n.t 'menu.hall_of_fame'}", problem_hof_report_path, class: 'nav-link mx-2'+active_class_when(controller: :report, action: :problem_hof) |
|
22 | / display MODE button (with countdown in contest mode) |
|
22 | / display MODE button (with countdown in contest mode) |
|
23 | - if GraderConfiguration.analysis_mode? |
|
23 | - if GraderConfiguration.analysis_mode? |
|
24 | %div.btn.btn-success#countdown= "ANALYSIS MODE" |
|
24 | %div.btn.btn-success#countdown= "ANALYSIS MODE" |
|
25 | - elsif GraderConfiguration.time_limit_mode? |
|
25 | - elsif GraderConfiguration.time_limit_mode? |
|
26 | - if @current_user.contest_finished? |
|
26 | - if @current_user.contest_finished? |
|
27 | %div.btn.btn-danger#countdown= "Contest is over" |
|
27 | %div.btn.btn-danger#countdown= "Contest is over" |
|
28 | - elsif !@current_user.contest_started? |
|
28 | - elsif !@current_user.contest_started? |
|
29 | %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started') |
|
29 | %div.btn.btn-primary#countdown= (t 'title_bar.contest_not_started') |
|
30 | - else |
|
30 | - else |
|
31 | %div.btn.btn-primary#countdown asdf |
|
31 | %div.btn.btn-primary#countdown asdf |
|
32 | :javascript |
|
32 | :javascript |
|
33 | $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'}); |
|
33 | $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'}); |
|
34 | / admin section |
|
34 | / admin section |
|
35 | - if (@current_user!=nil) and (session[:admin]) |
|
35 | - if (@current_user!=nil) and (session[:admin]) |
|
36 | / management |
|
36 | / management |
|
37 | %li.nav-item.dropdown.mx-2 |
|
37 | %li.nav-item.dropdown.mx-2 |
|
38 |
- %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, |
|
38 | + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"} |
|
39 | Manage |
|
39 | Manage |
|
40 | %ul.dropdown-menu |
|
40 | %ul.dropdown-menu |
|
41 | - %li= link_to 'Announcements', announcements_path, class: 'dropdown-item' |
|
41 | + %li= link_to 'Announcements', announcements_path, class: 'dropdown-item'+active_class_when(controller: :announcements) |
|
42 | - %li= link_to 'Problems', problems_path, class: 'dropdown-item' |
|
42 | + %li= link_to 'Problems', problems_path, class: 'dropdown-item'+active_class_when(controller: :problems) |
|
43 | - %li= link_to 'Tags', tags_path, class: 'dropdown-item' |
|
43 | + %li= link_to 'Tags', tags_path, class: 'dropdown-item'+active_class_when(controller: :tags) |
|
44 | - %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item' |
|
44 | + %li= link_to 'Users', user_admin_index_path, class: 'dropdown-item'+active_class_when(controller: :user_admin) |
|
45 | - %li= link_to 'User Groups', groups_path, class: 'dropdown-item' |
|
45 | + %li= link_to 'User Groups', groups_path, class: 'dropdown-item'+active_class_when(controller: :groups) |
|
46 | - %li= link_to 'Graders', graders_list_path, class: 'dropdown-item' |
|
46 | + %li= link_to 'Graders', graders_list_path, class: 'dropdown-item'+active_class_when(controller: :graders) |
|
47 | - %li= link_to 'Message ', console_messages_path, class: 'dropdown-item' |
|
47 | + %li= link_to 'Message ', console_messages_path, class: 'dropdown-item'+active_class_when(controller: :messages) |
|
48 | %li |
|
48 | %li |
|
49 | %hr.dropdown-divider |
|
49 | %hr.dropdown-divider |
|
50 | - %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item' |
|
50 | + %li= link_to 'System config', grader_configuration_index_path, class: 'dropdown-item'+active_class_when(controller: :grader_configuration) |
|
51 | %li |
|
51 | %li |
|
52 | %hr.dropdown-divider |
|
52 | %hr.dropdown-divider |
|
53 | - %li= link_to 'Sites', sites_path, class: 'dropdown-item' |
|
53 | + %li= link_to 'Sites', sites_path, class: 'dropdown-item'+active_class_when(controller: :sites) |
|
54 | - %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item' |
|
54 | + %li= link_to 'Contests', contest_management_index_path, class: 'dropdown-item'+active_class_when(controller: :contest_management) |
|
55 | -# |
|
55 | -# |
|
56 | / report |
|
56 | / report |
|
57 | %li.nav-item.dropdown.mx-2 |
|
57 | %li.nav-item.dropdown.mx-2 |
|
58 | - %a.nav-link.dropdown-toggle{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"} |
|
58 | + %a.nav-link.dropdown-toggle.active-with-children{href: '#', 'data-bs': {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"} |
|
59 | Report |
|
59 | Report |
|
60 | %ul.dropdown-menu |
|
60 | %ul.dropdown-menu |
|
61 | - %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item' |
|
61 | + %li= link_to 'Current Score', current_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :current_score) |
|
62 | - %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item' |
|
62 | + %li= link_to 'Score Report', max_score_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :max_score) |
|
63 | - %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item' |
|
63 | + %li= link_to 'Submission Report', submission_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :submission) |
|
64 | - %li= link_to 'Login Report', login_report_path, class: 'dropdown-item' |
|
64 | + %li= link_to 'Login Report', login_report_path, class: 'dropdown-item'+active_class_when(controller: :report, action: :login) |
|
65 | - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0 |
|
65 | - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0 |
|
66 | =link_to "#{ungraded} backlogs!", |
|
66 | =link_to "#{ungraded} backlogs!", |
|
67 | graders_list_path, |
|
67 | graders_list_path, |
|
68 | class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission' |
|
68 | class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission' |
|
69 | / announcement |
|
69 | / announcement |
|
70 | - @nav_announcement.each do |ann| |
|
70 | - @nav_announcement.each do |ann| |
|
71 | %p.navbar-text |
|
71 | %p.navbar-text |
|
72 | = ann.body.html_safe |
|
72 | = ann.body.html_safe |
|
73 | %ul.navbar-nav |
|
73 | %ul.navbar-nav |
|
74 | %li.nav-item |
|
74 | %li.nav-item |
|
75 | %a.nav-link{href: help_main_path} |
|
75 | %a.nav-link{href: help_main_path} |
|
76 | %span.mi.mi-bs.md-18 help |
|
76 | %span.mi.mi-bs.md-18 help |
|
77 | %li.nav-item |
|
77 | %li.nav-item |
|
78 | %a.nav-link{href: messages_path} |
|
78 | %a.nav-link{href: messages_path} |
|
79 | %span.mi.mi-bs.md-18 chat |
|
79 | %span.mi.mi-bs.md-18 chat |
|
80 | - if GraderConfiguration['system.user_setting_enabled'] |
|
80 | - if GraderConfiguration['system.user_setting_enabled'] |
|
81 | %li.nav-item |
|
81 | %li.nav-item |
|
82 | %a.nav-link{href: profile_users_path} |
|
82 | %a.nav-link{href: profile_users_path} |
|
83 | %span.mi.mi-bs.md-18 settings |
|
83 | %span.mi.mi-bs.md-18 settings |
|
84 | %li.nav-item |
|
84 | %li.nav-item |
|
85 | %a.nav-link{href: login_main_path} |
|
85 | %a.nav-link{href: login_main_path} |
|
86 | %span.mi.mi-bs.md-18 exit_to_app |
|
86 | %span.mi.mi-bs.md-18 exit_to_app |
|
87 | = @current_user.full_name |
|
87 | = @current_user.full_name |
|
|
88 | + :javascript | ||
|
|
89 | + $('.active-with-children').each( (index,obj) => { | ||
|
|
90 | + if ($(obj).siblings('.dropdown-menu').has('.active').length > 0) { | ||
|
|
91 | + $(obj).addClass('active') | ||
|
|
92 | + } | ||
|
|
93 | + } ) |
@@ -1,55 +1,78 | |||||
|
1 | - = error_messages_for 'problem' |
|
1 | + = simple_form_for problem do |form| |
|
2 | - / [form:problem] |
|
2 | + .row |
|
3 | - .form-group |
|
3 | + .col-md-6 |
|
4 | - %label{:for => "problem_name"} Name |
|
4 | + = form.input :name |
|
5 | - = text_field 'problem', 'name', class: 'form-control' |
|
5 | + = form.input :full_name |
|
6 | - %small |
|
6 | + = form.input :full_score |
|
7 | - Do not directly edit the problem name, unless you know what you are doing. If you want to change the name, use the name change button in the problem management menu instead. |
|
7 | + = form.input :tag_ids, collection: Tag.all, class: 'select2' |
|
8 | - .form-group |
|
8 | + = form.input :date_added |
|
9 | - %label{:for => "problem_full_name"} Full name |
|
9 | + = form.input :available |
|
10 | - = text_field 'problem', 'full_name', class: 'form-control' |
|
10 | + = form.input :test_allowed |
|
11 | - .form-group |
|
11 | + = form.input :output_only |
|
12 | - %label{:for => "problem_full_score"} Full score |
|
12 | + = form.input :description, as: :text |
|
13 | - = text_field 'problem', 'full_score', class: 'form-control' |
|
13 | + = form.input :markdown |
|
14 | - .form-group |
|
14 | + = form.input :url |
|
15 | - %label{:for => "problem_full_score"} Tags |
|
15 | + = form.input :statement |
|
16 | - = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'}) |
|
16 | + %p |
|
17 | - .form-group |
|
17 | + - if @problem.statement.attached? |
|
18 | - %label{:for => "problem_date_added"} Date added |
|
18 | + %a{href: get_statement_problem_path(@problem)} [Download current Statement] |
|
19 | - = date_select 'problem', 'date_added', class: 'form-control' |
|
19 | + - else |
|
20 | - - # TODO: these should be put in model Problem, but I can't think of |
|
20 | + no statement attached to this problem |
|
21 | - - # nice default values for them. These values look fine only |
|
21 | + = form.submit :submit, class: 'btn btn-primary' |
|
22 | - - # in this case (of lazily adding new problems). |
|
22 | + -# |
|
23 | - - @problem.available = true if @problem!=nil and @problem.available==nil |
|
23 | + = error_messages_for 'problem' |
|
24 | - - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil |
|
24 | + |
|
25 | - - @problem.output_only = false if @problem!=nil and @problem.output_only==nil |
|
25 | + / [form:problem] |
|
26 | - .checkbox |
|
26 | + .form-group |
|
27 |
- %label{:for => "problem_ |
|
27 | + %label{:for => "problem_name"} Name |
|
28 | - = check_box :problem, :available |
|
28 | + = text_field 'problem', 'name', class: 'form-control' |
|
29 | - Available? |
|
29 | + %small |
|
30 | - .checkbox |
|
30 | + Do not directly edit the problem name, unless you know what you are doing. If you want to change the name, use the name change button in the problem management menu instead. |
|
31 | - %label{:for => "problem_test_allowed"} |
|
31 | + .form-group |
|
32 | - = check_box :problem, :test_allowed |
|
32 | + %label{:for => "problem_full_name"} Full name |
|
33 | - Test allowed? |
|
33 | + = text_field 'problem', 'full_name', class: 'form-control' |
|
34 | - .checkbox |
|
34 | + .form-group |
|
35 |
- %label{:for => "problem_ |
|
35 | + %label{:for => "problem_full_score"} Full score |
|
36 | - = check_box :problem, :output_only |
|
36 | + = text_field 'problem', 'full_score', class: 'form-control' |
|
37 | - Output only? |
|
37 | + .form-group |
|
38 | - = error_messages_for 'description' |
|
38 | + %label{:for => "problem_full_score"} Tags |
|
39 | - .form-group |
|
39 | + = collection_select(:problem, :tag_ids, Tag.all, :id, :name, {}, {multiple: true, class: 'form-control select2'}) |
|
40 | - %label{:for => "description_body"} Description |
|
40 | + .form-group |
|
41 | - %br/ |
|
41 | + %label{:for => "problem_date_added"} Date added |
|
42 | - = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control' |
|
42 | + = date_select 'problem', 'date_added', class: 'form-control' |
|
43 | - .form-group |
|
43 | + - # TODO: these should be put in model Problem, but I can't think of |
|
44 | - %label{:for => "description_markdowned"} Markdowned? |
|
44 | + - # nice default values for them. These values look fine only |
|
45 | - = select "description", | |
|
45 | + - # in this case (of lazily adding new problems). |
|
46 | - "markdowned", | |
|
46 | + - @problem.available = true if @problem!=nil and @problem.available==nil |
|
47 | - [['True',true],['False',false]], | |
|
47 | + - @problem.test_allowed = true if @problem!=nil and @problem.test_allowed==nil |
|
48 | - {:selected => (@description) ? @description.markdowned : false } | |
|
48 | + - @problem.output_only = false if @problem!=nil and @problem.output_only==nil |
|
49 | - .form-group |
|
49 | + .checkbox |
|
50 |
- %label{:for => "problem_ |
|
50 | + %label{:for => "problem_available"} |
|
51 | - %br/ |
|
51 | + = check_box :problem, :available |
|
52 | - = text_field 'problem', 'url',class: 'form-control' |
|
52 | + Available? |
|
53 | - %p |
|
53 | + .checkbox |
|
54 | - Task PDF #{file_field_tag 'file'} |
|
54 | + %label{:for => "problem_test_allowed"} |
|
55 | - / [eoform:problem] |
|
55 | + = check_box :problem, :test_allowed |
|
|
56 | + Test allowed? | ||
|
|
57 | + .checkbox | ||
|
|
58 | + %label{:for => "problem_output_only"} | ||
|
|
59 | + = check_box :problem, :output_only | ||
|
|
60 | + Output only? | ||
|
|
61 | + = error_messages_for 'description' | ||
|
|
62 | + .form-group | ||
|
|
63 | + %label{:for => "description_body"} Description | ||
|
|
64 | + %br/ | ||
|
|
65 | + = text_area :description, :body, :rows => 10, :cols => 80,class: 'form-control' | ||
|
|
66 | + .form-group | ||
|
|
67 | + %label{:for => "description_markdowned"} Markdowned? | ||
|
|
68 | + = select "description", | | ||
|
|
69 | + "markdowned", | | ||
|
|
70 | + [['True',true],['False',false]], | | ||
|
|
71 | + {:selected => (@description) ? @description.markdowned : false } | | ||
|
|
72 | + .form-group | ||
|
|
73 | + %label{:for => "problem_url"} URL | ||
|
|
74 | + %br/ | ||
|
|
75 | + = text_field 'problem', 'url',class: 'form-control' | ||
|
|
76 | + %p | ||
|
|
77 | + Task PDF #{file_field_tag 'file'} | ||
|
|
78 | + / [eoform:problem] |
@@ -1,14 +1,6 | |||||
|
1 | - .container-fluid |
|
1 | + %h1 Editing Problem |
|
2 | - = form_for @problem,url:{action: 'update'},html: {multipart: true} do |
|
2 | + |
|
3 | - .row |
|
3 | + = render 'form', problem: @problem |
|
4 | - .col-md-6 |
|
4 | + .row.my-3 |
|
5 | - %h1 Editing problem |
|
5 | + .col-md-4 |
|
6 | - = render :partial => 'form' |
|
6 | + = link_to 'Back', problems_path, class: 'btn btn-secondary' |
|
7 | - .row |
|
||
|
8 | - .col-md-4 |
|
||
|
9 | - = submit_tag 'Edit', class: 'btn btn-primary btn-block' |
|
||
|
10 | - .col-md-4 |
|
||
|
11 | - = link_to 'Show', {:action => 'show', :id => @problem}, class: 'btn btn-default btn-block' |
|
||
|
12 | - .col-md-4 |
|
||
|
13 | - = link_to 'Back', problems_path, class: 'btn btn-default btn-block' |
|
||
|
14 | - .div{style: 'height: 5em'} |
|
@@ -28,38 +28,40 | |||||
|
28 | %th Date added |
|
28 | %th Date added |
|
29 | %th.text-center |
|
29 | %th.text-center |
|
30 | Avail? |
|
30 | Avail? |
|
31 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?] |
|
31 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?] |
|
32 | %th.text-center |
|
32 | %th.text-center |
|
33 | View Data? |
|
33 | View Data? |
|
34 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?] |
|
34 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?] |
|
35 | %th.text-center |
|
35 | %th.text-center |
|
36 | Test? |
|
36 | Test? |
|
37 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?] |
|
37 | %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?] |
|
38 | - if GraderConfiguration.multicontests? |
|
38 | - if GraderConfiguration.multicontests? |
|
39 | %th Contests |
|
39 | %th Contests |
|
|
40 | + %th.text-center | ||
|
|
41 | + %th.text-center | ||
|
|
42 | + %th.text-center | ||
|
40 | - for problem in @problems |
|
43 | - for problem in @problems |
|
41 | %tr{:class => "#{(problem.available) ? "bg-success bg-opacity-25" : "bg-opacity-25"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"} |
|
44 | %tr{:class => "#{(problem.available) ? "bg-success bg-opacity-25" : "bg-opacity-25"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"} |
|
42 | - @problem=problem |
|
45 | - @problem=problem |
|
43 | %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1 |
|
46 | %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1 |
|
44 | %td |
|
47 | %td |
|
45 | = problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 |
|
48 | = problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1 |
|
46 | = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem |
|
49 | = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem |
|
47 | %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1 |
|
50 | %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1 |
|
48 | %td |
|
51 | %td |
|
49 | - problem.tags.each do |t| |
|
52 | - problem.tags.each do |t| |
|
50 | - #%button.btn.btn-default.btn-sm= t.name |
|
53 | - #%button.btn.btn-default.btn-sm= t.name |
|
51 | %span.label.label-default= t.name |
|
54 | %span.label.label-default= t.name |
|
52 | %td= link_to "Submit", direct_edit_problem_submissions_path(problem,@current_user.id), class: 'btn btn-sm btn-primary' |
|
55 | %td= link_to "Submit", direct_edit_problem_submissions_path(problem,@current_user.id), class: 'btn btn-sm btn-primary' |
|
53 | %td= problem.date_added |
|
56 | %td= problem.date_added |
|
54 | %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}") |
|
57 | %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}") |
|
55 | %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}") |
|
58 | %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}") |
|
56 | %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}") |
|
59 | %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}") |
|
57 | - if GraderConfiguration.multicontests? |
|
60 | - if GraderConfiguration.multicontests? |
|
58 | %td |
|
61 | %td |
|
59 | = problem.contests.collect { |c| c.name }.join(', ') |
|
62 | = problem.contests.collect { |c| c.name }.join(', ') |
|
60 | %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-sm btn-block' |
|
63 | %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-sm btn-block' |
|
61 | - %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-info btn-sm btn-block' |
|
||
|
62 | %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-sm btn-block' |
|
64 | %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-sm btn-block' |
|
63 | %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-sm btn-block' |
|
65 | %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-sm btn-block' |
|
64 | %br/ |
|
66 | %br/ |
|
65 | = link_to '[New problem]', :action => 'new' |
|
67 | = link_to '[New problem]', :action => 'new' |
@@ -103,25 +103,25 | |||||
|
103 | # defaulting to :span. |
|
103 | # defaulting to :span. |
|
104 | # config.item_wrapper_tag = :span |
|
104 | # config.item_wrapper_tag = :span |
|
105 |
|
105 | ||
|
106 | # You can define a class to use in all item wrappers. Defaulting to none. |
|
106 | # You can define a class to use in all item wrappers. Defaulting to none. |
|
107 | # config.item_wrapper_class = nil |
|
107 | # config.item_wrapper_class = nil |
|
108 |
|
108 | ||
|
109 | # How the label text should be generated altogether with the required text. |
|
109 | # How the label text should be generated altogether with the required text. |
|
110 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } |
|
110 | # config.label_text = lambda { |label, required, explicit_label| "#{required} #{label}" } |
|
111 |
|
111 | ||
|
112 | # You can define the class to use on all labels. Default is nil. |
|
112 | # You can define the class to use on all labels. Default is nil. |
|
113 | # config.label_class = nil |
|
113 | # config.label_class = nil |
|
114 |
|
114 | ||
|
115 | - # You can define the default class to be used on forms. Can be overriden |
|
115 | + # You can define the default class to be used on forms. Can be overridden |
|
116 | # with `html: { :class }`. Defaulting to none. |
|
116 | # with `html: { :class }`. Defaulting to none. |
|
117 | # config.default_form_class = nil |
|
117 | # config.default_form_class = nil |
|
118 |
|
118 | ||
|
119 | # You can define which elements should obtain additional classes |
|
119 | # You can define which elements should obtain additional classes |
|
120 | # config.generate_additional_classes_for = [:wrapper, :label, :input] |
|
120 | # config.generate_additional_classes_for = [:wrapper, :label, :input] |
|
121 |
|
121 | ||
|
122 | # Whether attributes are required by default (or not). Default is true. |
|
122 | # Whether attributes are required by default (or not). Default is true. |
|
123 | # config.required_by_default = true |
|
123 | # config.required_by_default = true |
|
124 |
|
124 | ||
|
125 | # Tell browsers whether to use the native HTML5 validations (novalidate form option). |
|
125 | # Tell browsers whether to use the native HTML5 validations (novalidate form option). |
|
126 | # These validations are enabled in SimpleForm's internal config but disabled by default |
|
126 | # These validations are enabled in SimpleForm's internal config but disabled by default |
|
127 | # in this configuration, which is recommended due to some quirks from different browsers. |
|
127 | # in this configuration, which is recommended due to some quirks from different browsers. |
@@ -1,19 +1,17 | |||||
|
1 | # frozen_string_literal: true |
|
1 | # frozen_string_literal: true |
|
2 |
|
2 | ||
|
3 | - # Please do not make direct changes to this file! |
|
3 | + # These defaults are defined and maintained by the community at |
|
4 | - # This generator is maintained by the community around simple_form-bootstrap: |
|
4 | + # https://github.com/heartcombo/simple_form-bootstrap |
|
5 | - # https://github.com/rafaelfranca/simple_form-bootstrap |
|
5 | + # Please submit feedback, changes and tests only there. |
|
6 | - # All future development, tests, and organization should happen there. |
|
||
|
7 | - # Background history: https://github.com/heartcombo/simple_form/issues/1561 |
|
||
|
8 |
|
6 | ||
|
9 | # Uncomment this and change the path if necessary to include your own |
|
7 | # Uncomment this and change the path if necessary to include your own |
|
10 | # components. |
|
8 | # components. |
|
11 | # See https://github.com/heartcombo/simple_form#custom-components |
|
9 | # See https://github.com/heartcombo/simple_form#custom-components |
|
12 | # to know more about custom components. |
|
10 | # to know more about custom components. |
|
13 | # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f } |
|
11 | # Dir[Rails.root.join('lib/components/**/*.rb')].each { |f| require f } |
|
14 |
|
12 | ||
|
15 | # Use this setup block to configure all options available in SimpleForm. |
|
13 | # Use this setup block to configure all options available in SimpleForm. |
|
16 | SimpleForm.setup do |config| |
|
14 | SimpleForm.setup do |config| |
|
17 | # Default class for buttons |
|
15 | # Default class for buttons |
|
18 | config.button_class = 'btn' |
|
16 | config.button_class = 'btn' |
|
19 |
|
17 | ||
@@ -34,407 +32,341 | |||||
|
34 | config.include_default_input_wrapper_class = false |
|
32 | config.include_default_input_wrapper_class = false |
|
35 |
|
33 | ||
|
36 | # CSS class to add for error notification helper. |
|
34 | # CSS class to add for error notification helper. |
|
37 | config.error_notification_class = 'alert alert-danger' |
|
35 | config.error_notification_class = 'alert alert-danger' |
|
38 |
|
36 | ||
|
39 | # Method used to tidy up errors. Specify any Rails Array method. |
|
37 | # Method used to tidy up errors. Specify any Rails Array method. |
|
40 | # :first lists the first message for each field. |
|
38 | # :first lists the first message for each field. |
|
41 | # :to_sentence to list all errors for each field. |
|
39 | # :to_sentence to list all errors for each field. |
|
42 | config.error_method = :to_sentence |
|
40 | config.error_method = :to_sentence |
|
43 |
|
41 | ||
|
44 | # add validation classes to `input_field` |
|
42 | # add validation classes to `input_field` |
|
45 | config.input_field_error_class = 'is-invalid' |
|
43 | config.input_field_error_class = 'is-invalid' |
|
46 | - config.input_field_valid_class = 'is-valid' |
|
44 | + config.input_field_valid_class = 'is-valid-xxx' |
|
47 |
|
45 | ||
|
48 |
|
46 | ||
|
49 | # vertical forms |
|
47 | # vertical forms |
|
50 | # |
|
48 | # |
|
51 | # vertical default_wrapper |
|
49 | # vertical default_wrapper |
|
52 | - config.wrappers :vertical_form, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b| |
|
50 | + config.wrappers :vertical_form, class: 'mb-3' do |b| |
|
53 | b.use :html5 |
|
51 | b.use :html5 |
|
54 | b.use :placeholder |
|
52 | b.use :placeholder |
|
55 | b.optional :maxlength |
|
53 | b.optional :maxlength |
|
56 | b.optional :minlength |
|
54 | b.optional :minlength |
|
57 | b.optional :pattern |
|
55 | b.optional :pattern |
|
58 | b.optional :min_max |
|
56 | b.optional :min_max |
|
59 | b.optional :readonly |
|
57 | b.optional :readonly |
|
60 | - b.use :label |
|
58 | + b.use :label, class: 'form-label' |
|
61 |
- b.use :input, class: 'form-control', error_class: 'is-invalid' |
|
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 |
|
303 | end |
|
336 | - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' } |
|
||
|
337 | - end |
|
||
|
338 | - |
|
||
|
339 | - # custom multi select |
|
||
|
340 | - config.wrappers :custom_multi_select, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b| |
|
||
|
341 | - b.use :html5 |
|
||
|
342 | - b.optional :readonly |
|
||
|
343 | - b.use :label |
|
||
|
344 | - b.wrapper tag: 'div', class: 'd-flex flex-row justify-content-between align-items-center' do |ba| |
|
||
|
345 | - ba.use :input, class: 'custom-select mx-1', error_class: 'is-invalid', valid_class: 'is-valid' |
|
||
|
346 | - end |
|
||
|
347 | - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' } |
|
||
|
348 | - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' } |
|
||
|
349 | - end |
|
||
|
350 | - |
|
||
|
351 | - # custom range input |
|
||
|
352 | - config.wrappers :custom_range, tag: 'div', class: 'form-group', error_class: 'form-group-invalid', valid_class: 'form-group-valid' do |b| |
|
||
|
353 | - b.use :html5 |
|
||
|
354 | - b.use :placeholder |
|
||
|
355 | - b.optional :readonly |
|
||
|
356 | - b.optional :step |
|
||
|
357 | - b.use :label |
|
||
|
358 | - b.use :input, class: 'custom-range', error_class: 'is-invalid', valid_class: 'is-valid' |
|
||
|
359 | - b.use :full_error, wrap_with: { tag: 'div', class: 'invalid-feedback d-block' } |
|
||
|
360 | - b.use :hint, wrap_with: { tag: 'small', class: 'form-text text-muted' } |
|
||
|
361 | end |
|
304 | end |
|
362 |
|
305 | ||
|
363 |
|
306 | ||
|
364 | # Input Group - custom component |
|
307 | # Input Group - custom component |
|
365 |
- # see example app and config at https://github.com/ |
|
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 |
@@ -25,24 +25,25 | |||||
|
25 | resources :announcements do |
|
25 | resources :announcements do |
|
26 | member do |
|
26 | member do |
|
27 | get 'toggle','toggle_front' |
|
27 | get 'toggle','toggle_front' |
|
28 | end |
|
28 | end |
|
29 | end |
|
29 | end |
|
30 |
|
30 | ||
|
31 | resources :problems do |
|
31 | resources :problems do |
|
32 | member do |
|
32 | member do |
|
33 | get 'toggle' |
|
33 | get 'toggle' |
|
34 | get 'toggle_test' |
|
34 | get 'toggle_test' |
|
35 | get 'toggle_view_testcase' |
|
35 | get 'toggle_view_testcase' |
|
36 | get 'stat' |
|
36 | get 'stat' |
|
|
37 | + get 'get_statement' | ||
|
37 | end |
|
38 | end |
|
38 | collection do |
|
39 | collection do |
|
39 | get 'turn_all_off' |
|
40 | get 'turn_all_off' |
|
40 | get 'turn_all_on' |
|
41 | get 'turn_all_on' |
|
41 | get 'import' |
|
42 | get 'import' |
|
42 | get 'manage' |
|
43 | get 'manage' |
|
43 | get 'quick_create' |
|
44 | get 'quick_create' |
|
44 | post 'do_manage' |
|
45 | post 'do_manage' |
|
45 | post 'do_import' |
|
46 | post 'do_import' |
|
46 | end |
|
47 | end |
|
47 | end |
|
48 | end |
|
48 |
|
49 |
@@ -1,79 +1,107 | |||||
|
1 | # This file is auto-generated from the current state of the database. Instead |
|
1 | # This file is auto-generated from the current state of the database. Instead |
|
2 | # of editing this file, please use the migrations feature of Active Record to |
|
2 | # of editing this file, please use the migrations feature of Active Record to |
|
3 | # incrementally modify your database, and then regenerate this schema definition. |
|
3 | # incrementally modify your database, and then regenerate this schema definition. |
|
4 | # |
|
4 | # |
|
5 | # This file is the source Rails uses to define your schema when running `bin/rails |
|
5 | # This file is the source Rails uses to define your schema when running `bin/rails |
|
6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to |
|
6 | # db:schema:load`. When creating a new database, `bin/rails db:schema:load` tends to |
|
7 | # be faster and is potentially less error prone than running all of your |
|
7 | # be faster and is potentially less error prone than running all of your |
|
8 | # migrations from scratch. Old migrations may fail to apply correctly if those |
|
8 | # migrations from scratch. Old migrations may fail to apply correctly if those |
|
9 | # migrations use external dependencies or application code. |
|
9 | # migrations use external dependencies or application code. |
|
10 | # |
|
10 | # |
|
11 | # It's strongly recommended that you check this file into your version control system. |
|
11 | # It's strongly recommended that you check this file into your version control system. |
|
12 |
|
12 | ||
|
13 |
- ActiveRecord::Schema[7.0].define(version: 2022_02_04 |
|
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 | ||
@@ -86,240 +114,233 | |||||
|
86 | create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t| |
|
114 | create_table "groups_problems", id: false, charset: "latin1", force: :cascade do |t| |
|
87 | t.integer "problem_id", null: false |
|
115 | t.integer "problem_id", null: false |
|
88 | t.integer "group_id", null: false |
|
116 | t.integer "group_id", null: false |
|
89 | t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id" |
|
117 | t.index ["group_id", "problem_id"], name: "index_groups_problems_on_group_id_and_problem_id" |
|
90 | end |
|
118 | end |
|
91 |
|
119 | ||
|
92 | create_table "groups_users", charset: "latin1", force: :cascade do |t| |
|
120 | create_table "groups_users", charset: "latin1", force: :cascade do |t| |
|
93 | t.integer "group_id", null: false |
|
121 | t.integer "group_id", null: false |
|
94 | t.integer "user_id", null: false |
|
122 | t.integer "user_id", null: false |
|
95 | t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id" |
|
123 | t.index ["user_id", "group_id"], name: "index_groups_users_on_user_id_and_group_id" |
|
96 | end |
|
124 | end |
|
97 |
|
125 | ||
|
98 |
- create_table "heart_beats", id: :integer, charset: " |
|
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