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

r628:3df78cd5515f - - 25 files changed: 560 inserted, 168 deleted

@@ -0,0 +1,24
1 + class TestcasesController < ApplicationController
2 + before_action :set_testcase, only: [:download_input,:download_sol]
3 + before_action :testcase_authorization
4 +
5 + def download_input
6 + send_data @testcase.input, type: 'text/plain', filename: "#{@testcase.problem.name}.#{@testcase.num}.in"
7 + end
8 +
9 + def download_sol
10 + send_data @testcase.sol, type: 'text/plain', filename: "#{@testcase.problem.name}.#{@testcase.num}.sol"
11 + end
12 +
13 +
14 + private
15 + # Use callbacks to share common setup or constraints between actions.
16 + def set_testcase
17 + @testcase = Testcase.find(params[:id])
18 + end
19 +
20 + # Only allow a trusted parameter "white list" through.
21 + def testcase_params
22 + params[:testcase]
23 + end
24 + end
@@ -0,0 +1,2
1 + module TestcasesHelper
2 + end
@@ -0,0 +1,25
1 + %h1 Test cases
2 + %h2= @problem.long_name
3 +
4 + /navbar
5 + %ul.nav.nav-pills{role: :tablist}
6 + - @problem.testcases.each.with_index do |tc,id|
7 + %li{role: :presentation, class: ('active' if id == 0)}
8 + %a{href:"#tc#{tc.id}", role: 'tab', data: {toggle: 'tab'}}= tc.num
9 +
10 + /actual data
11 + .tab-content
12 + - @problem.testcases.each.with_index do |tc,id|
13 + .tab-pane{id: "tc#{tc.id}",class: ('active' if id == 0)}
14 + .row
15 + .col-md-6
16 + %h3 Input
17 + = link_to "Download",download_input_problem_testcase_path(@problem,tc),class: 'btn btn-info btn-sm'
18 + .col-md-6
19 + %h3 Output
20 + = link_to "Download",download_sol_problem_testcase_path(@problem,tc),class: 'btn btn-info btn-sm'
21 + .row
22 + .col-md-6
23 + %textarea{ rows: 25,readonly: true,style: "width:100%;resize=none;overflow-y: scroll;"}= tc.input
24 + .col-md-6
25 + %textarea{ rows: 25,readonly: true,style: "width:100%;resize=none;overflow-y: scroll;"}= tc.sol
@@ -0,0 +1,41
1 + # Original from http://snippets.dzone.com/posts/show/4468 by MichaelBoutros
2 + #
3 + # Optimized version which uses to_yaml for content creation and checks
4 + # that models are ActiveRecord::Base models before trying to fetch
5 + # them from database.
6 + namespace :db do
7 + namespace :fixtures do
8 + desc 'Dumps all models into fixtures.'
9 + task :dump => :environment do
10 + puts "rails root = #{Rails.root}"
11 + models = Dir.glob(Rails.root.to_s + '/app/models/**.rb').map do |s|
12 + Pathname.new(s).basename.to_s.gsub(/\.rb$/,'').camelize
13 + end
14 +
15 + puts "Found models: " + models.join(', ')
16 +
17 + models.each do |m|
18 + model = m.constantize
19 + next unless model.ancestors.include?(ActiveRecord::Base)
20 +
21 + puts "Dumping model: " + m
22 + entries = model.all.order(id: :asc)
23 +
24 + increment = 1
25 +
26 + model_file = Rails.root.to_s + '/test/fixtures2/' + m.underscore.pluralize + '.yml'
27 + File.open(model_file, 'w') do |f|
28 + entries.each do |a|
29 + attrs = a.attributes
30 + attrs.delete_if{|k,v| v.blank?}
31 +
32 + output = {m + '_' + increment.to_s => attrs}
33 + f << output.to_yaml.gsub(/^--- \n/,'') + "\n"
34 +
35 + increment += 1
36 + end
37 + end
38 + end
39 + end
40 + end
41 + end
@@ -0,0 +1,7
1 + require 'test_helper'
2 +
3 + class TestcasesControllerTest < ActionController::TestCase
4 + setup do
5 + @testcase = testcases(:one)
6 + end
7 + end
@@ -0,0 +1,144
1 + GraderConfiguration_1:
2 + key: system.single_user_mode
3 + value_type: boolean
4 + value: 'false'
5 + description: Only admins can log in to the system when running under single user mode.
6 +
7 + GraderConfiguration_2:
8 + key: ui.front.title
9 + value_type: string
10 + value: Grader
11 +
12 + GraderConfiguration_3:
13 + key: ui.front.welcome_message
14 + value_type: string
15 + value: Welcome!
16 +
17 + GraderConfiguration_4:
18 + key: ui.show_score
19 + value_type: boolean
20 + value: 'true'
21 +
22 + GraderConfiguration_5:
23 + key: contest.time_limit
24 + value_type: string
25 + value: unlimited
26 + description: Time limit in format hh:mm, or "unlimited" for contests with no time
27 + limits. This config is CACHED. Restart the server before the change can take
28 + effect.
29 +
30 + GraderConfiguration_6:
31 + key: system.mode
32 + value_type: string
33 + value: standard
34 + description: Current modes are "standard", "contest", "indv-contest", and "analysis".
35 +
36 +
37 + GraderConfiguration_7:
38 + key: contest.name
39 + value_type: string
40 + value: Grader
41 + description: This name will be shown on the user header bar.
42 +
43 +
44 + GraderConfiguration_8:
45 + key: contest.multisites
46 + value_type: boolean
47 + value: 'false'
48 + description: If the server is in contest mode and this option is true, on the log
49 + in of the admin a menu for site selections is shown.
50 +
51 +
52 + GraderConfiguration_9:
53 + key: right.user_hall_of_fame
54 + value_type: boolean
55 + value: 'false'
56 + description: If true, any user can access hall of fame page.
57 +
58 +
59 + GraderConfiguration_10:
60 + key: right.multiple_ip_login
61 + value_type: boolean
62 + value: 'true'
63 + description: When change from true to false, a user can login from the first IP
64 + they logged into afterward.
65 +
66 +
67 + GraderConfiguration_11:
68 + key: right.user_view_submission
69 + value_type: boolean
70 + value: 'false'
71 + description: If true, any user can view submissions of every one.
72 +
73 +
74 + GraderConfiguration_12:
75 + key: right.bypass_agreement
76 + value_type: boolean
77 + value: 'true'
78 + description: When false, a user must accept usage agreement before login
79 +
80 +
81 + GraderConfiguration_13:
82 + key: right.heartbeat_response
83 + value_type: string
84 + value: OK
85 + description: Heart beat response text
86 +
87 +
88 + GraderConfiguration_14:
89 + key: right.view_testcase
90 + value_type: boolean
91 + value: 'false'
92 + description: When true, any user can view/download test data
93 +
94 +
95 + GraderConfiguration_15:
96 + key: system.online_registration.smtp
97 + value_type: string
98 + value: smtp.somehost.com
99 +
100 +
101 + GraderConfiguration_16:
102 + key: system.online_registration.from
103 + value_type: string
104 + value: your.email@address
105 +
106 +
107 + GraderConfiguration_17:
108 + key: system.admin_email
109 + value_type: string
110 + value: admin@admin.email
111 +
112 +
113 + GraderConfiguration_18:
114 + key: system.user_setting_enabled
115 + value_type: boolean
116 + value: 'true'
117 + description: If this option is true, users can change their settings
118 +
119 +
120 + GraderConfiguration_19:
121 + key: contest.test_request.early_timeout
122 + value_type: boolean
123 + value: 'false'
124 +
125 +
126 + GraderConfiguration_20:
127 + key: system.multicontests
128 + value_type: boolean
129 + value: 'false'
130 +
131 +
132 + GraderConfiguration_21:
133 + key: contest.confirm_indv_contest_start
134 + value_type: boolean
135 + value: 'false'
136 +
137 +
138 + GraderConfiguration_22:
139 + key: contest.default_contest_name
140 + value_type: string
141 + value: none
142 + description: New user will be assigned to this contest automatically, if it exists. Set
143 + to 'none' if there is no default contest.
144 +
@@ -1,78 +1,88
1 source 'https://rubygems.org'
1 source 'https://rubygems.org'
2
2
3 + #rails
3 gem 'rails', '~>4.2.0'
4 gem 'rails', '~>4.2.0'
4 gem 'activerecord-session_store'
5 gem 'activerecord-session_store'
5
6
6 - gem 'select2-rails'
7
7
8 # Bundle edge Rails instead:
8 # Bundle edge Rails instead:
9 # gem 'rails', :git => 'git://github.com/rails/rails.git'
9 # gem 'rails', :git => 'git://github.com/rails/rails.git'
10
10
11 + #---------------- database ---------------------
12 + #the database
11 gem 'mysql2'
13 gem 'mysql2'
14 + #for testing
12 gem 'sqlite3'
15 gem 'sqlite3'
16 + #for dumping database into yaml
17 + gem 'yaml_db'
13
18
14 # Gems used only for assets and not required
19 # Gems used only for assets and not required
15 # in production environments by default.
20 # in production environments by default.
16 gem 'sass-rails'
21 gem 'sass-rails'
17 gem 'coffee-rails'
22 gem 'coffee-rails'
18
23
19 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
24 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
20 # gem 'therubyracer', :platforms => :ruby
25 # gem 'therubyracer', :platforms => :ruby
21
26
22 gem 'uglifier'
27 gem 'uglifier'
23
28
24 -
29 + gem 'haml'
30 + gem 'haml-rails'
25 # gem 'prototype-rails'
31 # gem 'prototype-rails'
26
32
27 # To use ActiveModel has_secure_password
33 # To use ActiveModel has_secure_password
28 # gem 'bcrypt-ruby', '~> 3.0.0'
34 # gem 'bcrypt-ruby', '~> 3.0.0'
29
35
30 # To use Jbuilder templates for JSON
36 # To use Jbuilder templates for JSON
31 # gem 'jbuilder'
37 # gem 'jbuilder'
32
38
33 # Use unicorn as the app server
39 # Use unicorn as the app server
34 # gem 'unicorn'
40 # gem 'unicorn'
35
41
36 # Deploy with Capistrano
42 # Deploy with Capistrano
37 # gem 'capistrano'
43 # gem 'capistrano'
38
44
39 # To use debugger
45 # To use debugger
40 # gem 'debugger'
46 # gem 'debugger'
41 #
47 #
42
48
43 #in-place editor
49 #in-place editor
44 gem 'best_in_place', '~> 3.0.1'
50 gem 'best_in_place', '~> 3.0.1'
45
51
46 # jquery addition
52 # jquery addition
47 gem 'jquery-rails'
53 gem 'jquery-rails'
48 gem 'jquery-ui-rails'
54 gem 'jquery-ui-rails'
49 gem 'jquery-timepicker-addon-rails'
55 gem 'jquery-timepicker-addon-rails'
50 gem 'jquery-tablesorter'
56 gem 'jquery-tablesorter'
51 gem 'jquery-countdown-rails'
57 gem 'jquery-countdown-rails'
52
58
53 #syntax highlighter
59 #syntax highlighter
54 gem 'rouge'
60 gem 'rouge'
55
61
56 #add bootstrap
62 #add bootstrap
57 gem 'bootstrap-sass', '~> 3.2.0'
63 gem 'bootstrap-sass', '~> 3.2.0'
58 gem 'bootstrap-switch-rails'
64 gem 'bootstrap-switch-rails'
59 gem 'bootstrap-toggle-rails'
65 gem 'bootstrap-toggle-rails'
60 gem 'autoprefixer-rails'
66 gem 'autoprefixer-rails'
61
67
62 #bootstrap sortable
68 #bootstrap sortable
63 gem 'momentjs-rails'
69 gem 'momentjs-rails'
64 gem 'rails_bootstrap_sortable'
70 gem 'rails_bootstrap_sortable'
65
71
72 + #----------- user interface -----------------
73 + #select 2
74 + gem 'select2-rails'
66 #ace editor
75 #ace editor
67 gem 'ace-rails-ap'
76 gem 'ace-rails-ap'
77 + #paginator
78 + gem 'will_paginate', '~> 3.0.7'
68
79
69 - gem 'haml'
70 - gem 'haml-rails'
71 gem 'mail'
80 gem 'mail'
72 gem 'rdiscount'
81 gem 'rdiscount'
73 - gem 'test-unit'
74 - gem 'will_paginate', '~> 3.0.7'
75 gem 'dynamic_form'
82 gem 'dynamic_form'
76 gem 'in_place_editing'
83 gem 'in_place_editing'
77 gem 'verification', :git => 'https://github.com/sikachu/verification.git'
84 gem 'verification', :git => 'https://github.com/sikachu/verification.git'
78
85
86 +
87 + #---------------- testiing -----------------------
88 + gem 'minitest-reporters'
@@ -1,221 +1,229
1 GIT
1 GIT
2 remote: https://github.com/sikachu/verification.git
2 remote: https://github.com/sikachu/verification.git
3 revision: ff31697b940d7b0e2ec65f08764215c96104e76d
3 revision: ff31697b940d7b0e2ec65f08764215c96104e76d
4 specs:
4 specs:
5 verification (1.0.3)
5 verification (1.0.3)
6 actionpack (>= 3.0.0, < 5.1)
6 actionpack (>= 3.0.0, < 5.1)
7 activesupport (>= 3.0.0, < 5.1)
7 activesupport (>= 3.0.0, < 5.1)
8
8
9 GEM
9 GEM
10 remote: https://rubygems.org/
10 remote: https://rubygems.org/
11 specs:
11 specs:
12 ace-rails-ap (4.1.1)
12 ace-rails-ap (4.1.1)
13 actionmailer (4.2.7.1)
13 actionmailer (4.2.7.1)
14 actionpack (= 4.2.7.1)
14 actionpack (= 4.2.7.1)
15 actionview (= 4.2.7.1)
15 actionview (= 4.2.7.1)
16 activejob (= 4.2.7.1)
16 activejob (= 4.2.7.1)
17 mail (~> 2.5, >= 2.5.4)
17 mail (~> 2.5, >= 2.5.4)
18 rails-dom-testing (~> 1.0, >= 1.0.5)
18 rails-dom-testing (~> 1.0, >= 1.0.5)
19 actionpack (4.2.7.1)
19 actionpack (4.2.7.1)
20 actionview (= 4.2.7.1)
20 actionview (= 4.2.7.1)
21 activesupport (= 4.2.7.1)
21 activesupport (= 4.2.7.1)
22 rack (~> 1.6)
22 rack (~> 1.6)
23 rack-test (~> 0.6.2)
23 rack-test (~> 0.6.2)
24 rails-dom-testing (~> 1.0, >= 1.0.5)
24 rails-dom-testing (~> 1.0, >= 1.0.5)
25 rails-html-sanitizer (~> 1.0, >= 1.0.2)
25 rails-html-sanitizer (~> 1.0, >= 1.0.2)
26 actionview (4.2.7.1)
26 actionview (4.2.7.1)
27 activesupport (= 4.2.7.1)
27 activesupport (= 4.2.7.1)
28 builder (~> 3.1)
28 builder (~> 3.1)
29 erubis (~> 2.7.0)
29 erubis (~> 2.7.0)
30 rails-dom-testing (~> 1.0, >= 1.0.5)
30 rails-dom-testing (~> 1.0, >= 1.0.5)
31 rails-html-sanitizer (~> 1.0, >= 1.0.2)
31 rails-html-sanitizer (~> 1.0, >= 1.0.2)
32 activejob (4.2.7.1)
32 activejob (4.2.7.1)
33 activesupport (= 4.2.7.1)
33 activesupport (= 4.2.7.1)
34 globalid (>= 0.3.0)
34 globalid (>= 0.3.0)
35 activemodel (4.2.7.1)
35 activemodel (4.2.7.1)
36 activesupport (= 4.2.7.1)
36 activesupport (= 4.2.7.1)
37 builder (~> 3.1)
37 builder (~> 3.1)
38 activerecord (4.2.7.1)
38 activerecord (4.2.7.1)
39 activemodel (= 4.2.7.1)
39 activemodel (= 4.2.7.1)
40 activesupport (= 4.2.7.1)
40 activesupport (= 4.2.7.1)
41 arel (~> 6.0)
41 arel (~> 6.0)
42 activerecord-session_store (1.0.0)
42 activerecord-session_store (1.0.0)
43 actionpack (>= 4.0, < 5.1)
43 actionpack (>= 4.0, < 5.1)
44 activerecord (>= 4.0, < 5.1)
44 activerecord (>= 4.0, < 5.1)
45 multi_json (~> 1.11, >= 1.11.2)
45 multi_json (~> 1.11, >= 1.11.2)
46 rack (>= 1.5.2, < 3)
46 rack (>= 1.5.2, < 3)
47 railties (>= 4.0, < 5.1)
47 railties (>= 4.0, < 5.1)
48 activesupport (4.2.7.1)
48 activesupport (4.2.7.1)
49 i18n (~> 0.7)
49 i18n (~> 0.7)
50 json (~> 1.7, >= 1.7.7)
50 json (~> 1.7, >= 1.7.7)
51 minitest (~> 5.1)
51 minitest (~> 5.1)
52 thread_safe (~> 0.3, >= 0.3.4)
52 thread_safe (~> 0.3, >= 0.3.4)
53 tzinfo (~> 1.1)
53 tzinfo (~> 1.1)
54 + ansi (1.5.0)
54 arel (6.0.4)
55 arel (6.0.4)
55 autoprefixer-rails (6.6.0)
56 autoprefixer-rails (6.6.0)
56 execjs
57 execjs
57 best_in_place (3.0.3)
58 best_in_place (3.0.3)
58 actionpack (>= 3.2)
59 actionpack (>= 3.2)
59 railties (>= 3.2)
60 railties (>= 3.2)
60 bootstrap-sass (3.2.0.2)
61 bootstrap-sass (3.2.0.2)
61 sass (~> 3.2)
62 sass (~> 3.2)
62 bootstrap-switch-rails (3.3.3)
63 bootstrap-switch-rails (3.3.3)
63 bootstrap-toggle-rails (2.2.1.0)
64 bootstrap-toggle-rails (2.2.1.0)
64 builder (3.2.2)
65 builder (3.2.2)
65 coffee-rails (4.2.1)
66 coffee-rails (4.2.1)
66 coffee-script (>= 2.2.0)
67 coffee-script (>= 2.2.0)
67 railties (>= 4.0.0, < 5.2.x)
68 railties (>= 4.0.0, < 5.2.x)
68 coffee-script (2.4.1)
69 coffee-script (2.4.1)
69 coffee-script-source
70 coffee-script-source
70 execjs
71 execjs
71 coffee-script-source (1.12.2)
72 coffee-script-source (1.12.2)
72 concurrent-ruby (1.0.4)
73 concurrent-ruby (1.0.4)
73 dynamic_form (1.1.4)
74 dynamic_form (1.1.4)
74 erubis (2.7.0)
75 erubis (2.7.0)
75 execjs (2.7.0)
76 execjs (2.7.0)
76 globalid (0.3.7)
77 globalid (0.3.7)
77 activesupport (>= 4.1.0)
78 activesupport (>= 4.1.0)
78 haml (4.0.7)
79 haml (4.0.7)
79 tilt
80 tilt
80 haml-rails (0.9.0)
81 haml-rails (0.9.0)
81 actionpack (>= 4.0.1)
82 actionpack (>= 4.0.1)
82 activesupport (>= 4.0.1)
83 activesupport (>= 4.0.1)
83 haml (>= 4.0.6, < 5.0)
84 haml (>= 4.0.6, < 5.0)
84 html2haml (>= 1.0.1)
85 html2haml (>= 1.0.1)
85 railties (>= 4.0.1)
86 railties (>= 4.0.1)
86 html2haml (2.0.0)
87 html2haml (2.0.0)
87 erubis (~> 2.7.0)
88 erubis (~> 2.7.0)
88 haml (~> 4.0.0)
89 haml (~> 4.0.0)
89 nokogiri (~> 1.6.0)
90 nokogiri (~> 1.6.0)
90 ruby_parser (~> 3.5)
91 ruby_parser (~> 3.5)
91 i18n (0.7.0)
92 i18n (0.7.0)
92 in_place_editing (1.2.0)
93 in_place_editing (1.2.0)
93 jquery-countdown-rails (2.0.2)
94 jquery-countdown-rails (2.0.2)
94 jquery-rails (4.2.1)
95 jquery-rails (4.2.1)
95 rails-dom-testing (>= 1, < 3)
96 rails-dom-testing (>= 1, < 3)
96 railties (>= 4.2.0)
97 railties (>= 4.2.0)
97 thor (>= 0.14, < 2.0)
98 thor (>= 0.14, < 2.0)
98 jquery-tablesorter (1.23.3)
99 jquery-tablesorter (1.23.3)
99 railties (>= 3.2, < 6)
100 railties (>= 3.2, < 6)
100 jquery-timepicker-addon-rails (1.4.1)
101 jquery-timepicker-addon-rails (1.4.1)
101 railties (>= 3.1)
102 railties (>= 3.1)
102 jquery-ui-rails (6.0.1)
103 jquery-ui-rails (6.0.1)
103 railties (>= 3.2.16)
104 railties (>= 3.2.16)
104 json (1.8.3)
105 json (1.8.3)
105 loofah (2.0.3)
106 loofah (2.0.3)
106 nokogiri (>= 1.5.9)
107 nokogiri (>= 1.5.9)
107 mail (2.6.4)
108 mail (2.6.4)
108 mime-types (>= 1.16, < 4)
109 mime-types (>= 1.16, < 4)
109 mime-types (3.1)
110 mime-types (3.1)
110 mime-types-data (~> 3.2015)
111 mime-types-data (~> 3.2015)
111 mime-types-data (3.2016.0521)
112 mime-types-data (3.2016.0521)
112 mini_portile2 (2.1.0)
113 mini_portile2 (2.1.0)
113 minitest (5.10.1)
114 minitest (5.10.1)
115 + minitest-reporters (1.1.13)
116 + ansi
117 + builder
118 + minitest (>= 5.0)
119 + ruby-progressbar
114 momentjs-rails (2.15.1)
120 momentjs-rails (2.15.1)
115 railties (>= 3.1)
121 railties (>= 3.1)
116 multi_json (1.12.1)
122 multi_json (1.12.1)
117 mysql2 (0.4.5)
123 mysql2 (0.4.5)
118 nokogiri (1.6.8.1)
124 nokogiri (1.6.8.1)
119 mini_portile2 (~> 2.1.0)
125 mini_portile2 (~> 2.1.0)
120 - power_assert (0.4.1)
121 rack (1.6.5)
126 rack (1.6.5)
122 rack-test (0.6.3)
127 rack-test (0.6.3)
123 rack (>= 1.0)
128 rack (>= 1.0)
124 rails (4.2.7.1)
129 rails (4.2.7.1)
125 actionmailer (= 4.2.7.1)
130 actionmailer (= 4.2.7.1)
126 actionpack (= 4.2.7.1)
131 actionpack (= 4.2.7.1)
127 actionview (= 4.2.7.1)
132 actionview (= 4.2.7.1)
128 activejob (= 4.2.7.1)
133 activejob (= 4.2.7.1)
129 activemodel (= 4.2.7.1)
134 activemodel (= 4.2.7.1)
130 activerecord (= 4.2.7.1)
135 activerecord (= 4.2.7.1)
131 activesupport (= 4.2.7.1)
136 activesupport (= 4.2.7.1)
132 bundler (>= 1.3.0, < 2.0)
137 bundler (>= 1.3.0, < 2.0)
133 railties (= 4.2.7.1)
138 railties (= 4.2.7.1)
134 sprockets-rails
139 sprockets-rails
135 rails-deprecated_sanitizer (1.0.3)
140 rails-deprecated_sanitizer (1.0.3)
136 activesupport (>= 4.2.0.alpha)
141 activesupport (>= 4.2.0.alpha)
137 rails-dom-testing (1.0.8)
142 rails-dom-testing (1.0.8)
138 activesupport (>= 4.2.0.beta, < 5.0)
143 activesupport (>= 4.2.0.beta, < 5.0)
139 nokogiri (~> 1.6)
144 nokogiri (~> 1.6)
140 rails-deprecated_sanitizer (>= 1.0.1)
145 rails-deprecated_sanitizer (>= 1.0.1)
141 rails-html-sanitizer (1.0.3)
146 rails-html-sanitizer (1.0.3)
142 loofah (~> 2.0)
147 loofah (~> 2.0)
143 rails_bootstrap_sortable (2.0.1)
148 rails_bootstrap_sortable (2.0.1)
144 momentjs-rails (>= 2.8.3)
149 momentjs-rails (>= 2.8.3)
145 railties (4.2.7.1)
150 railties (4.2.7.1)
146 actionpack (= 4.2.7.1)
151 actionpack (= 4.2.7.1)
147 activesupport (= 4.2.7.1)
152 activesupport (= 4.2.7.1)
148 rake (>= 0.8.7)
153 rake (>= 0.8.7)
149 thor (>= 0.18.1, < 2.0)
154 thor (>= 0.18.1, < 2.0)
150 rake (12.0.0)
155 rake (12.0.0)
151 rdiscount (2.2.0.1)
156 rdiscount (2.2.0.1)
152 rouge (2.0.7)
157 rouge (2.0.7)
158 + ruby-progressbar (1.8.1)
153 ruby_parser (3.8.3)
159 ruby_parser (3.8.3)
154 sexp_processor (~> 4.1)
160 sexp_processor (~> 4.1)
155 sass (3.4.23)
161 sass (3.4.23)
156 sass-rails (5.0.6)
162 sass-rails (5.0.6)
157 railties (>= 4.0.0, < 6)
163 railties (>= 4.0.0, < 6)
158 sass (~> 3.1)
164 sass (~> 3.1)
159 sprockets (>= 2.8, < 4.0)
165 sprockets (>= 2.8, < 4.0)
160 sprockets-rails (>= 2.0, < 4.0)
166 sprockets-rails (>= 2.0, < 4.0)
161 tilt (>= 1.1, < 3)
167 tilt (>= 1.1, < 3)
162 select2-rails (4.0.3)
168 select2-rails (4.0.3)
163 thor (~> 0.14)
169 thor (~> 0.14)
164 sexp_processor (4.7.0)
170 sexp_processor (4.7.0)
165 sprockets (3.7.1)
171 sprockets (3.7.1)
166 concurrent-ruby (~> 1.0)
172 concurrent-ruby (~> 1.0)
167 rack (> 1, < 3)
173 rack (> 1, < 3)
168 sprockets-rails (3.2.0)
174 sprockets-rails (3.2.0)
169 actionpack (>= 4.0)
175 actionpack (>= 4.0)
170 activesupport (>= 4.0)
176 activesupport (>= 4.0)
171 sprockets (>= 3.0.0)
177 sprockets (>= 3.0.0)
172 sqlite3 (1.3.12)
178 sqlite3 (1.3.12)
173 - test-unit (3.2.3)
174 - power_assert
175 thor (0.19.4)
179 thor (0.19.4)
176 thread_safe (0.3.5)
180 thread_safe (0.3.5)
177 tilt (2.0.5)
181 tilt (2.0.5)
178 tzinfo (1.2.2)
182 tzinfo (1.2.2)
179 thread_safe (~> 0.1)
183 thread_safe (~> 0.1)
180 uglifier (3.0.4)
184 uglifier (3.0.4)
181 execjs (>= 0.3.0, < 3)
185 execjs (>= 0.3.0, < 3)
182 will_paginate (3.0.12)
186 will_paginate (3.0.12)
187 + yaml_db (0.4.2)
188 + rails (>= 3.0, < 5.1)
189 + rake (>= 0.8.7)
183
190
184 PLATFORMS
191 PLATFORMS
185 ruby
192 ruby
186
193
187 DEPENDENCIES
194 DEPENDENCIES
188 ace-rails-ap
195 ace-rails-ap
189 activerecord-session_store
196 activerecord-session_store
190 autoprefixer-rails
197 autoprefixer-rails
191 best_in_place (~> 3.0.1)
198 best_in_place (~> 3.0.1)
192 bootstrap-sass (~> 3.2.0)
199 bootstrap-sass (~> 3.2.0)
193 bootstrap-switch-rails
200 bootstrap-switch-rails
194 bootstrap-toggle-rails
201 bootstrap-toggle-rails
195 coffee-rails
202 coffee-rails
196 dynamic_form
203 dynamic_form
197 haml
204 haml
198 haml-rails
205 haml-rails
199 in_place_editing
206 in_place_editing
200 jquery-countdown-rails
207 jquery-countdown-rails
201 jquery-rails
208 jquery-rails
202 jquery-tablesorter
209 jquery-tablesorter
203 jquery-timepicker-addon-rails
210 jquery-timepicker-addon-rails
204 jquery-ui-rails
211 jquery-ui-rails
205 mail
212 mail
213 + minitest-reporters
206 momentjs-rails
214 momentjs-rails
207 mysql2
215 mysql2
208 rails (~> 4.2.0)
216 rails (~> 4.2.0)
209 rails_bootstrap_sortable
217 rails_bootstrap_sortable
210 rdiscount
218 rdiscount
211 rouge
219 rouge
212 sass-rails
220 sass-rails
213 select2-rails
221 select2-rails
214 sqlite3
222 sqlite3
215 - test-unit
216 uglifier
223 uglifier
217 verification!
224 verification!
218 will_paginate (~> 3.0.7)
225 will_paginate (~> 3.0.7)
226 + yaml_db
219
227
220 BUNDLED WITH
228 BUNDLED WITH
221 1.13.6
229 1.13.6
@@ -1,128 +1,137
1 class ApplicationController < ActionController::Base
1 class ApplicationController < ActionController::Base
2 protect_from_forgery
2 protect_from_forgery
3
3
4 - before_filter :current_user
4 + before_filter :current_user
5
5
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8
8
9 #report and redirect for unauthorized activities
9 #report and redirect for unauthorized activities
10 def unauthorized_redirect
10 def unauthorized_redirect
11 flash[:notice] = 'You are not authorized to view the page you requested'
11 flash[:notice] = 'You are not authorized to view the page you requested'
12 redirect_to :controller => 'main', :action => 'login'
12 redirect_to :controller => 'main', :action => 'login'
13 end
13 end
14
14
15 # Returns the current logged-in user (if any).
15 # Returns the current logged-in user (if any).
16 def current_user
16 def current_user
17 return nil unless session[:user_id]
17 return nil unless session[:user_id]
18 @current_user ||= User.find(session[:user_id])
18 @current_user ||= User.find(session[:user_id])
19 end
19 end
20
20
21 def admin_authorization
21 def admin_authorization
22 return false unless authenticate
22 return false unless authenticate
23 user = User.includes(:roles).find(session[:user_id])
23 user = User.includes(:roles).find(session[:user_id])
24 unless user.admin?
24 unless user.admin?
25 unauthorized_redirect
25 unauthorized_redirect
26 return false
26 return false
27 end
27 end
28 return true
28 return true
29 end
29 end
30
30
31 def authorization_by_roles(allowed_roles)
31 def authorization_by_roles(allowed_roles)
32 return false unless authenticate
32 return false unless authenticate
33 user = User.find(session[:user_id])
33 user = User.find(session[:user_id])
34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
35 unauthorized_redirect
35 unauthorized_redirect
36 return false
36 return false
37 end
37 end
38 end
38 end
39
39
40 + def testcase_authorization
41 + #admin always has privileged
42 + if @current_user.admin?
43 + return true
44 + end
45 +
46 + unauthorized_redirect if GraderConfiguration["right.view_testcase"]
47 + end
48 +
40 protected
49 protected
41
50
42 def authenticate
51 def authenticate
43 unless session[:user_id]
52 unless session[:user_id]
44 flash[:notice] = 'You need to login'
53 flash[:notice] = 'You need to login'
45 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
54 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
46 flash[:notice] = 'You need to login but you cannot log in at this time'
55 flash[:notice] = 'You need to login but you cannot log in at this time'
47 end
56 end
48 redirect_to :controller => 'main', :action => 'login'
57 redirect_to :controller => 'main', :action => 'login'
49 return false
58 return false
50 end
59 end
51
60
52 # check if run in single user mode
61 # check if run in single user mode
53 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
62 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
54 user = User.find_by_id(session[:user_id])
63 user = User.find_by_id(session[:user_id])
55 if user==nil or (not user.admin?)
64 if user==nil or (not user.admin?)
56 flash[:notice] = 'You cannot log in at this time'
65 flash[:notice] = 'You cannot log in at this time'
57 redirect_to :controller => 'main', :action => 'login'
66 redirect_to :controller => 'main', :action => 'login'
58 return false
67 return false
59 end
68 end
60 unless user.enabled?
69 unless user.enabled?
61 flash[:notice] = 'Your account is disabled'
70 flash[:notice] = 'Your account is disabled'
62 redirect_to :controller => 'main', :action => 'login'
71 redirect_to :controller => 'main', :action => 'login'
63 return false
72 return false
64 end
73 end
65 return true
74 return true
66 end
75 end
67
76
68 if GraderConfiguration.multicontests?
77 if GraderConfiguration.multicontests?
69 user = User.find(session[:user_id])
78 user = User.find(session[:user_id])
70 return true if user.admin?
79 return true if user.admin?
71 begin
80 begin
72 if user.contest_stat(true).forced_logout
81 if user.contest_stat(true).forced_logout
73 flash[:notice] = 'You have been automatically logged out.'
82 flash[:notice] = 'You have been automatically logged out.'
74 redirect_to :controller => 'main', :action => 'index'
83 redirect_to :controller => 'main', :action => 'index'
75 end
84 end
76 rescue
85 rescue
77 end
86 end
78 end
87 end
79 return true
88 return true
80 end
89 end
81
90
82 def authenticate_by_ip_address
91 def authenticate_by_ip_address
83 #this assume that we have already authenticate normally
92 #this assume that we have already authenticate normally
84 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
93 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
85 user = User.find(session[:user_id])
94 user = User.find(session[:user_id])
86 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
95 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
87 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
96 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
88 redirect_to :controller => 'main', :action => 'login'
97 redirect_to :controller => 'main', :action => 'login'
89 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
98 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
90 return false
99 return false
91 end
100 end
92 unless user.last_ip
101 unless user.last_ip
93 user.last_ip = request.remote_ip
102 user.last_ip = request.remote_ip
94 user.save
103 user.save
95 end
104 end
96 end
105 end
97 return true
106 return true
98 end
107 end
99
108
100 def authorization
109 def authorization
101 return false unless authenticate
110 return false unless authenticate
102 user = User.find(session[:user_id])
111 user = User.find(session[:user_id])
103 unless user.roles.detect { |role|
112 unless user.roles.detect { |role|
104 role.rights.detect{ |right|
113 role.rights.detect{ |right|
105 right.controller == self.class.controller_name and
114 right.controller == self.class.controller_name and
106 (right.action == 'all' or right.action == action_name)
115 (right.action == 'all' or right.action == action_name)
107 }
116 }
108 }
117 }
109 flash[:notice] = 'You are not authorized to view the page you requested'
118 flash[:notice] = 'You are not authorized to view the page you requested'
110 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
119 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
111 redirect_to :controller => 'main', :action => 'login'
120 redirect_to :controller => 'main', :action => 'login'
112 return false
121 return false
113 end
122 end
114 end
123 end
115
124
116 def verify_time_limit
125 def verify_time_limit
117 return true if session[:user_id]==nil
126 return true if session[:user_id]==nil
118 user = User.find(session[:user_id], :include => :site)
127 user = User.find(session[:user_id], :include => :site)
119 return true if user==nil or user.site == nil
128 return true if user==nil or user.site == nil
120 if user.contest_finished?
129 if user.contest_finished?
121 flash[:notice] = 'Error: the contest you are participating is over.'
130 flash[:notice] = 'Error: the contest you are participating is over.'
122 redirect_to :back
131 redirect_to :back
123 return false
132 return false
124 end
133 end
125 return true
134 return true
126 end
135 end
127
136
128 end
137 end
@@ -1,279 +1,284
1 class ProblemsController < ApplicationController
1 class ProblemsController < ApplicationController
2
2
3 - before_filter :authenticate, :authorization
3 + before_action :authenticate, :authorization
4 + before_action :testcase_authorization, only: [:show_testcase]
4
5
5 in_place_edit_for :problem, :name
6 in_place_edit_for :problem, :name
6 in_place_edit_for :problem, :full_name
7 in_place_edit_for :problem, :full_name
7 in_place_edit_for :problem, :full_score
8 in_place_edit_for :problem, :full_score
8
9
9 def index
10 def index
10 @problems = Problem.order(date_added: :desc)
11 @problems = Problem.order(date_added: :desc)
11 end
12 end
12
13
13 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 verify :method => :post, :only => [ :create, :quick_create,
15 verify :method => :post, :only => [ :create, :quick_create,
15 :do_manage,
16 :do_manage,
16 :do_import,
17 :do_import,
17 ],
18 ],
18 :redirect_to => { :action => :index }
19 :redirect_to => { :action => :index }
19
20
20 def show
21 def show
21 @problem = Problem.find(params[:id])
22 @problem = Problem.find(params[:id])
22 end
23 end
23
24
24 def new
25 def new
25 @problem = Problem.new
26 @problem = Problem.new
26 @description = nil
27 @description = nil
27 end
28 end
28
29
29 def create
30 def create
30 @problem = Problem.new(params[:problem])
31 @problem = Problem.new(params[:problem])
31 @description = Description.new(params[:description])
32 @description = Description.new(params[:description])
32 if @description.body!=''
33 if @description.body!=''
33 if !@description.save
34 if !@description.save
34 render :action => new and return
35 render :action => new and return
35 end
36 end
36 else
37 else
37 @description = nil
38 @description = nil
38 end
39 end
39 @problem.description = @description
40 @problem.description = @description
40 if @problem.save
41 if @problem.save
41 flash[:notice] = 'Problem was successfully created.'
42 flash[:notice] = 'Problem was successfully created.'
42 redirect_to action: :index
43 redirect_to action: :index
43 else
44 else
44 render :action => 'new'
45 render :action => 'new'
45 end
46 end
46 end
47 end
47
48
48 def quick_create
49 def quick_create
49 @problem = Problem.new(params[:problem])
50 @problem = Problem.new(params[:problem])
50 @problem.full_name = @problem.name if @problem.full_name == ''
51 @problem.full_name = @problem.name if @problem.full_name == ''
51 @problem.full_score = 100
52 @problem.full_score = 100
52 @problem.available = false
53 @problem.available = false
53 @problem.test_allowed = true
54 @problem.test_allowed = true
54 @problem.output_only = false
55 @problem.output_only = false
55 @problem.date_added = Time.new
56 @problem.date_added = Time.new
56 if @problem.save
57 if @problem.save
57 flash[:notice] = 'Problem was successfully created.'
58 flash[:notice] = 'Problem was successfully created.'
58 redirect_to action: :index
59 redirect_to action: :index
59 else
60 else
60 flash[:notice] = 'Error saving problem'
61 flash[:notice] = 'Error saving problem'
61 redirect_to action: :index
62 redirect_to action: :index
62 end
63 end
63 end
64 end
64
65
65 def edit
66 def edit
66 @problem = Problem.find(params[:id])
67 @problem = Problem.find(params[:id])
67 @description = @problem.description
68 @description = @problem.description
68 end
69 end
69
70
70 def update
71 def update
71 @problem = Problem.find(params[:id])
72 @problem = Problem.find(params[:id])
72 @description = @problem.description
73 @description = @problem.description
73 if @description.nil? and params[:description][:body]!=''
74 if @description.nil? and params[:description][:body]!=''
74 @description = Description.new(params[:description])
75 @description = Description.new(params[:description])
75 if !@description.save
76 if !@description.save
76 flash[:notice] = 'Error saving description'
77 flash[:notice] = 'Error saving description'
77 render :action => 'edit' and return
78 render :action => 'edit' and return
78 end
79 end
79 @problem.description = @description
80 @problem.description = @description
80 elsif @description
81 elsif @description
81 if !@description.update_attributes(params[:description])
82 if !@description.update_attributes(params[:description])
82 flash[:notice] = 'Error saving description'
83 flash[:notice] = 'Error saving description'
83 render :action => 'edit' and return
84 render :action => 'edit' and return
84 end
85 end
85 end
86 end
86 if params[:file] and params[:file].content_type != 'application/pdf'
87 if params[:file] and params[:file].content_type != 'application/pdf'
87 flash[:notice] = 'Error: Uploaded file is not PDF'
88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 render :action => 'edit' and return
89 render :action => 'edit' and return
89 end
90 end
90 if @problem.update_attributes(params[:problem])
91 if @problem.update_attributes(params[:problem])
91 flash[:notice] = 'Problem was successfully updated.'
92 flash[:notice] = 'Problem was successfully updated.'
92 unless params[:file] == nil or params[:file] == ''
93 unless params[:file] == nil or params[:file] == ''
93 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 if not FileTest.exists? out_dirname
96 if not FileTest.exists? out_dirname
96 Dir.mkdir out_dirname
97 Dir.mkdir out_dirname
97 end
98 end
98
99
99 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 if FileTest.exists? out_filename
101 if FileTest.exists? out_filename
101 File.delete out_filename
102 File.delete out_filename
102 end
103 end
103
104
104 File.open(out_filename,"wb") do |file|
105 File.open(out_filename,"wb") do |file|
105 file.write(params[:file].read)
106 file.write(params[:file].read)
106 end
107 end
107 @problem.description_filename = "#{@problem.name}.pdf"
108 @problem.description_filename = "#{@problem.name}.pdf"
108 @problem.save
109 @problem.save
109 end
110 end
110 redirect_to :action => 'show', :id => @problem
111 redirect_to :action => 'show', :id => @problem
111 else
112 else
112 render :action => 'edit'
113 render :action => 'edit'
113 end
114 end
114 end
115 end
115
116
116 def destroy
117 def destroy
117 p = Problem.find(params[:id]).destroy
118 p = Problem.find(params[:id]).destroy
118 redirect_to action: :index
119 redirect_to action: :index
119 end
120 end
120
121
121 def toggle
122 def toggle
122 @problem = Problem.find(params[:id])
123 @problem = Problem.find(params[:id])
123 @problem.update_attributes(available: !(@problem.available) )
124 @problem.update_attributes(available: !(@problem.available) )
124 respond_to do |format|
125 respond_to do |format|
125 format.js { }
126 format.js { }
126 end
127 end
127 end
128 end
128
129
129 def toggle_test
130 def toggle_test
130 @problem = Problem.find(params[:id])
131 @problem = Problem.find(params[:id])
131 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 respond_to do |format|
133 respond_to do |format|
133 format.js { }
134 format.js { }
134 end
135 end
135 end
136 end
136
137
137 def turn_all_off
138 def turn_all_off
138 Problem.available.all.each do |problem|
139 Problem.available.all.each do |problem|
139 problem.available = false
140 problem.available = false
140 problem.save
141 problem.save
141 end
142 end
142 redirect_to action: :index
143 redirect_to action: :index
143 end
144 end
144
145
145 def turn_all_on
146 def turn_all_on
146 Problem.where.not(available: true).each do |problem|
147 Problem.where.not(available: true).each do |problem|
147 problem.available = true
148 problem.available = true
148 problem.save
149 problem.save
149 end
150 end
150 redirect_to action: :index
151 redirect_to action: :index
151 end
152 end
152
153
153 def stat
154 def stat
154 @problem = Problem.find(params[:id])
155 @problem = Problem.find(params[:id])
155 unless @problem.available or session[:admin]
156 unless @problem.available or session[:admin]
156 redirect_to :controller => 'main', :action => 'list'
157 redirect_to :controller => 'main', :action => 'list'
157 return
158 return
158 end
159 end
159 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
160 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
160
161
161 #stat summary
162 #stat summary
162 range =65
163 range =65
163 @histogram = { data: Array.new(range,0), summary: {} }
164 @histogram = { data: Array.new(range,0), summary: {} }
164 user = Hash.new(0)
165 user = Hash.new(0)
165 @submissions.find_each do |sub|
166 @submissions.find_each do |sub|
166 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
167 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
167 @histogram[:data][d.to_i] += 1 if d < range
168 @histogram[:data][d.to_i] += 1 if d < range
168 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
169 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
169 end
170 end
170 @histogram[:summary][:max] = [@histogram[:data].max,1].max
171 @histogram[:summary][:max] = [@histogram[:data].max,1].max
171
172
172 @summary = { attempt: user.count, solve: 0 }
173 @summary = { attempt: user.count, solve: 0 }
173 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
174 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
174 end
175 end
175
176
176 def manage
177 def manage
177 @problems = Problem.order(date_added: :desc)
178 @problems = Problem.order(date_added: :desc)
178 end
179 end
179
180
180 def do_manage
181 def do_manage
181 if params.has_key? 'change_date_added'
182 if params.has_key? 'change_date_added'
182 change_date_added
183 change_date_added
183 elsif params.has_key? 'add_to_contest'
184 elsif params.has_key? 'add_to_contest'
184 add_to_contest
185 add_to_contest
185 elsif params.has_key? 'enable_problem'
186 elsif params.has_key? 'enable_problem'
186 set_available(true)
187 set_available(true)
187 elsif params.has_key? 'disable_problem'
188 elsif params.has_key? 'disable_problem'
188 set_available(false)
189 set_available(false)
189 end
190 end
190 redirect_to :action => 'manage'
191 redirect_to :action => 'manage'
191 end
192 end
192
193
193 def import
194 def import
194 @allow_test_pair_import = allow_test_pair_import?
195 @allow_test_pair_import = allow_test_pair_import?
195 end
196 end
196
197
197 def do_import
198 def do_import
198 old_problem = Problem.find_by_name(params[:name])
199 old_problem = Problem.find_by_name(params[:name])
199 if !allow_test_pair_import? and params.has_key? :import_to_db
200 if !allow_test_pair_import? and params.has_key? :import_to_db
200 params.delete :import_to_db
201 params.delete :import_to_db
201 end
202 end
202 @problem, import_log = Problem.create_from_import_form_params(params,
203 @problem, import_log = Problem.create_from_import_form_params(params,
203 old_problem)
204 old_problem)
204
205
205 if !@problem.errors.empty?
206 if !@problem.errors.empty?
206 render :action => 'import' and return
207 render :action => 'import' and return
207 end
208 end
208
209
209 if old_problem!=nil
210 if old_problem!=nil
210 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
211 flash[:notice] = "The test data has been replaced for problem #{@problem.name}"
211 end
212 end
212 @log = import_log
213 @log = import_log
213 end
214 end
214
215
215 def remove_contest
216 def remove_contest
216 problem = Problem.find(params[:id])
217 problem = Problem.find(params[:id])
217 contest = Contest.find(params[:contest_id])
218 contest = Contest.find(params[:contest_id])
218 if problem!=nil and contest!=nil
219 if problem!=nil and contest!=nil
219 problem.contests.delete(contest)
220 problem.contests.delete(contest)
220 end
221 end
221 redirect_to :action => 'manage'
222 redirect_to :action => 'manage'
222 end
223 end
223
224
225 + def show_testcase
226 + @problem = Problem.includes(:testcases).find(params[:id])
227 + end
228 +
224 ##################################
229 ##################################
225 protected
230 protected
226
231
227 def allow_test_pair_import?
232 def allow_test_pair_import?
228 if defined? ALLOW_TEST_PAIR_IMPORT
233 if defined? ALLOW_TEST_PAIR_IMPORT
229 return ALLOW_TEST_PAIR_IMPORT
234 return ALLOW_TEST_PAIR_IMPORT
230 else
235 else
231 return false
236 return false
232 end
237 end
233 end
238 end
234
239
235 def change_date_added
240 def change_date_added
236 problems = get_problems_from_params
241 problems = get_problems_from_params
237 year = params[:date_added][:year].to_i
242 year = params[:date_added][:year].to_i
238 month = params[:date_added][:month].to_i
243 month = params[:date_added][:month].to_i
239 day = params[:date_added][:day].to_i
244 day = params[:date_added][:day].to_i
240 date = Date.new(year,month,day)
245 date = Date.new(year,month,day)
241 problems.each do |p|
246 problems.each do |p|
242 p.date_added = date
247 p.date_added = date
243 p.save
248 p.save
244 end
249 end
245 end
250 end
246
251
247 def add_to_contest
252 def add_to_contest
248 problems = get_problems_from_params
253 problems = get_problems_from_params
249 contest = Contest.find(params[:contest][:id])
254 contest = Contest.find(params[:contest][:id])
250 if contest!=nil and contest.enabled
255 if contest!=nil and contest.enabled
251 problems.each do |p|
256 problems.each do |p|
252 p.contests << contest
257 p.contests << contest
253 end
258 end
254 end
259 end
255 end
260 end
256
261
257 def set_available(avail)
262 def set_available(avail)
258 problems = get_problems_from_params
263 problems = get_problems_from_params
259 problems.each do |p|
264 problems.each do |p|
260 p.available = avail
265 p.available = avail
261 p.save
266 p.save
262 end
267 end
263 end
268 end
264
269
265 def get_problems_from_params
270 def get_problems_from_params
266 problems = []
271 problems = []
267 params.keys.each do |k|
272 params.keys.each do |k|
268 if k.index('prob-')==0
273 if k.index('prob-')==0
269 name, id, order = k.split('-')
274 name, id, order = k.split('-')
270 problems << Problem.find(id)
275 problems << Problem.find(id)
271 end
276 end
272 end
277 end
273 problems
278 problems
274 end
279 end
275
280
276 def get_problems_stat
281 def get_problems_stat
277 end
282 end
278
283
279 end
284 end
@@ -1,177 +1,183
1 require 'yaml'
1 require 'yaml'
2
2
3 #
3 #
4 # This class also contains various login of the system.
4 # This class also contains various login of the system.
5 #
5 #
6 class GraderConfiguration < ActiveRecord::Base
6 class GraderConfiguration < ActiveRecord::Base
7
7
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
10 MULTICONTESTS_KEY = 'system.multicontests'
10 MULTICONTESTS_KEY = 'system.multicontests'
11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
12 MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login'
12 MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login'
13 + VIEW_TESTCASE = 'right.view_testcase'
14 + SINGLE_USER_KEY = 'system.single_user_mode'
13
15
14 cattr_accessor :config_cache
16 cattr_accessor :config_cache
15 cattr_accessor :task_grading_info_cache
17 cattr_accessor :task_grading_info_cache
16 cattr_accessor :contest_time_str
18 cattr_accessor :contest_time_str
17 cattr_accessor :contest_time
19 cattr_accessor :contest_time
18
20
19 GraderConfiguration.config_cache = nil
21 GraderConfiguration.config_cache = nil
20 GraderConfiguration.task_grading_info_cache = nil
22 GraderConfiguration.task_grading_info_cache = nil
21
23
22 def self.config_cached?
24 def self.config_cached?
23 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
25 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
24 end
26 end
25
27
26 def self.get(key)
28 def self.get(key)
27 if GraderConfiguration.config_cached?
29 if GraderConfiguration.config_cached?
28 if GraderConfiguration.config_cache == nil
30 if GraderConfiguration.config_cache == nil
29 self.read_config
31 self.read_config
30 end
32 end
31 return GraderConfiguration.config_cache[key]
33 return GraderConfiguration.config_cache[key]
32 else
34 else
33 return GraderConfiguration.read_one_key(key)
35 return GraderConfiguration.read_one_key(key)
34 end
36 end
35 end
37 end
36
38
37 def self.[](key)
39 def self.[](key)
38 self.get(key)
40 self.get(key)
39 end
41 end
40
42
41 def self.reload
43 def self.reload
42 self.read_config
44 self.read_config
43 end
45 end
44
46
45 def self.clear
47 def self.clear
46 GraderConfiguration.config_cache = nil
48 GraderConfiguration.config_cache = nil
47 end
49 end
48
50
49 #
51 #
50 # View decision
52 # View decision
51 #
53 #
52 def self.show_submitbox_to?(user)
54 def self.show_submitbox_to?(user)
53 mode = get(SYSTEM_MODE_CONF_KEY)
55 mode = get(SYSTEM_MODE_CONF_KEY)
54 return false if mode=='analysis'
56 return false if mode=='analysis'
55 if (mode=='contest')
57 if (mode=='contest')
56 return false if (user.site!=nil) and
58 return false if (user.site!=nil) and
57 ((user.site.started!=true) or (user.site.finished?))
59 ((user.site.started!=true) or (user.site.finished?))
58 end
60 end
59 return true
61 return true
60 end
62 end
61
63
62 def self.show_tasks_to?(user)
64 def self.show_tasks_to?(user)
63 if time_limit_mode?
65 if time_limit_mode?
64 return false if not user.contest_started?
66 return false if not user.contest_started?
65 end
67 end
66 return true
68 return true
67 end
69 end
68
70
69 def self.show_grading_result
71 def self.show_grading_result
70 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
72 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
71 end
73 end
72
74
75 + def self.show_testcase
76 + return get(VIEW_TESTCASE)
77 + end
78 +
73 def self.allow_test_request(user)
79 def self.allow_test_request(user)
74 mode = get(SYSTEM_MODE_CONF_KEY)
80 mode = get(SYSTEM_MODE_CONF_KEY)
75 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
81 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
76 if (mode=='contest')
82 if (mode=='contest')
77 return false if ((user.site!=nil) and
83 return false if ((user.site!=nil) and
78 ((user.site.started!=true) or
84 ((user.site.started!=true) or
79 (early_timeout and (user.site.time_left < 30.minutes))))
85 (early_timeout and (user.site.time_left < 30.minutes))))
80 end
86 end
81 return false if mode=='analysis'
87 return false if mode=='analysis'
82 return true
88 return true
83 end
89 end
84
90
85 def self.task_grading_info
91 def self.task_grading_info
86 if GraderConfiguration.task_grading_info_cache==nil
92 if GraderConfiguration.task_grading_info_cache==nil
87 read_grading_info
93 read_grading_info
88 end
94 end
89 return GraderConfiguration.task_grading_info_cache
95 return GraderConfiguration.task_grading_info_cache
90 end
96 end
91
97
92 def self.standard_mode?
98 def self.standard_mode?
93 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
99 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
94 end
100 end
95
101
96 def self.contest_mode?
102 def self.contest_mode?
97 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
103 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
98 end
104 end
99
105
100 def self.indv_contest_mode?
106 def self.indv_contest_mode?
101 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
107 return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
102 end
108 end
103
109
104 def self.multicontests?
110 def self.multicontests?
105 return get(MULTICONTESTS_KEY) == true
111 return get(MULTICONTESTS_KEY) == true
106 end
112 end
107
113
108 def self.time_limit_mode?
114 def self.time_limit_mode?
109 mode = get(SYSTEM_MODE_CONF_KEY)
115 mode = get(SYSTEM_MODE_CONF_KEY)
110 return ((mode == 'contest') or (mode == 'indv-contest'))
116 return ((mode == 'contest') or (mode == 'indv-contest'))
111 end
117 end
112
118
113 def self.analysis_mode?
119 def self.analysis_mode?
114 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
120 return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
115 end
121 end
116
122
117 def self.contest_time_limit
123 def self.contest_time_limit
118 contest_time_str = GraderConfiguration[CONTEST_TIME_LIMIT_KEY]
124 contest_time_str = GraderConfiguration[CONTEST_TIME_LIMIT_KEY]
119
125
120 if not defined? GraderConfiguration.contest_time_str
126 if not defined? GraderConfiguration.contest_time_str
121 GraderConfiguration.contest_time_str = nil
127 GraderConfiguration.contest_time_str = nil
122 end
128 end
123
129
124 if GraderConfiguration.contest_time_str != contest_time_str
130 if GraderConfiguration.contest_time_str != contest_time_str
125 GraderConfiguration.contest_time_str = contest_time_str
131 GraderConfiguration.contest_time_str = contest_time_str
126 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
132 if tmatch = /(\d+):(\d+)/.match(contest_time_str)
127 h = tmatch[1].to_i
133 h = tmatch[1].to_i
128 m = tmatch[2].to_i
134 m = tmatch[2].to_i
129
135
130 GraderConfiguration.contest_time = h.hour + m.minute
136 GraderConfiguration.contest_time = h.hour + m.minute
131 else
137 else
132 GraderConfiguration.contest_time = nil
138 GraderConfiguration.contest_time = nil
133 end
139 end
134 end
140 end
135 return GraderConfiguration.contest_time
141 return GraderConfiguration.contest_time
136 end
142 end
137
143
138 protected
144 protected
139
145
140 def self.convert_type(val,type)
146 def self.convert_type(val,type)
141 case type
147 case type
142 when 'string'
148 when 'string'
143 return val
149 return val
144
150
145 when 'integer'
151 when 'integer'
146 return val.to_i
152 return val.to_i
147
153
148 when 'boolean'
154 when 'boolean'
149 return (val=='true')
155 return (val=='true')
150 end
156 end
151 end
157 end
152
158
153 def self.read_config
159 def self.read_config
154 GraderConfiguration.config_cache = {}
160 GraderConfiguration.config_cache = {}
155 GraderConfiguration.all.each do |conf|
161 GraderConfiguration.all.each do |conf|
156 key = conf.key
162 key = conf.key
157 val = conf.value
163 val = conf.value
158 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
164 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
159 end
165 end
160 end
166 end
161
167
162 def self.read_one_key(key)
168 def self.read_one_key(key)
163 conf = GraderConfiguration.find_by_key(key)
169 conf = GraderConfiguration.find_by_key(key)
164 if conf
170 if conf
165 return GraderConfiguration.convert_type(conf.value,conf.value_type)
171 return GraderConfiguration.convert_type(conf.value,conf.value_type)
166 else
172 else
167 return nil
173 return nil
168 end
174 end
169 end
175 end
170
176
171 def self.read_grading_info
177 def self.read_grading_info
172 f = File.open(TASK_GRADING_INFO_FILENAME)
178 f = File.open(TASK_GRADING_INFO_FILENAME)
173 GraderConfiguration.task_grading_info_cache = YAML.load(f)
179 GraderConfiguration.task_grading_info_cache = YAML.load(f)
174 f.close
180 f.close
175 end
181 end
176
182
177 end
183 end
@@ -1,39 +1,39
1 %b= GraderConfiguration['ui.front.welcome_message']
1 %b= GraderConfiguration['ui.front.welcome_message']
2 %br/
2 %br/
3
3
4 - if !@hidelogin
4 - if !@hidelogin
5 =t 'login.message'
5 =t 'login.message'
6 %br/
6 %br/
7 %br/
7 %br/
8
8
9 - if flash[:notice]
9 - if flash[:notice]
10 %hr/
10 %hr/
11 %b= flash[:notice]
11 %b= flash[:notice]
12 %hr/
12 %hr/
13
13
14 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
14 %div{ :style => "border: solid 1px gray; padding: 4px; background: #eeeeff;"}
15 - = form_tag :controller => 'login', :action => 'login' do
15 + = form_tag login_login_path do
16 %table
16 %table
17 %tr
17 %tr
18 %td{:align => "right"}
18 %td{:align => "right"}
19 ="#{t 'login_label'}:"
19 ="#{t 'login_label'}:"
20 %td= text_field_tag 'login'
20 %td= text_field_tag 'login'
21 %tr
21 %tr
22 %td{:align => "right"}
22 %td{:align => "right"}
23 ="#{t 'password_label'}:"
23 ="#{t 'password_label'}:"
24 %td= password_field_tag
24 %td= password_field_tag
25 - unless GraderConfiguration['right.bypass_agreement']
25 - unless GraderConfiguration['right.bypass_agreement']
26 %tr
26 %tr
27 %td{:align => "right"}= check_box_tag 'accept_agree'
27 %td{:align => "right"}= check_box_tag 'accept_agree'
28 %td ยอมรับข้อตกลงการใช้งาน
28 %td ยอมรับข้อตกลงการใช้งาน
29
29
30 = submit_tag t('login.login_submit')
30 = submit_tag t('login.login_submit')
31 %br/
31 %br/
32
32
33 - if GraderConfiguration['system.online_registration']
33 - if GraderConfiguration['system.online_registration']
34 =t 'login.participation'
34 =t 'login.participation'
35 %b
35 %b
36 = "#{t 'login.please'} "
36 = "#{t 'login.please'} "
37 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
37 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
38 %br/
38 %br/
39 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
39 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
@@ -1,27 +1,29
1
1
2 - if submission.nil?
2 - if submission.nil?
3 = "-"
3 = "-"
4 - else
4 - else
5 - unless submission.graded_at
5 - unless submission.graded_at
6 = t 'main.submitted_at'
6 = t 'main.submitted_at'
7 = format_short_time(submission.submitted_at.localtime)
7 = format_short_time(submission.submitted_at.localtime)
8 - else
8 - else
9 %strong= t 'main.graded_at'
9 %strong= t 'main.graded_at'
10 = "#{format_short_time(submission.graded_at.localtime)} "
10 = "#{format_short_time(submission.graded_at.localtime)} "
11 %br
11 %br
12 - if GraderConfiguration['ui.show_score']
12 - if GraderConfiguration['ui.show_score']
13 %strong=t 'main.score'
13 %strong=t 'main.score'
14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
15 = " ["
15 = " ["
16 %tt
16 %tt
17 = submission.grader_comment
17 = submission.grader_comment
18 = "]"
18 = "]"
19 %br
19 %br
20 %strong View:
20 %strong View:
21 - if GraderConfiguration.show_grading_result
21 - if GraderConfiguration.show_grading_result
22 = link_to '[detailed result]', :action => 'result', :id => submission.id
22 = link_to '[detailed result]', :action => 'result', :id => submission.id
23 /= link_to "#{t 'main.cmp_msg'}", {:action => 'compiler_msg', :id => submission.id}, {popup: true,class: 'btn btn-xs btn-info'}
23 /= link_to "#{t 'main.cmp_msg'}", {:action => 'compiler_msg', :id => submission.id}, {popup: true,class: 'btn btn-xs btn-info'}
24 = link_to "#{t 'main.cmp_msg'}", compiler_msg_submission_path(submission.id), {popup: true,remote: true,class: 'btn btn-xs btn-info'}
24 = link_to "#{t 'main.cmp_msg'}", compiler_msg_submission_path(submission.id), {popup: true,remote: true,class: 'btn btn-xs btn-info'}
25 = link_to "#{t 'main.src_link'}",{:action => 'source', :id => submission.id}, class: 'btn btn-xs btn-info'
25 = link_to "#{t 'main.src_link'}",{:action => 'source', :id => submission.id}, class: 'btn btn-xs btn-info'
26 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
26 = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
27 + - if GraderConfiguration.show_testcase
28 + = link_to "testcases", show_testcase_problem_path(problem_id), class: 'btn btn-xs btn-info'
27
29
@@ -1,52 +1,63
1 - content_for :head do
1 - content_for :head do
2 = javascript_include_tag "announcement_refresh"
2 = javascript_include_tag "announcement_refresh"
3
3
4 = user_title_bar(@user)
4 = user_title_bar(@user)
5
5
6 - if (GraderConfiguration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
6 - if (GraderConfiguration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
7 %p=t 'main.start_soon'
7 %p=t 'main.start_soon'
8
8
9 .row
9 .row
10 .col-md-7
10 .col-md-7
11 - if GraderConfiguration.show_submitbox_to?(@user)
11 - if GraderConfiguration.show_submitbox_to?(@user)
12 .panel.panel-primary
12 .panel.panel-primary
13 .panel-heading
13 .panel-heading
14 Submission
14 Submission
15 .panel-body
15 .panel-body
16 = render :partial => 'submission_box'
16 = render :partial => 'submission_box'
17 - if GraderConfiguration.show_tasks_to?(@user)
17 - if GraderConfiguration.show_tasks_to?(@user)
18 - if not GraderConfiguration.multicontests?
18 - if not GraderConfiguration.multicontests?
19 %table.table.table-striped.table-condensed
19 %table.table.table-striped.table-condensed
20 %thead
20 %thead
21 %tr
21 %tr
22 %th Task name
22 %th Task name
23 %th Full name
23 %th Full name
24 %th # of sub(s)
24 %th # of sub(s)
25 %th Results
25 %th Results
26 %th
26 %th
27 %tbody
27 %tbody
28 = render :partial => 'problem', :collection => @problems
28 = render :partial => 'problem', :collection => @problems
29 - else
29 - else
30 - @contest_problems.each do |cp|
30 - @contest_problems.each do |cp|
31 - if cp[:problems].length > 0
31 - if cp[:problems].length > 0
32 %h2{:class =>'contest-title'}
32 %h2{:class =>'contest-title'}
33 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
33 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
34 %table.info
34 %table.info
35 %tr.info-head
35 %tr.info-head
36 %th Task name
36 %th Task name
37 %th Full name
37 %th Full name
38 %th # of sub(s)
38 %th # of sub(s)
39 %th Results
39 %th Results
40 %th
40 %th
41 = render :partial => 'problem', :collection => cp[:problems]
41 = render :partial => 'problem', :collection => cp[:problems]
42 .col-md-5
42 .col-md-5
43 .panel.panel-info
43 .panel.panel-info
44 .panel-heading
44 .panel-heading
45 Announcement
45 Announcement
46 %ul.list-group
46 %ul.list-group
47 = render :partial => 'announcement', :collection => @announcements
47 = render :partial => 'announcement', :collection => @announcements
48
48
49 %script{:type => 'text/javascript'}
49 %script{:type => 'text/javascript'}
50 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
50 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
51 Announcement.registerRefreshEventTimer();
51 Announcement.registerRefreshEventTimer();
52
52
53 + .modal.fade#compiler{tabindex: -1,role: 'dialog'}
54 + .modal-dialog.modal-lg{role:'document'}
55 + .modal-content
56 + .modal-header
57 + %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
58 + %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
59 + %h4 Compiler message
60 + .modal-body
61 + %pre#compiler_msg
62 + .modal-footer
63 + %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -1,3 +1,4
1 - :javascript
1 + :plain
2 - $("#compiler_msg").html("#{j @submissionhcompiler_msg}")
2 + $("#compiler_msg").html("#{j @submission.compiler_message}");
3 -
3 + $("#compiler").modal();
4 +
@@ -1,2 +1,2
1 - :javascript
1 + :plain
2 $("#latest_status").html("#{j render({partial: 'submission_short', locals: {submission: @submission, problem_name: @problem.name}})}")
2 $("#latest_status").html("#{j render({partial: 'submission_short', locals: {submission: @submission, problem_name: @problem.name}})}")
@@ -1,77 +1,88
1 CafeGrader::Application.routes.draw do
1 CafeGrader::Application.routes.draw do
2 get "sources/direct_edit"
2 get "sources/direct_edit"
3
3
4 root :to => 'main#login'
4 root :to => 'main#login'
5
5
6 + #logins
7 + get 'login/login', to: 'login#login'
8 +
6 resources :contests
9 resources :contests
7
10
8 resources :sites
11 resources :sites
9
12
10 resources :announcements do
13 resources :announcements do
11 member do
14 member do
12 get 'toggle','toggle_front'
15 get 'toggle','toggle_front'
13 end
16 end
14 end
17 end
15
18
16 resources :problems do
19 resources :problems do
17 member do
20 member do
18 get 'toggle'
21 get 'toggle'
19 get 'toggle_test'
22 get 'toggle_test'
20 get 'stat'
23 get 'stat'
24 + get 'show_testcase'
21 end
25 end
22 collection do
26 collection do
23 get 'turn_all_off'
27 get 'turn_all_off'
24 get 'turn_all_on'
28 get 'turn_all_on'
25 get 'import'
29 get 'import'
26 get 'manage'
30 get 'manage'
27 end
31 end
32 +
33 + resources :testcases, only: [] do
34 + member do
35 + get 'download_input'
36 + get 'download_sol'
37 + end
38 + end
28 end
39 end
29
40
30 resources :grader_configuration, controller: 'configurations'
41 resources :grader_configuration, controller: 'configurations'
31
42
32 resources :users do
43 resources :users do
33 member do
44 member do
34 get 'toggle_activate', 'toggle_enable'
45 get 'toggle_activate', 'toggle_enable'
35 get 'stat'
46 get 'stat'
36 end
47 end
37 end
48 end
38
49
39 resources :submissions do
50 resources :submissions do
40 member do
51 member do
41 get 'download'
52 get 'download'
42 get 'compiler_msg'
53 get 'compiler_msg'
43 end
54 end
44 collection do
55 collection do
45 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
56 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
46 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
57 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
47 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
58 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
48 end
59 end
49 end
60 end
50
61
51 get 'tasks/view/:file.:ext' => 'tasks#view'
62 get 'tasks/view/:file.:ext' => 'tasks#view'
52 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
63 get 'tasks/download/:id/:file.:ext' => 'tasks#download'
53 get 'heartbeat/:id/edit' => 'heartbeat#edit'
64 get 'heartbeat/:id/edit' => 'heartbeat#edit'
54
65
55 #main
66 #main
56 get "main/list"
67 get "main/list"
57 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
68 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
58
69
59 #report
70 #report
60 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
71 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
61 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
72 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
62 get "report/login"
73 get "report/login"
63 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
74 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
64 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
75 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
65
76
66 #grader
77 #grader
67 get 'graders/list', to: 'graders#list', as: 'grader_list'
78 get 'graders/list', to: 'graders#list', as: 'grader_list'
68
79
69
80
70 get 'heartbeat/:id/edit' => 'heartbeat#edit'
81 get 'heartbeat/:id/edit' => 'heartbeat#edit'
71
82
72 # See how all your routes lay out with "rake routes"
83 # See how all your routes lay out with "rake routes"
73
84
74 # This is a legacy wild controller route that's not recommended for RESTful applications.
85 # This is a legacy wild controller route that's not recommended for RESTful applications.
75 # Note: This route will make all actions in every controller accessible via GET requests.
86 # Note: This route will make all actions in every controller accessible via GET requests.
76 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
87 match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
77 end
88 end
@@ -1,280 +1,280
1 # encoding: UTF-8
1 # encoding: UTF-8
2 # This file is auto-generated from the current state of the database. Instead
2 # This file is auto-generated from the current state of the database. Instead
3 # of editing this file, please use the migrations feature of Active Record to
3 # of editing this file, please use the migrations feature of Active Record to
4 # incrementally modify your database, and then regenerate this schema definition.
4 # incrementally modify your database, and then regenerate this schema definition.
5 #
5 #
6 # Note that this schema.rb definition is the authoritative source for your
6 # Note that this schema.rb definition is the authoritative source for your
7 # database schema. If you need to create the application database on another
7 # database schema. If you need to create the application database on another
8 # system, you should be using db:schema:load, not running all the migrations
8 # system, you should be using db:schema:load, not running all the migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 #
11 #
12 # It's strongly recommended that you check this file into your version control system.
12 # It's strongly recommended that you check this file into your version control system.
13
13
14 ActiveRecord::Schema.define(version: 20161031063337) do
14 ActiveRecord::Schema.define(version: 20161031063337) do
15
15
16 create_table "announcements", force: :cascade do |t|
16 create_table "announcements", force: :cascade do |t|
17 - t.string "author"
17 + t.string "author", limit: 255
18 - t.text "body"
18 + t.text "body", limit: 65535
19 t.boolean "published"
19 t.boolean "published"
20 - t.datetime "created_at", null: false
20 + t.datetime "created_at", null: false
21 - t.datetime "updated_at", null: false
21 + t.datetime "updated_at", null: false
22 - t.boolean "frontpage", default: false
22 + t.boolean "frontpage", default: false
23 - t.boolean "contest_only", default: false
23 + t.boolean "contest_only", default: false
24 - t.string "title"
24 + t.string "title", limit: 255
25 - t.string "notes"
25 + t.string "notes", limit: 255
26 end
26 end
27
27
28 create_table "contests", force: :cascade do |t|
28 create_table "contests", force: :cascade do |t|
29 - t.string "title"
29 + t.string "title", limit: 255
30 t.boolean "enabled"
30 t.boolean "enabled"
31 - t.datetime "created_at", null: false
31 + t.datetime "created_at", null: false
32 - t.datetime "updated_at", null: false
32 + t.datetime "updated_at", null: false
33 - t.string "name"
33 + t.string "name", limit: 255
34 end
34 end
35
35
36 create_table "contests_problems", id: false, force: :cascade do |t|
36 create_table "contests_problems", id: false, force: :cascade do |t|
37 - t.integer "contest_id"
37 + t.integer "contest_id", limit: 4
38 - t.integer "problem_id"
38 + t.integer "problem_id", limit: 4
39 end
39 end
40
40
41 create_table "contests_users", id: false, force: :cascade do |t|
41 create_table "contests_users", id: false, force: :cascade do |t|
42 - t.integer "contest_id"
42 + t.integer "contest_id", limit: 4
43 - t.integer "user_id"
43 + t.integer "user_id", limit: 4
44 end
44 end
45
45
46 create_table "countries", force: :cascade do |t|
46 create_table "countries", force: :cascade do |t|
47 - t.string "name"
47 + t.string "name", limit: 255
48 - t.datetime "created_at", null: false
48 + t.datetime "created_at", null: false
49 - t.datetime "updated_at", null: false
49 + t.datetime "updated_at", null: false
50 end
50 end
51
51
52 create_table "descriptions", force: :cascade do |t|
52 create_table "descriptions", force: :cascade do |t|
53 - t.text "body"
53 + t.text "body", limit: 65535
54 t.boolean "markdowned"
54 t.boolean "markdowned"
55 - t.datetime "created_at", null: false
55 + t.datetime "created_at", null: false
56 - t.datetime "updated_at", null: false
56 + t.datetime "updated_at", null: false
57 end
57 end
58
58
59 create_table "grader_configurations", force: :cascade do |t|
59 create_table "grader_configurations", force: :cascade do |t|
60 - t.string "key"
60 + t.string "key", limit: 255
61 - t.string "value_type"
61 + t.string "value_type", limit: 255
62 - t.string "value"
62 + t.string "value", limit: 255
63 - t.datetime "created_at", null: false
63 + t.datetime "created_at", null: false
64 - t.datetime "updated_at", null: false
64 + t.datetime "updated_at", null: false
65 - t.text "description"
65 + t.text "description", limit: 65535
66 end
66 end
67
67
68 create_table "grader_processes", force: :cascade do |t|
68 create_table "grader_processes", force: :cascade do |t|
69 - t.string "host"
69 + t.string "host", limit: 255
70 - t.integer "pid"
70 + t.integer "pid", limit: 4
71 - t.string "mode"
71 + t.string "mode", limit: 255
72 t.boolean "active"
72 t.boolean "active"
73 - t.datetime "created_at", null: false
73 + t.datetime "created_at", null: false
74 - t.datetime "updated_at", null: false
74 + t.datetime "updated_at", null: false
75 - t.integer "task_id"
75 + t.integer "task_id", limit: 4
76 - t.string "task_type"
76 + t.string "task_type", limit: 255
77 t.boolean "terminated"
77 t.boolean "terminated"
78 end
78 end
79
79
80 - add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid"
80 + add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree
81
81
82 create_table "heart_beats", force: :cascade do |t|
82 create_table "heart_beats", force: :cascade do |t|
83 - t.integer "user_id"
83 + t.integer "user_id", limit: 4
84 - t.string "ip_address"
84 + t.string "ip_address", limit: 255
85 - t.datetime "created_at", null: false
85 + t.datetime "created_at", null: false
86 - t.datetime "updated_at", null: false
86 + t.datetime "updated_at", null: false
87 - t.string "status"
87 + t.string "status", limit: 255
88 end
88 end
89
89
90 - add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at"
90 + add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree
91
91
92 create_table "languages", force: :cascade do |t|
92 create_table "languages", force: :cascade do |t|
93 t.string "name", limit: 10
93 t.string "name", limit: 10
94 - t.string "pretty_name"
94 + t.string "pretty_name", limit: 255
95 t.string "ext", limit: 10
95 t.string "ext", limit: 10
96 - t.string "common_ext"
96 + t.string "common_ext", limit: 255
97 end
97 end
98
98
99 create_table "logins", force: :cascade do |t|
99 create_table "logins", force: :cascade do |t|
100 - t.integer "user_id"
100 + t.integer "user_id", limit: 4
101 - t.string "ip_address"
101 + t.string "ip_address", limit: 255
102 - t.datetime "created_at", null: false
102 + t.datetime "created_at", null: false
103 - t.datetime "updated_at", null: false
103 + t.datetime "updated_at", null: false
104 end
104 end
105
105
106 create_table "messages", force: :cascade do |t|
106 create_table "messages", force: :cascade do |t|
107 - t.integer "sender_id"
107 + t.integer "sender_id", limit: 4
108 - t.integer "receiver_id"
108 + t.integer "receiver_id", limit: 4
109 - t.integer "replying_message_id"
109 + t.integer "replying_message_id", limit: 4
110 - t.text "body"
110 + t.text "body", limit: 65535
111 t.boolean "replied"
111 t.boolean "replied"
112 - t.datetime "created_at", null: false
112 + t.datetime "created_at", null: false
113 - t.datetime "updated_at", null: false
113 + t.datetime "updated_at", null: false
114 end
114 end
115
115
116 create_table "problems", force: :cascade do |t|
116 create_table "problems", force: :cascade do |t|
117 t.string "name", limit: 30
117 t.string "name", limit: 30
118 - t.string "full_name"
118 + t.string "full_name", limit: 255
119 - t.integer "full_score"
119 + t.integer "full_score", limit: 4
120 t.date "date_added"
120 t.date "date_added"
121 t.boolean "available"
121 t.boolean "available"
122 - t.string "url"
122 + t.string "url", limit: 255
123 - t.integer "description_id"
123 + t.integer "description_id", limit: 4
124 t.boolean "test_allowed"
124 t.boolean "test_allowed"
125 t.boolean "output_only"
125 t.boolean "output_only"
126 - t.string "description_filename"
126 + t.string "description_filename", limit: 255
127 end
127 end
128
128
129 create_table "rights", force: :cascade do |t|
129 create_table "rights", force: :cascade do |t|
130 - t.string "name"
130 + t.string "name", limit: 255
131 - t.string "controller"
131 + t.string "controller", limit: 255
132 - t.string "action"
132 + t.string "action", limit: 255
133 end
133 end
134
134
135 create_table "rights_roles", id: false, force: :cascade do |t|
135 create_table "rights_roles", id: false, force: :cascade do |t|
136 - t.integer "right_id"
136 + t.integer "right_id", limit: 4
137 - t.integer "role_id"
137 + t.integer "role_id", limit: 4
138 end
138 end
139
139
140 - add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id"
140 + add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
141
141
142 create_table "roles", force: :cascade do |t|
142 create_table "roles", force: :cascade do |t|
143 - t.string "name"
143 + t.string "name", limit: 255
144 end
144 end
145
145
146 create_table "roles_users", id: false, force: :cascade do |t|
146 create_table "roles_users", id: false, force: :cascade do |t|
147 - t.integer "role_id"
147 + t.integer "role_id", limit: 4
148 - t.integer "user_id"
148 + t.integer "user_id", limit: 4
149 end
149 end
150
150
151 - add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id"
151 + add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
152
152
153 create_table "sessions", force: :cascade do |t|
153 create_table "sessions", force: :cascade do |t|
154 - t.string "session_id"
154 + t.string "session_id", limit: 255
155 - t.text "data"
155 + t.text "data", limit: 65535
156 t.datetime "updated_at"
156 t.datetime "updated_at"
157 end
157 end
158
158
159 - add_index "sessions", ["session_id"], name: "index_sessions_on_session_id"
159 + add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
160 - add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at"
160 + add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
161
161
162 create_table "sites", force: :cascade do |t|
162 create_table "sites", force: :cascade do |t|
163 - t.string "name"
163 + t.string "name", limit: 255
164 t.boolean "started"
164 t.boolean "started"
165 t.datetime "start_time"
165 t.datetime "start_time"
166 - t.datetime "created_at", null: false
166 + t.datetime "created_at", null: false
167 - t.datetime "updated_at", null: false
167 + t.datetime "updated_at", null: false
168 - t.integer "country_id"
168 + t.integer "country_id", limit: 4
169 - t.string "password"
169 + t.string "password", limit: 255
170 end
170 end
171
171
172 create_table "submission_view_logs", force: :cascade do |t|
172 create_table "submission_view_logs", force: :cascade do |t|
173 - t.integer "user_id"
173 + t.integer "user_id", limit: 4
174 - t.integer "submission_id"
174 + t.integer "submission_id", limit: 4
175 - t.datetime "created_at", null: false
175 + t.datetime "created_at", null: false
176 - t.datetime "updated_at", null: false
176 + t.datetime "updated_at", null: false
177 end
177 end
178
178
179 create_table "submissions", force: :cascade do |t|
179 create_table "submissions", force: :cascade do |t|
180 - t.integer "user_id"
180 + t.integer "user_id", limit: 4
181 - t.integer "problem_id"
181 + t.integer "problem_id", limit: 4
182 - t.integer "language_id"
182 + t.integer "language_id", limit: 4
183 - t.text "source"
183 + t.text "source", limit: 65535
184 - t.binary "binary"
184 + t.binary "binary", limit: 65535
185 t.datetime "submitted_at"
185 t.datetime "submitted_at"
186 t.datetime "compiled_at"
186 t.datetime "compiled_at"
187 - t.text "compiler_message"
187 + t.text "compiler_message", limit: 65535
188 t.datetime "graded_at"
188 t.datetime "graded_at"
189 - t.integer "points"
189 + t.integer "points", limit: 4
190 - t.text "grader_comment"
190 + t.text "grader_comment", limit: 65535
191 - t.integer "number"
191 + t.integer "number", limit: 4
192 - t.string "source_filename"
192 + t.string "source_filename", limit: 255
193 - t.float "max_runtime"
193 + t.float "max_runtime", limit: 24
194 - t.integer "peak_memory"
194 + t.integer "peak_memory", limit: 4
195 - t.integer "effective_code_length"
195 + t.integer "effective_code_length", limit: 4
196 - t.string "ip_address"
196 + t.string "ip_address", limit: 255
197 end
197 end
198
198
199 - add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true
199 + add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
200 - add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id"
200 + add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
201
201
202 create_table "tasks", force: :cascade do |t|
202 create_table "tasks", force: :cascade do |t|
203 - t.integer "submission_id"
203 + t.integer "submission_id", limit: 4
204 t.datetime "created_at"
204 t.datetime "created_at"
205 - t.integer "status"
205 + t.integer "status", limit: 4
206 t.datetime "updated_at"
206 t.datetime "updated_at"
207 end
207 end
208
208
209 create_table "test_pairs", force: :cascade do |t|
209 create_table "test_pairs", force: :cascade do |t|
210 - t.integer "problem_id"
210 + t.integer "problem_id", limit: 4
211 t.text "input", limit: 16777215
211 t.text "input", limit: 16777215
212 t.text "solution", limit: 16777215
212 t.text "solution", limit: 16777215
213 t.datetime "created_at", null: false
213 t.datetime "created_at", null: false
214 t.datetime "updated_at", null: false
214 t.datetime "updated_at", null: false
215 end
215 end
216
216
217 create_table "test_requests", force: :cascade do |t|
217 create_table "test_requests", force: :cascade do |t|
218 - t.integer "user_id"
218 + t.integer "user_id", limit: 4
219 - t.integer "problem_id"
219 + t.integer "problem_id", limit: 4
220 - t.integer "submission_id"
220 + t.integer "submission_id", limit: 4
221 - t.string "input_file_name"
221 + t.string "input_file_name", limit: 255
222 - t.string "output_file_name"
222 + t.string "output_file_name", limit: 255
223 - t.string "running_stat"
223 + t.string "running_stat", limit: 255
224 - t.integer "status"
224 + t.integer "status", limit: 4
225 - t.datetime "updated_at", null: false
225 + t.datetime "updated_at", null: false
226 t.datetime "submitted_at"
226 t.datetime "submitted_at"
227 t.datetime "compiled_at"
227 t.datetime "compiled_at"
228 - t.text "compiler_message"
228 + t.text "compiler_message", limit: 65535
229 t.datetime "graded_at"
229 t.datetime "graded_at"
230 - t.string "grader_comment"
230 + t.string "grader_comment", limit: 255
231 - t.datetime "created_at", null: false
231 + t.datetime "created_at", null: false
232 - t.float "running_time"
232 + t.float "running_time", limit: 24
233 - t.string "exit_status"
233 + t.string "exit_status", limit: 255
234 - t.integer "memory_usage"
234 + t.integer "memory_usage", limit: 4
235 end
235 end
236
236
237 - add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id"
237 + add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
238
238
239 create_table "testcases", force: :cascade do |t|
239 create_table "testcases", force: :cascade do |t|
240 - t.integer "problem_id"
240 + t.integer "problem_id", limit: 4
241 - t.integer "num"
241 + t.integer "num", limit: 4
242 - t.integer "group"
242 + t.integer "group", limit: 4
243 - t.integer "score"
243 + t.integer "score", limit: 4
244 - t.text "input"
244 + t.text "input", limit: 65535
245 - t.text "sol"
245 + t.text "sol", limit: 65535
246 - t.datetime "created_at", null: false
246 + t.datetime "created_at"
247 - t.datetime "updated_at", null: false
247 + t.datetime "updated_at"
248 end
248 end
249
249
250 - add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id"
250 + add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
251
251
252 create_table "user_contest_stats", force: :cascade do |t|
252 create_table "user_contest_stats", force: :cascade do |t|
253 - t.integer "user_id"
253 + t.integer "user_id", limit: 4
254 t.datetime "started_at"
254 t.datetime "started_at"
255 - t.datetime "created_at", null: false
255 + t.datetime "created_at", null: false
256 - t.datetime "updated_at", null: false
256 + t.datetime "updated_at", null: false
257 t.boolean "forced_logout"
257 t.boolean "forced_logout"
258 end
258 end
259
259
260 create_table "users", force: :cascade do |t|
260 create_table "users", force: :cascade do |t|
261 t.string "login", limit: 50
261 t.string "login", limit: 50
262 - t.string "full_name"
262 + t.string "full_name", limit: 255
263 - t.string "hashed_password"
263 + t.string "hashed_password", limit: 255
264 t.string "salt", limit: 5
264 t.string "salt", limit: 5
265 - t.string "alias"
265 + t.string "alias", limit: 255
266 - t.string "email"
266 + t.string "email", limit: 255
267 - t.integer "site_id"
267 + t.integer "site_id", limit: 4
268 - t.integer "country_id"
268 + t.integer "country_id", limit: 4
269 - t.boolean "activated", default: false
269 + t.boolean "activated", default: false
270 t.datetime "created_at"
270 t.datetime "created_at"
271 t.datetime "updated_at"
271 t.datetime "updated_at"
272 - t.boolean "enabled", default: true
272 + t.boolean "enabled", default: true
273 - t.string "remark"
273 + t.string "remark", limit: 255
274 - t.string "last_ip"
274 + t.string "last_ip", limit: 255
275 - t.string "section"
275 + t.string "section", limit: 255
276 end
276 end
277
277
278 - add_index "users", ["login"], name: "index_users_on_login", unique: true
278 + add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
279
279
280 end
280 end
@@ -1,245 +1,251
1 CONFIGURATIONS =
1 CONFIGURATIONS =
2 [
2 [
3 {
3 {
4 :key => 'system.single_user_mode',
4 :key => 'system.single_user_mode',
5 :value_type => 'boolean',
5 :value_type => 'boolean',
6 :default_value => 'false',
6 :default_value => 'false',
7 :description => 'Only admins can log in to the system when running under single user mode.'
7 :description => 'Only admins can log in to the system when running under single user mode.'
8 },
8 },
9
9
10 {
10 {
11 :key => 'ui.front.title',
11 :key => 'ui.front.title',
12 :value_type => 'string',
12 :value_type => 'string',
13 :default_value => 'Grader'
13 :default_value => 'Grader'
14 },
14 },
15
15
16 {
16 {
17 :key => 'ui.front.welcome_message',
17 :key => 'ui.front.welcome_message',
18 :value_type => 'string',
18 :value_type => 'string',
19 :default_value => 'Welcome!'
19 :default_value => 'Welcome!'
20 },
20 },
21
21
22 {
22 {
23 :key => 'ui.show_score',
23 :key => 'ui.show_score',
24 :value_type => 'boolean',
24 :value_type => 'boolean',
25 :default_value => 'true'
25 :default_value => 'true'
26 },
26 },
27
27
28 {
28 {
29 :key => 'contest.time_limit',
29 :key => 'contest.time_limit',
30 :value_type => 'string',
30 :value_type => 'string',
31 :default_value => 'unlimited',
31 :default_value => 'unlimited',
32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
32 :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits. This config is CACHED. Restart the server before the change can take effect.'
33 },
33 },
34
34
35 {
35 {
36 :key => 'system.mode',
36 :key => 'system.mode',
37 :value_type => 'string',
37 :value_type => 'string',
38 :default_value => 'standard',
38 :default_value => 'standard',
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 },
40 },
41
41
42 {
42 {
43 :key => 'contest.name',
43 :key => 'contest.name',
44 :value_type => 'string',
44 :value_type => 'string',
45 :default_value => 'Grader',
45 :default_value => 'Grader',
46 :description => 'This name will be shown on the user header bar.'
46 :description => 'This name will be shown on the user header bar.'
47 },
47 },
48
48
49 {
49 {
50 :key => 'contest.multisites',
50 :key => 'contest.multisites',
51 :value_type => 'boolean',
51 :value_type => 'boolean',
52 :default_value => 'false',
52 :default_value => 'false',
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
53 :description => 'If the server is in contest mode and this option is true, on the log in of the admin a menu for site selections is shown.'
54 },
54 },
55
55
56 #---------------------------- right --------------------------------
56 #---------------------------- right --------------------------------
57 {
57 {
58 :key => 'right.user_hall_of_fame',
58 :key => 'right.user_hall_of_fame',
59 :value_type => 'boolean',
59 :value_type => 'boolean',
60 :default_value => 'false',
60 :default_value => 'false',
61 :description => 'If true, any user can access hall of fame page.'
61 :description => 'If true, any user can access hall of fame page.'
62 },
62 },
63
63
64 {
64 {
65 :key => 'right.multiple_ip_login',
65 :key => 'right.multiple_ip_login',
66 :value_type => 'boolean',
66 :value_type => 'boolean',
67 :default_value => 'true',
67 :default_value => 'true',
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
69 },
69 },
70
70
71 {
71 {
72 :key => 'right.user_view_submission',
72 :key => 'right.user_view_submission',
73 :value_type => 'boolean',
73 :value_type => 'boolean',
74 :default_value => 'false',
74 :default_value => 'false',
75 :description => 'If true, any user can view submissions of every one.'
75 :description => 'If true, any user can view submissions of every one.'
76 },
76 },
77
77
78 {
78 {
79 :key => 'right.bypass_agreement',
79 :key => 'right.bypass_agreement',
80 :value_type => 'boolean',
80 :value_type => 'boolean',
81 :default_value => 'true',
81 :default_value => 'true',
82 :description => 'When false, a user must accept usage agreement before login'
82 :description => 'When false, a user must accept usage agreement before login'
83 },
83 },
84
84
85 {
85 {
86 :key => 'right.heartbeat_response',
86 :key => 'right.heartbeat_response',
87 :value_type => 'string',
87 :value_type => 'string',
88 :default_value => 'OK',
88 :default_value => 'OK',
89 :description => 'Heart beat response text'
89 :description => 'Heart beat response text'
90 },
90 },
91
91
92 + {
93 + :key => 'right.view_testcase',
94 + :value_type => 'boolean',
95 + :default_value => 'false',
96 + :description => 'When true, any user can view/download test data'
97 + },
92 # If Configuration['system.online_registration'] is true, the
98 # If Configuration['system.online_registration'] is true, the
93 # system allows online registration, and will use these
99 # system allows online registration, and will use these
94 # information for sending confirmation emails.
100 # information for sending confirmation emails.
95 {
101 {
96 :key => 'system.online_registration.smtp',
102 :key => 'system.online_registration.smtp',
97 :value_type => 'string',
103 :value_type => 'string',
98 :default_value => 'smtp.somehost.com'
104 :default_value => 'smtp.somehost.com'
99 },
105 },
100
106
101 {
107 {
102 :key => 'system.online_registration.from',
108 :key => 'system.online_registration.from',
103 :value_type => 'string',
109 :value_type => 'string',
104 :default_value => 'your.email@address'
110 :default_value => 'your.email@address'
105 },
111 },
106
112
107 {
113 {
108 :key => 'system.admin_email',
114 :key => 'system.admin_email',
109 :value_type => 'string',
115 :value_type => 'string',
110 :default_value => 'admin@admin.email'
116 :default_value => 'admin@admin.email'
111 },
117 },
112
118
113 {
119 {
114 :key => 'system.user_setting_enabled',
120 :key => 'system.user_setting_enabled',
115 :value_type => 'boolean',
121 :value_type => 'boolean',
116 :default_value => 'true',
122 :default_value => 'true',
117 :description => 'If this option is true, users can change their settings'
123 :description => 'If this option is true, users can change their settings'
118 },
124 },
119
125
120 {
126 {
121 :key => 'system.user_setting_enabled',
127 :key => 'system.user_setting_enabled',
122 :value_type => 'boolean',
128 :value_type => 'boolean',
123 :default_value => 'true',
129 :default_value => 'true',
124 :description => 'If this option is true, users can change their settings'
130 :description => 'If this option is true, users can change their settings'
125 },
131 },
126
132
127 # If Configuration['contest.test_request.early_timeout'] is true
133 # If Configuration['contest.test_request.early_timeout'] is true
128 # the user will not be able to use test request at 30 minutes
134 # the user will not be able to use test request at 30 minutes
129 # before the contest ends.
135 # before the contest ends.
130 {
136 {
131 :key => 'contest.test_request.early_timeout',
137 :key => 'contest.test_request.early_timeout',
132 :value_type => 'boolean',
138 :value_type => 'boolean',
133 :default_value => 'false'
139 :default_value => 'false'
134 },
140 },
135
141
136 {
142 {
137 :key => 'system.multicontests',
143 :key => 'system.multicontests',
138 :value_type => 'boolean',
144 :value_type => 'boolean',
139 :default_value => 'false'
145 :default_value => 'false'
140 },
146 },
141
147
142 {
148 {
143 :key => 'contest.confirm_indv_contest_start',
149 :key => 'contest.confirm_indv_contest_start',
144 :value_type => 'boolean',
150 :value_type => 'boolean',
145 :default_value => 'false'
151 :default_value => 'false'
146 },
152 },
147
153
148 {
154 {
149 :key => 'contest.default_contest_name',
155 :key => 'contest.default_contest_name',
150 :value_type => 'string',
156 :value_type => 'string',
151 :default_value => 'none',
157 :default_value => 'none',
152 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
158 :description => "New user will be assigned to this contest automatically, if it exists. Set to 'none' if there is no default contest."
153 }
159 }
154
160
155 ]
161 ]
156
162
157
163
158 def create_configuration_key(key,
164 def create_configuration_key(key,
159 value_type,
165 value_type,
160 default_value,
166 default_value,
161 description='')
167 description='')
162 conf = (GraderConfiguration.find_by_key(key) ||
168 conf = (GraderConfiguration.find_by_key(key) ||
163 GraderConfiguration.new(:key => key,
169 GraderConfiguration.new(:key => key,
164 :value_type => value_type,
170 :value_type => value_type,
165 :value => default_value))
171 :value => default_value))
166 conf.description = description
172 conf.description = description
167 conf.save
173 conf.save
168 end
174 end
169
175
170 def seed_config
176 def seed_config
171 CONFIGURATIONS.each do |conf|
177 CONFIGURATIONS.each do |conf|
172 if conf.has_key? :description
178 if conf.has_key? :description
173 desc = conf[:description]
179 desc = conf[:description]
174 else
180 else
175 desc = ''
181 desc = ''
176 end
182 end
177 create_configuration_key(conf[:key],
183 create_configuration_key(conf[:key],
178 conf[:value_type],
184 conf[:value_type],
179 conf[:default_value],
185 conf[:default_value],
180 desc)
186 desc)
181 end
187 end
182 end
188 end
183
189
184 def seed_roles
190 def seed_roles
185 return if Role.find_by_name('admin')
191 return if Role.find_by_name('admin')
186
192
187 role = Role.create(:name => 'admin')
193 role = Role.create(:name => 'admin')
188 user_admin_right = Right.create(:name => 'user_admin',
194 user_admin_right = Right.create(:name => 'user_admin',
189 :controller => 'user_admin',
195 :controller => 'user_admin',
190 :action => 'all')
196 :action => 'all')
191 problem_admin_right = Right.create(:name=> 'problem_admin',
197 problem_admin_right = Right.create(:name=> 'problem_admin',
192 :controller => 'problems',
198 :controller => 'problems',
193 :action => 'all')
199 :action => 'all')
194
200
195 graders_right = Right.create(:name => 'graders_admin',
201 graders_right = Right.create(:name => 'graders_admin',
196 :controller => 'graders',
202 :controller => 'graders',
197 :action => 'all')
203 :action => 'all')
198
204
199 role.rights << user_admin_right;
205 role.rights << user_admin_right;
200 role.rights << problem_admin_right;
206 role.rights << problem_admin_right;
201 role.rights << graders_right;
207 role.rights << graders_right;
202 role.save
208 role.save
203 end
209 end
204
210
205 def seed_root
211 def seed_root
206 return if User.find_by_login('root')
212 return if User.find_by_login('root')
207
213
208 root = User.new(:login => 'root',
214 root = User.new(:login => 'root',
209 :full_name => 'Administrator',
215 :full_name => 'Administrator',
210 :alias => 'root')
216 :alias => 'root')
211 root.password = 'ioionrails';
217 root.password = 'ioionrails';
212
218
213 class << root
219 class << root
214 public :encrypt_new_password
220 public :encrypt_new_password
215 def valid?(context=nil)
221 def valid?(context=nil)
216 true
222 true
217 end
223 end
218 end
224 end
219
225
220 root.encrypt_new_password
226 root.encrypt_new_password
221
227
222 root.roles << Role.find_by_name('admin')
228 root.roles << Role.find_by_name('admin')
223
229
224 root.activated = true
230 root.activated = true
225 root.save
231 root.save
226 end
232 end
227
233
228 def seed_users_and_roles
234 def seed_users_and_roles
229 seed_roles
235 seed_roles
230 seed_root
236 seed_root
231 end
237 end
232
238
233 def seed_more_languages
239 def seed_more_languages
234 Language.delete_all
240 Language.delete_all
235 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
241 Language.create( name: 'c', pretty_name: 'C', ext: 'c', common_ext: 'c' )
236 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
242 Language.create( name: 'cpp', pretty_name: 'C++', ext: 'cpp', common_ext: 'cpp,cc' )
237 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
243 Language.create( name: 'pas', pretty_name: 'Pascal', ext: 'pas', common_ext: 'pas' )
238 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
244 Language.create( name: 'ruby', pretty_name: 'Ruby', ext: 'rb', common_ext: 'rb' )
239 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
245 Language.create( name: 'python', pretty_name: 'Python', ext: 'py', common_ext: 'py' )
240 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
246 Language.create( name: 'java', pretty_name: 'Java', ext: 'java', common_ext: 'java' )
241 end
247 end
242
248
243 seed_config
249 seed_config
244 seed_users_and_roles
250 seed_users_and_roles
245 seed_more_languages
251 seed_more_languages
@@ -1,58 +1,73
1 module GraderScript
1 module GraderScript
2
2
3 def self.grader_control_enabled?
3 def self.grader_control_enabled?
4 if defined? GRADER_ROOT_DIR
4 if defined? GRADER_ROOT_DIR
5 GRADER_ROOT_DIR != ''
5 GRADER_ROOT_DIR != ''
6 else
6 else
7 false
7 false
8 end
8 end
9 end
9 end
10
10
11 def self.raw_dir
11 def self.raw_dir
12 File.join GRADER_ROOT_DIR, "raw"
12 File.join GRADER_ROOT_DIR, "raw"
13 end
13 end
14
14
15 def self.call_grader(params)
15 def self.call_grader(params)
16 if GraderScript.grader_control_enabled?
16 if GraderScript.grader_control_enabled?
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
17 cmd = File.join(GRADER_ROOT_DIR, "scripts/grader") + " " + params
18 system(cmd)
18 system(cmd)
19 end
19 end
20 end
20 end
21
21
22 def self.stop_grader(pid)
22 def self.stop_grader(pid)
23 GraderScript.call_grader "stop #{pid}"
23 GraderScript.call_grader "stop #{pid}"
24 end
24 end
25
25
26 def self.stop_graders(pids)
26 def self.stop_graders(pids)
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
27 pid_str = (pids.map { |process| process.pid.to_s }).join ' '
28 GraderScript.call_grader "stop #{pid_str}"
28 GraderScript.call_grader "stop #{pid_str}"
29 end
29 end
30
30
31 def self.start_grader(env)
31 def self.start_grader(env)
32 GraderScript.call_grader "#{env} queue --err-log &"
32 GraderScript.call_grader "#{env} queue --err-log &"
33 GraderScript.call_grader "#{env} test_request -err-log &"
33 GraderScript.call_grader "#{env} test_request -err-log &"
34 end
34 end
35
35
36 def self.call_import_problem(problem_name,
36 def self.call_import_problem(problem_name,
37 problem_dir,
37 problem_dir,
38 time_limit=1,
38 time_limit=1,
39 memory_limit=32,
39 memory_limit=32,
40 checker_name='text')
40 checker_name='text')
41 if GraderScript.grader_control_enabled?
41 if GraderScript.grader_control_enabled?
42 cur_dir = `pwd`.chomp
42 cur_dir = `pwd`.chomp
43 Dir.chdir(GRADER_ROOT_DIR)
43 Dir.chdir(GRADER_ROOT_DIR)
44
44
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 " -t #{time_limit} -m #{memory_limit}"
47 " -t #{time_limit} -m #{memory_limit}"
48
48
49 output = `#{cmd}`
49 output = `#{cmd}`
50
50
51 Dir.chdir(cur_dir)
51 Dir.chdir(cur_dir)
52 -
52 +
53 return "import CMD: #{cmd}\n" + output
53 return "import CMD: #{cmd}\n" + output
54 end
54 end
55 return ''
55 return ''
56 end
56 end
57
57
58 + def self.call_import_testcase(problem_name)
59 + if GraderScript.grader_control_enabled?
60 + cur_dir = `pwd`.chomp
61 + Dir.chdir(GRADER_ROOT_DIR)
62 +
63 + script_name = File.join(GRADER_ROOT_DIR, "scripts/load_testcase")
64 + cmd = "#{script_name} #{problem_name}"
65 +
66 + output = `#{cmd}`
67 +
68 + Dir.chdir(cur_dir)
69 + return "Testcase import result:\n" + output
70 + end
71 + end
72 +
58 end
73 end
@@ -1,190 +1,193
1 require 'tmpdir'
1 require 'tmpdir'
2
2
3 class TestdataImporter
3 class TestdataImporter
4
4
5 attr :log_msg
5 attr :log_msg
6
6
7 def initialize(problem)
7 def initialize(problem)
8 @problem = problem
8 @problem = problem
9 end
9 end
10
10
11 def import_from_file(tempfile,
11 def import_from_file(tempfile,
12 time_limit,
12 time_limit,
13 memory_limit,
13 memory_limit,
14 checker_name='text',
14 checker_name='text',
15 import_to_db=false)
15 import_to_db=false)
16
16
17 dirname = extract(tempfile)
17 dirname = extract(tempfile)
18 return false if not dirname
18 return false if not dirname
19 if not import_to_db
19 if not import_to_db
20 @log_msg = GraderScript.call_import_problem(@problem.name,
20 @log_msg = GraderScript.call_import_problem(@problem.name,
21 dirname,
21 dirname,
22 time_limit,
22 time_limit,
23 memory_limit,
23 memory_limit,
24 checker_name)
24 checker_name)
25 else
25 else
26 # Import test data to test pairs.
26 # Import test data to test pairs.
27
27
28 @problem.test_pairs.clear
28 @problem.test_pairs.clear
29 if import_test_pairs(dirname)
29 if import_test_pairs(dirname)
30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 else
32 else
33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 end
34 end
35 end
35 end
36
36
37 @log_msg << import_problem_description(dirname)
37 @log_msg << import_problem_description(dirname)
38 @log_msg << import_problem_pdf(dirname)
38 @log_msg << import_problem_pdf(dirname)
39 @log_msg << import_full_score(dirname)
39 @log_msg << import_full_score(dirname)
40
40
41 + #import test data
42 + @log_msg << GraderScript.call_import_testcase(@problem.name)
43 +
41 return true
44 return true
42 end
45 end
43
46
44 protected
47 protected
45
48
46 def self.long_ext(filename)
49 def self.long_ext(filename)
47 i = filename.index('.')
50 i = filename.index('.')
48 len = filename.length
51 len = filename.length
49 return filename.slice(i..len)
52 return filename.slice(i..len)
50 end
53 end
51
54
52 def extract(tempfile)
55 def extract(tempfile)
53 testdata_filename = save_testdata_file(tempfile)
56 testdata_filename = save_testdata_file(tempfile)
54 ext = TestdataImporter.long_ext(tempfile.original_filename)
57 ext = TestdataImporter.long_ext(tempfile.original_filename)
55
58
56 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
59 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
57 if File.exists? extract_dir
60 if File.exists? extract_dir
58 backup_count = 0
61 backup_count = 0
59 begin
62 begin
60 backup_count += 1
63 backup_count += 1
61 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
64 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
62 end while File.exists? backup_dirname
65 end while File.exists? backup_dirname
63 File.rename(extract_dir, backup_dirname)
66 File.rename(extract_dir, backup_dirname)
64 end
67 end
65 Dir.mkdir extract_dir
68 Dir.mkdir extract_dir
66
69
67 if ext=='.tar.gz' or ext=='.tgz'
70 if ext=='.tar.gz' or ext=='.tgz'
68 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
71 cmd = "tar -zxvf #{testdata_filename} -C #{extract_dir}"
69 elsif ext=='.tar'
72 elsif ext=='.tar'
70 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
73 cmd = "tar -xvf #{testdata_filename} -C #{extract_dir}"
71 elsif ext=='.zip'
74 elsif ext=='.zip'
72 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
75 cmd = "unzip -o #{testdata_filename} -d #{extract_dir}"
73 else
76 else
74 return nil
77 return nil
75 end
78 end
76
79
77 system(cmd)
80 system(cmd)
78
81
79 files = Dir["#{extract_dir}/**/*1*.in"]
82 files = Dir["#{extract_dir}/**/*1*.in"]
80 return nil if files.length==0
83 return nil if files.length==0
81
84
82 File.delete(testdata_filename)
85 File.delete(testdata_filename)
83
86
84 return File.dirname(files[0])
87 return File.dirname(files[0])
85 end
88 end
86
89
87 def save_testdata_file(tempfile)
90 def save_testdata_file(tempfile)
88 ext = TestdataImporter.long_ext(tempfile.original_filename)
91 ext = TestdataImporter.long_ext(tempfile.original_filename)
89 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
92 testdata_filename = File.join(Dir.tmpdir,"#{@problem.name}#{ext}")
90
93
91 return nil if tempfile==""
94 return nil if tempfile==""
92
95
93 if tempfile.instance_of?(Tempfile)
96 if tempfile.instance_of?(Tempfile)
94 tempfile.close
97 tempfile.close
95 FileUtils.move(tempfile.path,testdata_filename)
98 FileUtils.move(tempfile.path,testdata_filename)
96 else
99 else
97 File.open(testdata_filename, "wb") do |f|
100 File.open(testdata_filename, "wb") do |f|
98 f.write(tempfile.read)
101 f.write(tempfile.read)
99 end
102 end
100 end
103 end
101
104
102 return testdata_filename
105 return testdata_filename
103 end
106 end
104
107
105 def import_test_pairs(dirname)
108 def import_test_pairs(dirname)
106 test_num = 1
109 test_num = 1
107 while FileTest.exists? "#{dirname}/#{test_num}.in"
110 while FileTest.exists? "#{dirname}/#{test_num}.in"
108 in_filename = "#{dirname}/#{test_num}.in"
111 in_filename = "#{dirname}/#{test_num}.in"
109 sol_filename = "#{dirname}/#{test_num}.sol"
112 sol_filename = "#{dirname}/#{test_num}.sol"
110
113
111 break if not FileTest.exists? sol_filename
114 break if not FileTest.exists? sol_filename
112
115
113 test_pair = TestPair.new(:input => open(in_filename).read,
116 test_pair = TestPair.new(:input => open(in_filename).read,
114 :solution => open(sol_filename).read,
117 :solution => open(sol_filename).read,
115 :problem => @problem)
118 :problem => @problem)
116 break if not test_pair.save
119 break if not test_pair.save
117
120
118 test_num += 1
121 test_num += 1
119 end
122 end
120 return test_num > 1
123 return test_num > 1
121 end
124 end
122
125
123 def import_problem_description(dirname)
126 def import_problem_description(dirname)
124 html_files = Dir["#{dirname}/*.html"]
127 html_files = Dir["#{dirname}/*.html"]
125 markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
128 markdown_files = Dir["#{dirname}/*.md"] + Dir["#{dirname}/*.markdown"]
126 if (html_files.length != 0) or (markdown_files.length != 0)
129 if (html_files.length != 0) or (markdown_files.length != 0)
127 description = @problem.description || Description.new
130 description = @problem.description || Description.new
128
131
129 if html_files.length != 0
132 if html_files.length != 0
130 filename = html_files[0]
133 filename = html_files[0]
131 description.markdowned = false
134 description.markdowned = false
132 else
135 else
133 filename = markdown_files[0]
136 filename = markdown_files[0]
134 description.markdowned = true
137 description.markdowned = true
135 end
138 end
136
139
137 description.body = open(filename).read
140 description.body = open(filename).read
138 description.save
141 description.save
139 @problem.description = description
142 @problem.description = description
140 @problem.save
143 @problem.save
141 return "\nProblem description imported from #{filename}."
144 return "\nProblem description imported from #{filename}."
142 else
145 else
143 return ''
146 return ''
144 end
147 end
145 end
148 end
146
149
147 def import_problem_pdf(dirname)
150 def import_problem_pdf(dirname)
148 pdf_files = Dir["#{dirname}/*.pdf"]
151 pdf_files = Dir["#{dirname}/*.pdf"]
149 puts "CHECKING... #{dirname}"
152 puts "CHECKING... #{dirname}"
150 if pdf_files.length != 0
153 if pdf_files.length != 0
151 puts "HAS PDF FILE"
154 puts "HAS PDF FILE"
152 filename = pdf_files[0]
155 filename = pdf_files[0]
153
156
154 @problem.save if not @problem.id
157 @problem.save if not @problem.id
155 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
158 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
156 if not FileTest.exists? out_dirname
159 if not FileTest.exists? out_dirname
157 Dir.mkdir out_dirname
160 Dir.mkdir out_dirname
158 end
161 end
159
162
160 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
163 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
161
164
162 if FileTest.exists? out_filename
165 if FileTest.exists? out_filename
163 File.delete out_filename
166 File.delete out_filename
164 end
167 end
165
168
166 File.rename(filename, out_filename)
169 File.rename(filename, out_filename)
167 @problem.description_filename = "#{@problem.name}.pdf"
170 @problem.description_filename = "#{@problem.name}.pdf"
168 @problem.save
171 @problem.save
169 return "\nProblem pdf imported from #{filename}."
172 return "\nProblem pdf imported from #{filename}."
170 else
173 else
171 return ""
174 return ""
172 end
175 end
173 end
176 end
174
177
175 #just set the full score to the total number of test case
178 #just set the full score to the total number of test case
176 #it is not perfect but works on most normal use case
179 #it is not perfect but works on most normal use case
177 def import_full_score(dirname)
180 def import_full_score(dirname)
178 num = 0
181 num = 0
179 loop do
182 loop do
180 num += 1
183 num += 1
181 in_file = Dir["#{dirname}/#{num}*.in"]
184 in_file = Dir["#{dirname}/#{num}*.in"]
182 break if in_file.length == 0
185 break if in_file.length == 0
183 end
186 end
184 full_score = (num - 1) * 10
187 full_score = (num - 1) * 10
185 @problem.full_score = full_score
188 @problem.full_score = full_score
186 @problem.save
189 @problem.save
187 return "\nFull score is set to #{full_score}."
190 return "\nFull score is set to #{full_score}."
188 end
191 end
189
192
190 end
193 end
@@ -1,5 +1,36
1 - # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
1 + Language_1:
2 - one:
2 + name: c
3 - id: 1
3 + pretty_name: C
4 - two:
4 + ext: c
5 - id: 2
5 + common_ext: c
6 +
7 + Language_2:
8 + name: cpp
9 + pretty_name: C++
10 + ext: cpp
11 + common_ext: cpp,cc
12 +
13 + Language_3:
14 + name: pas
15 + pretty_name: Pascal
16 + ext: pas
17 + common_ext: pas
18 +
19 + Language_4:
20 + name: ruby
21 + pretty_name: Ruby
22 + ext: rb
23 + common_ext: rb
24 +
25 + Language_5:
26 + name: python
27 + pretty_name: Python
28 + ext: py
29 + common_ext: py
30 +
31 + Language_6:
32 + name: java
33 + pretty_name: Java
34 + ext: java
35 + common_ext: java
36 +
@@ -1,38 +1,38
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2
2
3 <%
3 <%
4 User.public_class_method :encrypt
4 User.public_class_method :encrypt
5
5
6 salt = "abc"
6 salt = "abc"
7 %>
7 %>
8
8
9 john:
9 john:
10 login: john
10 login: john
11 full_name: john
11 full_name: john
12 hashed_password: <%= User.encrypt("hello",salt) %>
12 hashed_password: <%= User.encrypt("hello",salt) %>
13 salt: <%= salt %>
13 salt: <%= salt %>
14 activated: true
14 activated: true
15
15
16 - mary:
16 + admin:
17 - login: mary
17 + login: admin
18 - full_name: mary
18 + full_name: admin
19 - hashed_password: <%= User.encrypt("goodbye",salt) %>
19 + hashed_password: <%= User.encrypt("admin",salt) %>
20 salt: <%= salt %>
20 salt: <%= salt %>
21 roles: admin
21 roles: admin
22 activated: true
22 activated: true
23
23
24 james:
24 james:
25 login: james
25 login: james
26 full_name: James
26 full_name: James
27 hashed_password: <%= User.encrypt("morning",salt) %>
27 hashed_password: <%= User.encrypt("morning",salt) %>
28 salt: <%= salt %>
28 salt: <%= salt %>
29 contests: contest_a
29 contests: contest_a
30 activated: true
30 activated: true
31
31
32 jack:
32 jack:
33 login: jack
33 login: jack
34 full_name: Jack
34 full_name: Jack
35 hashed_password: <%= User.encrypt("morning",salt) %>
35 hashed_password: <%= User.encrypt("morning",salt) %>
36 salt: <%= salt %>
36 salt: <%= salt %>
37 contests: contest_a, contest_b
37 contests: contest_a, contest_b
38 activated: true
38 activated: true
@@ -1,13 +1,40
1 require 'test_helper'
1 require 'test_helper'
2
2
3 class LoginTest < ActionDispatch::IntegrationTest
3 class LoginTest < ActionDispatch::IntegrationTest
4 # test "the truth" do
4 # test "the truth" do
5 # assert true
5 # assert true
6 # end
6 # end
7
7
8 - test "login with valid information" do
8 + test "login with invalid information" do
9 + get root_path
10 + assert_response :success
11 + post login_login_path, login: "root", password: "hahaha"
12 + assert_redirected_to root_path
13 + end
14 +
15 + test "normal user login" do
9 get root_path
16 get root_path
10 assert_response :success
17 assert_response :success
18 + post login_login_path, {login: "john", password: "hello" }
19 + assert_redirected_to main_list_path
20 + end
11
21
22 + test "normal user login in single_user mode" do
23 + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true')
24 + GraderConfiguration.reload
25 + get root_path
26 + assert_response :success
27 + post login_login_path, {login: "john", password: "hello" }
28 + follow_redirect!
29 + assert_redirected_to root_path
30 + end
31 +
32 + test "root login in in single_user mode" do
33 + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true')
34 + GraderConfiguration.reload
35 + get root_path
36 + assert_response :success
37 + post login_login_path, {login: "admin", password: "admin" }
38 + assert_redirected_to main_list_path
12 end
39 end
13 end
40 end
@@ -1,16 +1,20
1 ENV["RAILS_ENV"] = "test"
1 ENV["RAILS_ENV"] = "test"
2 require File.expand_path('../../config/environment', __FILE__)
2 require File.expand_path('../../config/environment', __FILE__)
3 require 'rails/test_help'
3 require 'rails/test_help'
4
4
5 + #reporter
6 + require "minitest/reporters"
7 + Minitest::Reporters.use!
8 +
5 class ActiveSupport::TestCase
9 class ActiveSupport::TestCase
6 # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
10 # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7 #
11 #
8 # Note: You'll currently still have to declare fixtures explicitly in integration tests
12 # Note: You'll currently still have to declare fixtures explicitly in integration tests
9 # -- they do not yet inherit this setting
13 # -- they do not yet inherit this setting
10 fixtures :all
14 fixtures :all
11
15
12 # Add more helper methods to be used by all tests here...
16 # Add more helper methods to be used by all tests here...
13
17
14 self.use_transactional_fixtures = true
18 self.use_transactional_fixtures = true
15 self.use_instantiated_fixtures = false
19 self.use_instantiated_fixtures = false
16 end
20 end
You need to be logged in to leave comments. Login now