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

r661:50e8e6077bb9 - - 146 files changed: 1465 inserted, 2374 deleted

@@ -0,0 +1,32
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 + def show_problem
14 + @problem = Problem.includes(:testcases).find(params[:problem_id])
15 + unless @current_user.admin? or @problem.view_testcase
16 + flash[:error] = 'You cannot view the testcase of this problem'
17 + redirect_to :controller => 'main', :action => 'list'
18 + end
19 + end
20 +
21 +
22 + private
23 + # Use callbacks to share common setup or constraints between actions.
24 + def set_testcase
25 + @testcase = Testcase.find(params[:id])
26 + end
27 +
28 + # Only allow a trusted parameter "white list" through.
29 + def testcase_params
30 + params[:testcase]
31 + end
32 + end
@@ -0,0 +1,2
1 + module TestcasesHelper
2 + end
@@ -0,0 +1,2
1 + = render partial: 'toggle_button',
2 + locals: {button_id: "#problem-view-testcase-#{@problem.id}",button_on: @problem.view_testcase?}
@@ -0,0 +1,4
1 + :plain
2 + $("#compiler_msg").html("#{j @submission.compiler_message}");
3 + $("#compiler").modal();
4 +
@@ -0,0 +1,2
1 + :plain
2 + $("body").prepend("<div class=\"alert alert-info\"> Submission #{@submission.id}'s task status has been changed to \"#{@task.status_str}\". It will be re-judged soon. </div>")
@@ -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_testcase_path(tc),class: 'btn btn-info btn-sm'
18 + .col-md-6
19 + %h3 Output
20 + = link_to "Download",download_sol_testcase_path(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,77
1 + %h1 Bulk Manage User
2 +
3 + = form_tag bulk_manage_user_admin_path
4 + .row
5 + .col-md-6
6 + .panel.panel-primary
7 + .panel-title.panel-heading
8 + Filter User
9 + .panel-body
10 + Filtering users whose login match the following MySQL regex
11 + .form-group
12 + = label_tag "regex", 'Regex Pattern'
13 + = text_field_tag "regex", params[:regex], class: 'form-control'
14 + %p
15 + Example
16 + %ul
17 + %li
18 + %code root
19 + matches every user whose login contains "root"
20 + %li
21 + %code ^56
22 + matches every user whose login starts with "56"
23 + %li
24 + %code 21$
25 + matches every user whose login ends with "21"
26 + .col-md-6
27 + .panel.panel-primary
28 + .panel-title.panel-heading
29 + Action
30 + .panel-body
31 + .row.form-group
32 + .col-md-6
33 + %label.checkbox-inline
34 + = check_box_tag "enabled", true, params[:enabled]
35 + Change "Enabled" to
36 + .col-md-3
37 + %label.radio-inline
38 + = radio_button_tag "enable", 1, params[:enable] == '1', id: 'enable-yes'
39 + Yes
40 + .col-md-3
41 + %label.radio-inline
42 + = radio_button_tag "enable", 0, params[:enable] == '0', id: 'enable-no'
43 + No
44 + .row.form-group
45 + .col-md-6
46 + %label.checkbox-inline
47 + = check_box_tag "gen_password", true, params[:gen_password]
48 + Generate new random password
49 +
50 + .row
51 + .col-md-12
52 + = submit_tag "Preview Result", class: 'btn btn-default'
53 + - if @users
54 + .row
55 + .col-md-4
56 + - if @action
57 + %h2 Confirmation
58 + - if @action[:set_enable]
59 + .alert.alert-info The following users will be set #{(@action[:enabled] ? 'enable' : 'disable')}.
60 + - if @action[:gen_password]
61 + .alert.alert-info The password of the following users will be randomly generated.
62 + .row
63 + .col-md-4
64 + = submit_tag "Perform", class: 'btn btn-primary'
65 + .row
66 + .col-md-12
67 + The pattern matches #{@users.count} following users.
68 + %br
69 + - @users.each do |user|
70 + = user.login
71 + = ' '
72 + = user.full_name
73 + = ' '
74 + = "(#{user.remark})" if user.remark
75 + %br
76 +
77 +
@@ -0,0 +1,8
1 + development:
2 + secret_key_base: '444f426d08add8e2d7cbd76e2057e521e06091231eb4d5472af6ba5654ea1124ce6a636f549be6827ce09561c314181226ad840d44e4677e1077942ee0dc82bd'
3 +
4 + test:
5 + secret_key_base: 'd52f411b06a79cc9f56d92e10d27e670cf0f0c3357e7caf9018ec23091b5c452ea9266c03a5c9e37b72c358702d4d460e957f90dcc553c9fc73a98adb520e781'
6 +
7 + production:
8 + secret_key_base: '7f85485d3d652fc6336dfe3cd98917d9bd7a323b32096bf7635d26b98ccd0480816cc2d12b5c10805cecf7d8fb322104e2bda71eb60dd871c5c537e56a063038'
@@ -0,0 +1,16
1 + class AddConfigViewTest < ActiveRecord::Migration
2 + def up
3 + GraderConfiguration.create key: 'right.view_testcase', value_type: 'boolean', value:'true', description:'When true, any user can view/download test data'
4 + #uglily and dirtily and shamelessly check other config and inifialize
5 + GraderConfiguration.where(key: 'right.user_hall_of_fame').first_or_create(value_type: 'boolean', value: 'false',
6 + description: 'If true, any user can access hall of fame page.')
7 + GraderConfiguration.where(key: 'right.multiple_ip_login').first_or_create(value_type: 'boolean', value: 'false',
8 + description: 'When change from true to false, a user can login from the first IP they logged into afterward.')
9 + GraderConfiguration.where(key: 'right.user_view_submission').first_or_create(value_type: 'boolean', value: 'false',
10 + description: 'If true, any user can view submissions of every one.')
11 + end
12 +
13 + def down
14 + GraderConfiguration.where(key: 'right.view_testcase').destroy_all;
15 + end
16 + end
@@ -0,0 +1,6
1 + class ChangeTestcaseSize < ActiveRecord::Migration
2 + def change
3 + change_column :testcases, :input, :text, :limit => 4294967295
4 + change_column :testcases, :sol, :text, :limit => 4294967295
5 + end
6 + end
@@ -0,0 +1,5
1 + class AddViewTestcaseToProblem < ActiveRecord::Migration
2 + def change
3 + add_column :problems, :view_testcase, :bool
4 + end
5 + end
@@ -0,0 +1,5
1 + class AddIndexToTask < ActiveRecord::Migration
2 + def change
3 + add_index :tasks, :submission_id
4 + end
5 + end
@@ -0,0 +1,9
1 + class AddHeartBeatFull < ActiveRecord::Migration
2 + def up
3 + GraderConfiguration.create key: 'right.heartbeat_response_full', value_type: 'string', value:'RESTART', description:'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
4 + end
5 +
6 + def down
7 +
8 + end
9 + end
@@ -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,50
1 + require 'test_helper'
2 +
3 + class AnnouncementsControllerTest < ActionController::TestCase
4 + setup do
5 + @announcement = announcements(:one)
6 + @request.session[:user_id] = users(:admin).id
7 + end
8 +
9 + test "should get index" do
10 + get :index
11 + assert_response :success
12 + assert_not_nil assigns(:announcements)
13 + end
14 +
15 + test "should get new" do
16 + get :new
17 + assert_response :success
18 + end
19 +
20 + test "should create announcement" do
21 + assert_difference('Announcement.count') do
22 + post :create, announcement: { author: 'aa',body: 'bb', published: true, frontpage: true, title: 'test'}
23 + end
24 +
25 + assert_redirected_to announcement_path(assigns(:announcement))
26 + end
27 +
28 + test "should show announcement" do
29 + get :show, id: @announcement
30 + assert_response :success
31 + end
32 +
33 + test "should get edit" do
34 + get :edit, id: @announcement
35 + assert_response :success
36 + end
37 +
38 + test "should update announcement" do
39 + patch :update, id: @announcement, announcement: { author: 'aa',body: 'bb', published: true, frontpage: true, title: 'test'}
40 + assert_redirected_to announcement_path(assigns(:announcement))
41 + end
42 +
43 + test "should destroy announcement" do
44 + assert_difference('Announcement.count', -1) do
45 + delete :destroy, id: @announcement
46 + end
47 +
48 + assert_redirected_to announcements_path
49 + end
50 + 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 +
@@ -0,0 +1,7
1 + require 'test_helper'
2 +
3 + class AdminTaskTest < ActionDispatch::IntegrationTest
4 + # test "the truth" do
5 + # assert true
6 + # end
7 + end
@@ -0,0 +1,40
1 + require 'test_helper'
2 +
3 + class LoginTest < ActionDispatch::IntegrationTest
4 + # test "the truth" do
5 + # assert true
6 + # end
7 +
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
16 + get root_path
17 + assert_response :success
18 + post login_login_path, {login: "john", password: "hello" }
19 + assert_redirected_to main_list_path
20 + end
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
39 + end
40 + end
@@ -10,24 +10,26
10 10 # Ignore the default SQLite database.
11 11 /db/*.sqlite3
12 12
13 13 # Ignore all logfiles and tempfiles.
14 14 /log/*.log
15 15 /tmp
16 16
17 17 *~
18 18
19 19 /vendor/plugins/rails_upgrade
20 20
21 21 #ignore public assets???
22 22 /public/assets
23 23 /public
24 24
25 25 /data
26 26
27 27 #ignore .orig and .swp
28 28 *.orig
29 29 *.swp
30 30
31 31 #ignore rvm setting file
32 32 .ruby-gemset
33 33 .ruby-version
34 +
35 + /config/secrets.yml
@@ -1,80 +1,91
1 1 source 'https://rubygems.org'
2 2
3 - gem 'rails', '~>3.2'
3 + #rails
4 + gem 'rails', '~>4.2.0'
5 + gem 'activerecord-session_store'
4 6
5 - gem 'select2-rails'
6 7
7 8 # Bundle edge Rails instead:
8 9 # gem 'rails', :git => 'git://github.com/rails/rails.git'
9 10
11 + #---------------- database ---------------------
12 + #the database
10 13 gem 'mysql2'
14 + #for testing
15 + gem 'sqlite3'
16 + #for dumping database into yaml
17 + gem 'yaml_db'
11 18
12 19 # Gems used only for assets and not required
13 20 # in production environments by default.
14 - group :assets do
15 - gem 'sass-rails', '~> 3.2.6'
16 - gem 'coffee-rails', '~> 3.2.2'
21 + gem 'sass-rails'
22 + gem 'coffee-rails'
17 23
18 24 # See https://github.com/sstephenson/execjs#readme for more supported runtimes
19 25 # gem 'therubyracer', :platforms => :ruby
20 26
21 - gem 'uglifier'
22 - end
27 + gem 'uglifier'
23 28
24 - gem 'prototype-rails'
29 + gem 'haml'
30 + gem 'haml-rails'
31 + # gem 'prototype-rails'
25 32
26 33 # To use ActiveModel has_secure_password
27 34 # gem 'bcrypt-ruby', '~> 3.0.0'
28 35
29 36 # To use Jbuilder templates for JSON
30 37 # gem 'jbuilder'
31 38
32 39 # Use unicorn as the app server
33 40 # gem 'unicorn'
34 41
35 42 # Deploy with Capistrano
36 43 # gem 'capistrano'
37 44
38 45 # To use debugger
39 46 # gem 'debugger'
40 47 #
41 48
42 49 #in-place editor
43 50 gem 'best_in_place', '~> 3.0.1'
44 51
45 52 # jquery addition
46 53 gem 'jquery-rails'
47 - gem 'jquery-ui-sass-rails'
54 + gem 'jquery-ui-rails'
48 55 gem 'jquery-timepicker-addon-rails'
49 56 gem 'jquery-tablesorter'
50 57 gem 'jquery-countdown-rails'
51 58
52 59 #syntax highlighter
53 60 gem 'rouge'
54 61
55 62 #add bootstrap
56 63 gem 'bootstrap-sass', '~> 3.2.0'
57 64 gem 'bootstrap-switch-rails'
58 65 gem 'bootstrap-toggle-rails'
59 66 gem 'autoprefixer-rails'
60 67
61 68 #bootstrap sortable
62 69 gem 'momentjs-rails'
63 70 gem 'rails_bootstrap_sortable'
64 71
72 + #----------- user interface -----------------
73 + #select 2
74 + gem 'select2-rails'
65 75 #ace editor
66 76 gem 'ace-rails-ap'
77 + #paginator
78 + gem 'will_paginate', '~> 3.0.7'
67 79
68 - gem 'haml'
69 - gem 'haml-rails'
70 80 gem 'mail'
71 81 gem 'rdiscount'
72 - gem 'test-unit'
73 - gem 'will_paginate', '~> 3.0.7'
74 82 gem 'dynamic_form'
75 83 gem 'in_place_editing'
76 84 gem 'verification', :git => 'https://github.com/sikachu/verification.git'
77 85
78 - group :test, :development do
79 - gem 'rspec-rails', '~> 2.99.0'
80 - end
86 +
87 + #---------------- testiing -----------------------
88 + gem 'minitest-reporters'
89 +
90 + #---------------- for console --------------------
91 + gem 'fuzzy-string-match'
@@ -1,208 +1,235
1 1 GIT
2 2 remote: https://github.com/sikachu/verification.git
3 - revision: 76eaf51b13276ecae54bd9cd115832595d2ff56d
3 + revision: ff31697b940d7b0e2ec65f08764215c96104e76d
4 4 specs:
5 5 verification (1.0.3)
6 - actionpack (>= 3.0.0, < 5.0)
7 - activesupport (>= 3.0.0, < 5.0)
6 + actionpack (>= 3.0.0, < 5.1)
7 + activesupport (>= 3.0.0, < 5.1)
8 8
9 9 GEM
10 10 remote: https://rubygems.org/
11 11 specs:
12 - ace-rails-ap (4.0.2)
13 - actionmailer (3.2.22.5)
14 - actionpack (= 3.2.22.5)
15 - mail (~> 2.5.4)
16 - actionpack (3.2.22.5)
17 - activemodel (= 3.2.22.5)
18 - activesupport (= 3.2.22.5)
19 - builder (~> 3.0.0)
12 + RubyInline (3.12.4)
13 + ZenTest (~> 4.3)
14 + ZenTest (4.11.1)
15 + ace-rails-ap (4.1.1)
16 + actionmailer (4.2.7.1)
17 + actionpack (= 4.2.7.1)
18 + actionview (= 4.2.7.1)
19 + activejob (= 4.2.7.1)
20 + mail (~> 2.5, >= 2.5.4)
21 + rails-dom-testing (~> 1.0, >= 1.0.5)
22 + actionpack (4.2.7.1)
23 + actionview (= 4.2.7.1)
24 + activesupport (= 4.2.7.1)
25 + rack (~> 1.6)
26 + rack-test (~> 0.6.2)
27 + rails-dom-testing (~> 1.0, >= 1.0.5)
28 + rails-html-sanitizer (~> 1.0, >= 1.0.2)
29 + actionview (4.2.7.1)
30 + activesupport (= 4.2.7.1)
31 + builder (~> 3.1)
20 32 erubis (~> 2.7.0)
21 - journey (~> 1.0.4)
22 - rack (~> 1.4.5)
23 - rack-cache (~> 1.2)
24 - rack-test (~> 0.6.1)
25 - sprockets (~> 2.2.1)
26 - activemodel (3.2.22.5)
27 - activesupport (= 3.2.22.5)
28 - builder (~> 3.0.0)
29 - activerecord (3.2.22.5)
30 - activemodel (= 3.2.22.5)
31 - activesupport (= 3.2.22.5)
32 - arel (~> 3.0.2)
33 - tzinfo (~> 0.3.29)
34 - activeresource (3.2.22.5)
35 - activemodel (= 3.2.22.5)
36 - activesupport (= 3.2.22.5)
37 - activesupport (3.2.22.5)
38 - i18n (~> 0.6, >= 0.6.4)
39 - multi_json (~> 1.0)
40 - arel (3.0.3)
41 - autoprefixer-rails (6.0.3)
33 + rails-dom-testing (~> 1.0, >= 1.0.5)
34 + rails-html-sanitizer (~> 1.0, >= 1.0.2)
35 + activejob (4.2.7.1)
36 + activesupport (= 4.2.7.1)
37 + globalid (>= 0.3.0)
38 + activemodel (4.2.7.1)
39 + activesupport (= 4.2.7.1)
40 + builder (~> 3.1)
41 + activerecord (4.2.7.1)
42 + activemodel (= 4.2.7.1)
43 + activesupport (= 4.2.7.1)
44 + arel (~> 6.0)
45 + activerecord-session_store (1.0.0)
46 + actionpack (>= 4.0, < 5.1)
47 + activerecord (>= 4.0, < 5.1)
48 + multi_json (~> 1.11, >= 1.11.2)
49 + rack (>= 1.5.2, < 3)
50 + railties (>= 4.0, < 5.1)
51 + activesupport (4.2.7.1)
52 + i18n (~> 0.7)
53 + json (~> 1.7, >= 1.7.7)
54 + minitest (~> 5.1)
55 + thread_safe (~> 0.3, >= 0.3.4)
56 + tzinfo (~> 1.1)
57 + ansi (1.5.0)
58 + arel (6.0.4)
59 + autoprefixer-rails (6.6.0)
42 60 execjs
43 - json
44 61 best_in_place (3.0.3)
45 62 actionpack (>= 3.2)
46 63 railties (>= 3.2)
47 64 bootstrap-sass (3.2.0.2)
48 65 sass (~> 3.2)
49 66 bootstrap-switch-rails (3.3.3)
50 67 bootstrap-toggle-rails (2.2.1.0)
51 - builder (3.0.4)
52 - coffee-rails (3.2.2)
68 + builder (3.2.2)
69 + coffee-rails (4.2.1)
53 70 coffee-script (>= 2.2.0)
54 - railties (~> 3.2.0)
55 - coffee-script (2.3.0)
71 + railties (>= 4.0.0, < 5.2.x)
72 + coffee-script (2.4.1)
56 73 coffee-script-source
57 74 execjs
58 - coffee-script-source (1.9.0)
59 - diff-lcs (1.2.5)
75 + coffee-script-source (1.12.2)
76 + concurrent-ruby (1.0.4)
60 77 dynamic_form (1.1.4)
61 78 erubis (2.7.0)
62 - execjs (2.3.0)
63 - haml (4.0.6)
79 + execjs (2.7.0)
80 + fuzzy-string-match (1.0.0)
81 + RubyInline (>= 3.8.6)
82 + globalid (0.3.7)
83 + activesupport (>= 4.1.0)
84 + haml (4.0.7)
64 85 tilt
65 - haml-rails (0.4)
66 - actionpack (>= 3.1, < 4.1)
67 - activesupport (>= 3.1, < 4.1)
68 - haml (>= 3.1, < 4.1)
69 - railties (>= 3.1, < 4.1)
70 - hike (1.2.3)
86 + haml-rails (0.9.0)
87 + actionpack (>= 4.0.1)
88 + activesupport (>= 4.0.1)
89 + haml (>= 4.0.6, < 5.0)
90 + html2haml (>= 1.0.1)
91 + railties (>= 4.0.1)
92 + html2haml (2.0.0)
93 + erubis (~> 2.7.0)
94 + haml (~> 4.0.0)
95 + nokogiri (~> 1.6.0)
96 + ruby_parser (~> 3.5)
71 97 i18n (0.7.0)
72 98 in_place_editing (1.2.0)
73 - journey (1.0.4)
74 99 jquery-countdown-rails (2.0.2)
75 - jquery-rails (3.1.2)
76 - railties (>= 3.0, < 5.0)
100 + jquery-rails (4.2.1)
101 + rails-dom-testing (>= 1, < 3)
102 + railties (>= 4.2.0)
77 103 thor (>= 0.14, < 2.0)
78 - jquery-tablesorter (1.13.4)
79 - railties (>= 3.1, < 5)
104 + jquery-tablesorter (1.23.3)
105 + railties (>= 3.2, < 6)
80 106 jquery-timepicker-addon-rails (1.4.1)
81 107 railties (>= 3.1)
82 - jquery-ui-rails (4.0.3)
83 - jquery-rails
84 - railties (>= 3.1.0)
85 - jquery-ui-sass-rails (4.0.3.0)
86 - jquery-rails
87 - jquery-ui-rails (= 4.0.3)
88 - railties (>= 3.1.0)
108 + jquery-ui-rails (6.0.1)
109 + railties (>= 3.2.16)
89 110 json (1.8.3)
90 - mail (2.5.4)
91 - mime-types (~> 1.16)
92 - treetop (~> 1.4.8)
93 - mime-types (1.25.1)
94 - momentjs-rails (2.11.1)
111 + loofah (2.0.3)
112 + nokogiri (>= 1.5.9)
113 + mail (2.6.4)
114 + mime-types (>= 1.16, < 4)
115 + mime-types (3.1)
116 + mime-types-data (~> 3.2015)
117 + mime-types-data (3.2016.0521)
118 + mini_portile2 (2.1.0)
119 + minitest (5.10.1)
120 + minitest-reporters (1.1.13)
121 + ansi
122 + builder
123 + minitest (>= 5.0)
124 + ruby-progressbar
125 + momentjs-rails (2.15.1)
95 126 railties (>= 3.1)
96 127 multi_json (1.12.1)
97 - mysql2 (0.3.20)
98 - polyglot (0.3.5)
99 - power_assert (0.2.2)
100 - prototype-rails (3.2.1)
101 - rails (~> 3.2)
102 - rack (1.4.7)
103 - rack-cache (1.6.1)
104 - rack (>= 0.4)
105 - rack-ssl (1.3.4)
106 - rack
128 + mysql2 (0.4.5)
129 + nokogiri (1.6.8.1)
130 + mini_portile2 (~> 2.1.0)
131 + rack (1.6.5)
107 132 rack-test (0.6.3)
108 133 rack (>= 1.0)
109 - rails (3.2.22.5)
110 - actionmailer (= 3.2.22.5)
111 - actionpack (= 3.2.22.5)
112 - activerecord (= 3.2.22.5)
113 - activeresource (= 3.2.22.5)
114 - activesupport (= 3.2.22.5)
115 - bundler (~> 1.0)
116 - railties (= 3.2.22.5)
117 - rails_bootstrap_sortable (2.0.0)
118 - momentjs-rails (~> 2, >= 2.8.3)
119 - railties (3.2.22.5)
120 - actionpack (= 3.2.22.5)
121 - activesupport (= 3.2.22.5)
122 - rack-ssl (~> 1.3.2)
134 + rails (4.2.7.1)
135 + actionmailer (= 4.2.7.1)
136 + actionpack (= 4.2.7.1)
137 + actionview (= 4.2.7.1)
138 + activejob (= 4.2.7.1)
139 + activemodel (= 4.2.7.1)
140 + activerecord (= 4.2.7.1)
141 + activesupport (= 4.2.7.1)
142 + bundler (>= 1.3.0, < 2.0)
143 + railties (= 4.2.7.1)
144 + sprockets-rails
145 + rails-deprecated_sanitizer (1.0.3)
146 + activesupport (>= 4.2.0.alpha)
147 + rails-dom-testing (1.0.8)
148 + activesupport (>= 4.2.0.beta, < 5.0)
149 + nokogiri (~> 1.6)
150 + rails-deprecated_sanitizer (>= 1.0.1)
151 + rails-html-sanitizer (1.0.3)
152 + loofah (~> 2.0)
153 + rails_bootstrap_sortable (2.0.1)
154 + momentjs-rails (>= 2.8.3)
155 + railties (4.2.7.1)
156 + actionpack (= 4.2.7.1)
157 + activesupport (= 4.2.7.1)
123 158 rake (>= 0.8.7)
124 - rdoc (~> 3.4)
125 - thor (>= 0.14.6, < 2.0)
126 - rake (11.2.2)
127 - rdiscount (2.1.8)
128 - rdoc (3.12.2)
129 - json (~> 1.4)
130 - rouge (1.8.0)
131 - rspec-collection_matchers (1.1.2)
132 - rspec-expectations (>= 2.99.0.beta1)
133 - rspec-core (2.99.2)
134 - rspec-expectations (2.99.2)
135 - diff-lcs (>= 1.1.3, < 2.0)
136 - rspec-mocks (2.99.3)
137 - rspec-rails (2.99.0)
138 - actionpack (>= 3.0)
139 - activemodel (>= 3.0)
140 - activesupport (>= 3.0)
141 - railties (>= 3.0)
142 - rspec-collection_matchers
143 - rspec-core (~> 2.99.0)
144 - rspec-expectations (~> 2.99.0)
145 - rspec-mocks (~> 2.99.0)
146 - sass (3.4.11)
147 - sass-rails (3.2.6)
148 - railties (~> 3.2.0)
149 - sass (>= 3.1.10)
150 - tilt (~> 1.3)
151 - select2-rails (4.0.1)
159 + thor (>= 0.18.1, < 2.0)
160 + rake (12.0.0)
161 + rdiscount (2.2.0.1)
162 + rouge (2.0.7)
163 + ruby-progressbar (1.8.1)
164 + ruby_parser (3.8.3)
165 + sexp_processor (~> 4.1)
166 + sass (3.4.23)
167 + sass-rails (5.0.6)
168 + railties (>= 4.0.0, < 6)
169 + sass (~> 3.1)
170 + sprockets (>= 2.8, < 4.0)
171 + sprockets-rails (>= 2.0, < 4.0)
172 + tilt (>= 1.1, < 3)
173 + select2-rails (4.0.3)
152 174 thor (~> 0.14)
153 - sprockets (2.2.3)
154 - hike (~> 1.2)
155 - multi_json (~> 1.0)
156 - rack (~> 1.0)
157 - tilt (~> 1.1, != 1.3.0)
158 - test-unit (3.0.9)
159 - power_assert
160 - thor (0.19.1)
161 - tilt (1.4.1)
162 - treetop (1.4.15)
163 - polyglot
164 - polyglot (>= 0.3.1)
165 - tzinfo (0.3.51)
166 - uglifier (2.7.0)
167 - execjs (>= 0.3.0)
168 - json (>= 1.8.0)
169 - will_paginate (3.0.7)
175 + sexp_processor (4.7.0)
176 + sprockets (3.7.1)
177 + concurrent-ruby (~> 1.0)
178 + rack (> 1, < 3)
179 + sprockets-rails (3.2.0)
180 + actionpack (>= 4.0)
181 + activesupport (>= 4.0)
182 + sprockets (>= 3.0.0)
183 + sqlite3 (1.3.12)
184 + thor (0.19.4)
185 + thread_safe (0.3.5)
186 + tilt (2.0.5)
187 + tzinfo (1.2.2)
188 + thread_safe (~> 0.1)
189 + uglifier (3.0.4)
190 + execjs (>= 0.3.0, < 3)
191 + will_paginate (3.0.12)
192 + yaml_db (0.4.2)
193 + rails (>= 3.0, < 5.1)
194 + rake (>= 0.8.7)
170 195
171 196 PLATFORMS
172 197 ruby
173 198
174 199 DEPENDENCIES
175 200 ace-rails-ap
201 + activerecord-session_store
176 202 autoprefixer-rails
177 203 best_in_place (~> 3.0.1)
178 204 bootstrap-sass (~> 3.2.0)
179 205 bootstrap-switch-rails
180 206 bootstrap-toggle-rails
181 - coffee-rails (~> 3.2.2)
207 + coffee-rails
182 208 dynamic_form
209 + fuzzy-string-match
183 210 haml
184 211 haml-rails
185 212 in_place_editing
186 213 jquery-countdown-rails
187 214 jquery-rails
188 215 jquery-tablesorter
189 216 jquery-timepicker-addon-rails
190 - jquery-ui-sass-rails
217 + jquery-ui-rails
191 218 mail
219 + minitest-reporters
192 220 momentjs-rails
193 221 mysql2
194 - prototype-rails
195 - rails (~> 3.2)
222 + rails (~> 4.2.0)
196 223 rails_bootstrap_sortable
197 224 rdiscount
198 225 rouge
199 - rspec-rails (~> 2.99.0)
200 - sass-rails (~> 3.2.6)
226 + sass-rails
201 227 select2-rails
202 - test-unit
228 + sqlite3
203 229 uglifier
204 230 verification!
205 231 will_paginate (~> 3.0.7)
232 + yaml_db
206 233
207 234 BUNDLED WITH
208 - 1.12.5
235 + 1.13.6
@@ -1,44 +1,41
1 1 // This is a manifest file that'll be compiled into application.js, which will include all the files
2 2 // listed below.
3 3 //
4 4 // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5 5 // or vendor/assets/javascripts of plugins, if any, can be referenced here using a relative path.
6 6 //
7 7 // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8 8 // the compiled file.
9 9 //
10 10 // WARNING: THE FIRST BLANK LINE MARKS THE END OF WHAT'S TO BE PROCESSED, ANY BLANK LINE SHOULD
11 11 // GO AFTER THE REQUIRES BELOW.
12 12 //
13 13 //= require jquery
14 14 //= require jquery_ujs
15 - //= require jquery.ui.all
15 + //= require jquery-ui
16 16 //= require bootstrap-sprockets
17 17 //= require moment
18 18 //= require bootstrap-sortable
19 19 //= require select2
20 20 //= require ace-rails-ap
21 21 //= require ace/mode-c_cpp
22 22 //= require ace/mode-python
23 23 //= require ace/mode-ruby
24 24 //= require ace/mode-pascal
25 25 //= require ace/mode-javascript
26 26 //= require ace/mode-java
27 27 //= require ace/theme-merbivore
28 28 //= require custom
29 29 //= require jquery.countdown
30 30 //-------------- addition from local_jquery -----------
31 - //= require jquery.ui.datepicker
32 - //= require jquery.ui.slider
33 - //= require jquery-ui-timepicker-addon
34 31 //= require jquery-tablesorter
35 32 //= require best_in_place
36 33 //= require best_in_place.jquery-ui
37 34 //= require brython
38 35
39 36 // since this is after blank line, it is not downloaded
40 37 //x= require prototype
41 38 //x= require prototype_ujs
42 39 //x= require effects
43 40 //x= require dragdrop
44 41 //x= require controls
@@ -1,14 +1,4
1 - //= require jquery
2 - //= require jquery_ujs
3 - //= require jquery.ui.all
4 - //= require jquery.ui.datepicker
5 - //= require jquery.ui.slider
6 - //= require jquery-ui-timepicker-addon
7 - //= require jquery-tablesorter
8 - //= require best_in_place
9 - //= require best_in_place.jquery-ui
10 -
11 1 $(document).ready(function() {
12 2 /* Activating Best In Place */
13 3 jQuery(".best_in_place").best_in_place();
14 4 });
@@ -1,45 +1,45
1 1 /* This is a manifest file that'll be compiled into application.css, which will include all the files
2 2 * listed below.
3 3 *
4 4 * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
5 5 * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
6 6 *
7 7 * You're free to add application-wide styles to this file and they'll appear at the bottom of the
8 8 * compiled file so the styles you add here take precedence over styles defined in any styles
9 9 * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
10 10 * file per style scope.
11 11 *
12 12 * // bootstrap says that we should not do this, but @import each file instead
13 13 * # *= require_tree .
14 14 * # *= require_self
15 15 */
16 16
17 - @import "jquery.ui.all";
18 - @import "jquery.ui.core";
19 - @import "jquery.ui.theme";
20 - @import "jquery.ui.datepicker";
21 - @import "jquery.ui.slider";
17 + @import "jquery-ui";
18 + //@import "jquery.ui.core";
19 + //@import "jquery.ui.theme";
20 + //@import "jquery.ui.datepicker";
21 + //@import "jquery.ui.slider";
22 22 @import "jquery-ui-timepicker-addon";
23 23 @import "jquery-tablesorter/theme.metro-dark";
24 24 @import "jquery.countdown";
25 25 @import "tablesorter-theme.cafe";
26 26
27 27 //bootstrap
28 28 @import "bootstrap-sprockets";
29 29 @import "bootstrap";
30 30 @import "select2";
31 31 @import "select2-bootstrap";
32 32
33 33 //@import bootstrap3-switch
34 34 @import "bootstrap-toggle";
35 35 @import "bootstrap-sortable";
36 36
37 37 //bootstrap navbar color (from)
38 38 $bgDefault: #19197b;
39 39 $bgHighlight: #06064b;
40 40 $colDefault: #8e8eb4;
41 41 $colHighlight: #ffffff;
42 42 $dropDown: false;
43 43
44 44 @font-face {
45 45 font-family: 'Glyphicons Halflings';
@@ -1,111 +1,116
1 1 class AnnouncementsController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 in_place_edit_for :announcement, :published
6 6
7 7 # GET /announcements
8 8 # GET /announcements.xml
9 9 def index
10 - @announcements = Announcement.find(:all,
11 - :order => "created_at DESC")
10 + @announcements = Announcement.order(created_at: :desc)
12 11
13 12 respond_to do |format|
14 13 format.html # index.html.erb
15 14 format.xml { render :xml => @announcements }
16 15 end
17 16 end
18 17
19 18 # GET /announcements/1
20 19 # GET /announcements/1.xml
21 20 def show
22 21 @announcement = Announcement.find(params[:id])
23 22
24 23 respond_to do |format|
25 24 format.html # show.html.erb
26 25 format.xml { render :xml => @announcement }
27 26 end
28 27 end
29 28
30 29 # GET /announcements/new
31 30 # GET /announcements/new.xml
32 31 def new
33 32 @announcement = Announcement.new
34 33
35 34 respond_to do |format|
36 35 format.html # new.html.erb
37 36 format.xml { render :xml => @announcement }
38 37 end
39 38 end
40 39
41 40 # GET /announcements/1/edit
42 41 def edit
43 42 @announcement = Announcement.find(params[:id])
44 43 end
45 44
46 45 # POST /announcements
47 46 # POST /announcements.xml
48 47 def create
49 - @announcement = Announcement.new(params[:announcement])
48 + @announcement = Announcement.new(announcement_params)
50 49
51 50 respond_to do |format|
52 51 if @announcement.save
53 52 flash[:notice] = 'Announcement was successfully created.'
54 53 format.html { redirect_to(@announcement) }
55 54 format.xml { render :xml => @announcement, :status => :created, :location => @announcement }
56 55 else
57 56 format.html { render :action => "new" }
58 57 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
59 58 end
60 59 end
61 60 end
62 61
63 62 # PUT /announcements/1
64 63 # PUT /announcements/1.xml
65 64 def update
66 65 @announcement = Announcement.find(params[:id])
67 66
68 67 respond_to do |format|
69 - if @announcement.update_attributes(params[:announcement])
68 + if @announcement.update_attributes(announcement_params)
70 69 flash[:notice] = 'Announcement was successfully updated.'
71 70 format.html { redirect_to(@announcement) }
72 71 format.js {}
73 72 format.xml { head :ok }
74 73 else
75 74 format.html { render :action => "edit" }
76 75 format.js {}
77 76 format.xml { render :xml => @announcement.errors, :status => :unprocessable_entity }
78 77 end
79 78 end
80 79 end
81 80
82 81 def toggle
83 82 @announcement = Announcement.find(params[:id])
84 83 @announcement.update_attributes( published: !@announcement.published? )
85 84 respond_to do |format|
86 85 format.js { render partial: 'toggle_button',
87 86 locals: {button_id: "#announcement_toggle_#{@announcement.id}",button_on: @announcement.published? } }
88 87 end
89 88 end
90 89
91 90 def toggle_front
92 91 @announcement = Announcement.find(params[:id])
93 92 @announcement.update_attributes( frontpage: !@announcement.frontpage? )
94 93 respond_to do |format|
95 94 format.js { render partial: 'toggle_button',
96 95 locals: {button_id: "#announcement_toggle_front_#{@announcement.id}",button_on: @announcement.frontpage? } }
97 96 end
98 97 end
99 98
100 99 # DELETE /announcements/1
101 100 # DELETE /announcements/1.xml
102 101 def destroy
103 102 @announcement = Announcement.find(params[:id])
104 103 @announcement.destroy
105 104
106 105 respond_to do |format|
107 106 format.html { redirect_to(announcements_url) }
108 107 format.xml { head :ok }
109 108 end
110 109 end
110 +
111 + private
112 +
113 + def announcement_params
114 + params.require(:announcement).permit(:author, :body, :published, :frontpage, :contest_only, :title)
115 + end
111 116 end
@@ -1,63 +1,75
1 1 class ApplicationController < ActionController::Base
2 2 protect_from_forgery
3 3
4 - before_filter :current_user
4 + before_filter :current_user
5 5
6 6 SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode'
7 7 MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login'
8 8
9 9 #report and redirect for unauthorized activities
10 10 def unauthorized_redirect
11 11 flash[:notice] = 'You are not authorized to view the page you requested'
12 12 redirect_to :controller => 'main', :action => 'login'
13 13 end
14 14
15 15 # Returns the current logged-in user (if any).
16 16 def current_user
17 17 return nil unless session[:user_id]
18 18 @current_user ||= User.find(session[:user_id])
19 19 end
20 20
21 21 def admin_authorization
22 22 return false unless authenticate
23 - user = User.find(session[:user_id], :include => ['roles'])
23 + user = User.includes(:roles).find(session[:user_id])
24 24 unless user.admin?
25 25 unauthorized_redirect
26 26 return false
27 27 end
28 28 return true
29 29 end
30 30
31 31 def authorization_by_roles(allowed_roles)
32 32 return false unless authenticate
33 33 user = User.find(session[:user_id])
34 34 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
35 35 unauthorized_redirect
36 36 return false
37 37 end
38 38 end
39 39
40 + def testcase_authorization
41 + #admin always has privileged
42 + puts "haha"
43 + if @current_user.admin?
44 + return true
45 + end
46 +
47 + puts "hehe"
48 + puts GraderConfiguration["right.view_testcase"]
49 + unauthorized_redirect unless GraderConfiguration["right.view_testcase"]
50 + end
51 +
40 52 protected
41 53
42 54 def authenticate
43 55 unless session[:user_id]
44 56 flash[:notice] = 'You need to login'
45 57 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
46 58 flash[:notice] = 'You need to login but you cannot log in at this time'
47 59 end
48 60 redirect_to :controller => 'main', :action => 'login'
49 61 return false
50 62 end
51 63
52 64 # check if run in single user mode
53 65 if GraderConfiguration[SINGLE_USER_MODE_CONF_KEY]
54 66 user = User.find_by_id(session[:user_id])
55 67 if user==nil or (not user.admin?)
56 68 flash[:notice] = 'You cannot log in at this time'
57 69 redirect_to :controller => 'main', :action => 'login'
58 70 return false
59 71 end
60 72 unless user.enabled?
61 73 flash[:notice] = 'Your account is disabled'
62 74 redirect_to :controller => 'main', :action => 'login'
63 75 return false
@@ -80,49 +92,49
80 92 end
81 93
82 94 def authenticate_by_ip_address
83 95 #this assume that we have already authenticate normally
84 96 unless GraderConfiguration[MULTIPLE_IP_LOGIN_CONF_KEY]
85 97 user = User.find(session[:user_id])
86 98 if (not user.admin? and user.last_ip and user.last_ip != request.remote_ip)
87 99 flash[:notice] = "You cannot use the system from #{request.remote_ip}. Your last ip is #{user.last_ip}"
88 100 redirect_to :controller => 'main', :action => 'login'
89 101 puts "CHEAT: user #{user.login} tried to login from '#{request.remote_ip}' while last ip is '#{user.last_ip}' at #{Time.zone.now}"
90 102 return false
91 103 end
92 104 unless user.last_ip
93 105 user.last_ip = request.remote_ip
94 106 user.save
95 107 end
96 108 end
97 109 return true
98 110 end
99 111
100 112 def authorization
101 113 return false unless authenticate
102 114 user = User.find(session[:user_id])
103 115 unless user.roles.detect { |role|
104 - role.rights.detect{ |right|
105 - right.controller == self.class.controller_name and
106 - (right.action == 'all' or right.action == action_name)
107 - }
116 + role.rights.detect{ |right|
117 + right.controller == self.class.controller_name and
118 + (right.action == 'all' or right.action == action_name)
119 + }
108 120 }
109 121 flash[:notice] = 'You are not authorized to view the page you requested'
110 122 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
111 123 redirect_to :controller => 'main', :action => 'login'
112 124 return false
113 125 end
114 126 end
115 127
116 128 def verify_time_limit
117 129 return true if session[:user_id]==nil
118 130 user = User.find(session[:user_id], :include => :site)
119 131 return true if user==nil or user.site == nil
120 132 if user.contest_finished?
121 133 flash[:notice] = 'Error: the contest you are participating is over.'
122 134 redirect_to :back
123 135 return false
124 136 end
125 137 return true
126 138 end
127 139
128 140 end
@@ -1,29 +1,34
1 1 class ConfigurationsController < ApplicationController
2 2
3 3 before_filter :authenticate
4 4 before_filter { |controller| controller.authorization_by_roles(['admin'])}
5 5
6 6
7 7 def index
8 - @configurations = GraderConfiguration.find(:all,
9 - :order => '`key`')
8 + @configurations = GraderConfiguration.order(:key)
9 + @group = GraderConfiguration.pluck("grader_configurations.key").map{ |x| x[0...(x.index('.'))] }.uniq.sort
10 10 end
11 11
12 12 def reload
13 13 GraderConfiguration.reload
14 14 redirect_to :action => 'index'
15 15 end
16 16
17 17 def update
18 18 @config = GraderConfiguration.find(params[:id])
19 19 User.clear_last_login if @config.key == GraderConfiguration::MULTIPLE_IP_LOGIN_KEY and @config.value == 'true' and params[:grader_configuration][:value] == 'false'
20 20 respond_to do |format|
21 - if @config.update_attributes(params[:grader_configuration])
21 + if @config.update_attributes(configuration_params)
22 22 format.json { head :ok }
23 23 else
24 24 format.json { respond_with_bip(@config) }
25 25 end
26 26 end
27 27 end
28 28
29 + private
30 + def configuration_params
31 + params.require(:grader_configuration).permit(:key,:value_type,:value,:description)
32 + end
33 +
29 34 end
@@ -1,40 +1,40
1 1 class ContestManagementController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 def index
6 6 @num_contests = Contest.count()
7 7 end
8 8
9 9 def user_stat
10 10 if not GraderConfiguration.indv_contest_mode?
11 11 redirect_to :action => 'index' and return
12 12 end
13 13
14 - @users = User.find(:all)
14 + @users = User.all
15 15 @start_times = {}
16 - UserContestStat.find(:all).each do |stat|
16 + UserContestStat.all.each do |stat|
17 17 @start_times[stat.user_id] = stat.started_at
18 18 end
19 19 end
20 20
21 21 def clear_stat
22 22 user = User.find(params[:id])
23 23 if user.contest_stat!=nil
24 24 user.contest_stat.destroy
25 25 end
26 26 redirect_to :action => 'user_stat'
27 27 end
28 28
29 29 def clear_all_stat
30 30 if not GraderConfiguration.indv_contest_mode?
31 31 redirect_to :action => 'index' and return
32 32 end
33 33
34 34 UserContestStat.delete_all()
35 35 flash[:notice] = 'All start time statistic cleared.'
36 36 redirect_to :action => 'index'
37 37 end
38 38
39 39 def change_contest_mode
40 40 if ['standard', 'contest', 'indv-contest', 'analysis'].include? params[:id]
@@ -45,48 +45,54
45 45
46 46 # POST /contests
47 47 # POST /contests.xml
48 48 def create
49 49 @contest = Contest.new(params[:contest])
50 50
51 51 respond_to do |format|
52 52 if @contest.save
53 53 flash[:notice] = 'Contest was successfully created.'
54 54 format.html { redirect_to(@contest) }
55 55 format.xml { render :xml => @contest, :status => :created, :location => @contest }
56 56 else
57 57 format.html { render :action => "new" }
58 58 format.xml { render :xml => @contest.errors, :status => :unprocessable_entity }
59 59 end
60 60 end
61 61 end
62 62
63 63 # PUT /contests/1
64 64 # PUT /contests/1.xml
65 65 def update
66 66 @contest = Contest.find(params[:id])
67 67
68 68 respond_to do |format|
69 - if @contest.update_attributes(params[:contest])
69 + if @contest.update_attributes(contests_params)
70 70 flash[:notice] = 'Contest was successfully updated.'
71 71 format.html { redirect_to(@contest) }
72 72 format.xml { head :ok }
73 73 else
74 74 format.html { render :action => "edit" }
75 75 format.xml { render :xml => @contest.errors, :status => :unprocessable_entity }
76 76 end
77 77 end
78 78 end
79 79
80 80 # DELETE /contests/1
81 81 # DELETE /contests/1.xml
82 82 def destroy
83 83 @contest = Contest.find(params[:id])
84 84 @contest.destroy
85 85
86 86 respond_to do |format|
87 87 format.html { redirect_to(contests_url) }
88 88 format.xml { head :ok }
89 89 end
90 90 end
91 91
92 + private
93 +
94 + def contests_params
95 + params.require(:contest).permit(:title,:enabled,:name)
96 + end
97 +
92 98 end
@@ -14,71 +14,69
14 14 return true
15 15 else
16 16 unauthorized_redirect
17 17 return false
18 18 end
19 19 }
20 20
21 21 verify :method => :post, :only => ['clear_all',
22 22 'start_exam',
23 23 'start_grading',
24 24 'stop_all',
25 25 'clear_terminated'],
26 26 :redirect_to => {:action => 'index'}
27 27
28 28 def index
29 29 redirect_to :action => 'list'
30 30 end
31 31
32 32 def list
33 33 @grader_processes = GraderProcess.find_running_graders
34 34 @stalled_processes = GraderProcess.find_stalled_process
35 35
36 36 @terminated_processes = GraderProcess.find_terminated_graders
37 37
38 - @last_task = Task.find(:first,
39 - :order => 'created_at DESC')
40 - @last_test_request = TestRequest.find(:first,
41 - :order => 'created_at DESC')
38 + @last_task = Task.last
39 + @last_test_request = TestRequest.last
42 40 @submission = Submission.order("id desc").limit(20)
43 41 @backlog_submission = Submission.where('graded_at is null')
44 42 end
45 43
46 44 def clear
47 45 grader_proc = GraderProcess.find(params[:id])
48 46 grader_proc.destroy if grader_proc!=nil
49 47 redirect_to :action => 'list'
50 48 end
51 49
52 50 def clear_terminated
53 51 GraderProcess.find_terminated_graders.each do |p|
54 52 p.destroy
55 53 end
56 54 redirect_to :action => 'list'
57 55 end
58 56
59 57 def clear_all
60 - GraderProcess.find(:all).each do |p|
58 + GraderProcess.all.each do |p|
61 59 p.destroy
62 60 end
63 61 redirect_to :action => 'list'
64 62 end
65 63
66 64 def view
67 65 if params[:type]=='Task'
68 66 redirect_to :action => 'task', :id => params[:id]
69 67 else
70 68 redirect_to :action => 'test_request', :id => params[:id]
71 69 end
72 70 end
73 71
74 72 def test_request
75 73 @test_request = TestRequest.find(params[:id])
76 74 end
77 75
78 76 def task
79 77 @task = Task.find(params[:id])
80 78 end
81 79
82 80 def submission
83 81 @submission = Submission.find(params[:id])
84 82 formatter = Rouge::Formatters::HTML.new(css_class: 'highlight', line_numbers: true )
@@ -1,31 +1,46
1 1 class HeartbeatController < ApplicationController
2 2 before_filter :admin_authorization, :only => ['index']
3 3
4 4 def edit
5 - @user = User.find_by_login(params[:id])
6 - unless @user
7 - render text: "LOGIN_NOT_FOUND"
8 - return
9 - end
5 + #@user = User.find_by_login(params[:id])
6 + #unless @user
7 + # render text: "LOGIN_NOT_FOUND"
8 + # return
9 + #end
10 10
11 11 #hb = HeartBeat.where(user_id: @user.id, ip_address: request.remote_ip).first
12 12 #puts "status = #{params[:status]}"
13 13 #if hb
14 14 # if params[:status]
15 15 # hb.status = params[:status]
16 16 # hb.save
17 17 # end
18 18 # hb.touch
19 19 #else
20 20 # HeartBeat.creae(user_id: @user.id, ip_address: request.remote_ip)
21 21 #end
22 - HeartBeat.create(user_id: @user.id, ip_address: request.remote_ip, status: params[:status])
22 + #HeartBeat.create(user_id: @user.id, ip_address: request.remote_ip, status: params[:status])
23 +
24 + res = GraderConfiguration['right.heartbeat_response']
25 + res.strip! if res
26 + full = GraderConfiguration['right.heartbeat_response_full']
27 + full.strip! if full
23 28
24 - render text: (GraderConfiguration['right.heartbeat_response'] || 'OK')
29 + if full and full != ''
30 + l = Login.where(ip_address: request.remote_ip).last
31 + @user = l.user
32 + if @user.solve_all_available_problems?
33 + render text: (full || 'OK')
34 + else
35 + render text: (res || 'OK')
36 + end
37 + else
38 + render text: (GraderConfiguration['right.heartbeat_response'] || 'OK')
39 + end
25 40 end
26 41
27 42 def index
28 43 @hb = HeartBeat.where("updated_at >= ?",Time.zone.now-2.hours).includes(:user).order(:user_id).all
29 44 @num = HeartBeat.where("updated_at >= ?",Time.zone.now-5.minutes).count(:user_id,distinct: true)
30 45 end
31 46 end
@@ -24,144 +24,127
24 24 # COMMENT OUT: only need when having high load
25 25 # caches_action :index, :login
26 26
27 27 # NOTE: This method is not actually needed, 'config/routes.rb' has
28 28 # assigned action login as a default action.
29 29 def index
30 30 redirect_to :action => 'login'
31 31 end
32 32
33 33 def login
34 34 saved_notice = flash[:notice]
35 35 reset_session
36 36 flash.now[:notice] = saved_notice
37 37
38 38 # EXPERIMENT:
39 39 # Hide login if in single user mode and the url does not
40 40 # explicitly specify /login
41 41 #
42 42 # logger.info "PATH: #{request.path}"
43 43 # if GraderConfiguration['system.single_user_mode'] and
44 44 # request.path!='/main/login'
45 45 # @hidelogin = true
46 46 # end
47 47
48 - @announcements = Announcement.find_for_frontpage
48 + @announcements = Announcement.frontpage
49 49 render :action => 'login', :layout => 'empty'
50 50 end
51 51
52 52 def list
53 53 prepare_list_information
54 54 end
55 55
56 56 def help
57 57 @user = User.find(session[:user_id])
58 58 end
59 59
60 60 def submit
61 61 user = User.find(session[:user_id])
62 62
63 63 @submission = Submission.new
64 64 @submission.problem_id = params[:submission][:problem_id]
65 65 @submission.user = user
66 66 @submission.language_id = 0
67 67 if (params['file']) and (params['file']!='')
68 68 @submission.source = File.open(params['file'].path,'r:UTF-8',&:read)
69 69 @submission.source.encode!('UTF-8','UTF-8',invalid: :replace, replace: '')
70 70 @submission.source_filename = params['file'].original_filename
71 71 end
72 72
73 73 if (params[:editor_text])
74 74 language = Language.find_by_id(params[:language_id])
75 75 @submission.source = params[:editor_text]
76 76 @submission.source_filename = "live_edit.#{language.ext}"
77 77 @submission.language = language
78 78 end
79 79
80 80 @submission.submitted_at = Time.new.gmtime
81 81 @submission.ip_address = request.remote_ip
82 82
83 83 if GraderConfiguration.time_limit_mode? and user.contest_finished?
84 84 @submission.errors.add(:base,"The contest is over.")
85 85 prepare_list_information
86 86 render :action => 'list' and return
87 87 end
88 88
89 89 if @submission.valid?
90 90 if @submission.save == false
91 - flash[:notice] = 'Error saving your submission'
91 + flash[:notice] = 'Error saving your submission'
92 92 elsif Task.create(:submission_id => @submission.id,
93 93 :status => Task::STATUS_INQUEUE) == false
94 - flash[:notice] = 'Error adding your submission to task queue'
94 + flash[:notice] = 'Error adding your submission to task queue'
95 95 end
96 96 else
97 97 prepare_list_information
98 98 render :action => 'list' and return
99 99 end
100 100 redirect_to :action => 'list'
101 101 end
102 102
103 103 def source
104 104 submission = Submission.find(params[:id])
105 105 if ((submission.user_id == session[:user_id]) and
106 106 (submission.problem != nil) and
107 107 (submission.problem.available))
108 108 send_data(submission.source,
109 - {:filename => submission.download_filename,
109 + {:filename => submission.download_filename,
110 110 :type => 'text/plain'})
111 111 else
112 112 flash[:notice] = 'Error viewing source'
113 113 redirect_to :action => 'list'
114 114 end
115 115 end
116 116
117 117 def compiler_msg
118 118 @submission = Submission.find(params[:id])
119 119 if @submission.user_id == session[:user_id]
120 120 render :action => 'compiler_msg', :layout => 'empty'
121 121 else
122 122 flash[:notice] = 'Error viewing source'
123 123 redirect_to :action => 'list'
124 124 end
125 125 end
126 126
127 - def submission
128 - @user = User.find(session[:user_id])
129 - @problems = @user.available_problems
130 - if params[:id]==nil
131 - @problem = nil
132 - @submissions = nil
133 - else
134 - @problem = Problem.find_by_id(params[:id])
135 - if (@problem == nil) or (not @problem.available)
136 - redirect_to :action => 'list'
137 - flash[:notice] = 'Error: submissions for that problem are not viewable.'
138 - return
139 - end
140 - @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
141 - end
142 - end
143 -
144 127 def result
145 128 if !GraderConfiguration.show_grading_result
146 129 redirect_to :action => 'list' and return
147 130 end
148 131 @user = User.find(session[:user_id])
149 132 @submission = Submission.find(params[:id])
150 133 if @submission.user!=@user
151 134 flash[:notice] = 'You are not allowed to view result of other users.'
152 135 redirect_to :action => 'list' and return
153 136 end
154 137 prepare_grading_result(@submission)
155 138 end
156 139
157 140 def load_output
158 141 if !GraderConfiguration.show_grading_result or params[:num]==nil
159 142 redirect_to :action => 'list' and return
160 143 end
161 144 @user = User.find(session[:user_id])
162 145 @submission = Submission.find(params[:id])
163 146 if @submission.user!=@user
164 147 flash[:notice] = 'You are not allowed to view result of other users.'
165 148 redirect_to :action => 'list' and return
166 149 end
167 150 case_num = params[:num].to_i
@@ -196,51 +179,51
196 179 prepare_announcements(params[:recent])
197 180 else
198 181 prepare_announcements
199 182 end
200 183 render(:partial => 'announcement',
201 184 :collection => @announcements,
202 185 :locals => {:announcement_effect => true})
203 186 end
204 187
205 188 def confirm_contest_start
206 189 user = User.find(session[:user_id])
207 190 if request.method == 'POST'
208 191 user.update_start_time
209 192 redirect_to :action => 'list'
210 193 else
211 194 @contests = user.contests
212 195 @user = user
213 196 end
214 197 end
215 198
216 199 protected
217 200
218 201 def prepare_announcements(recent=nil)
219 202 if GraderConfiguration.show_tasks_to?(@user)
220 - @announcements = Announcement.find_published(true)
203 + @announcements = Announcement.published(true)
221 204 else
222 - @announcements = Announcement.find_published
205 + @announcements = Announcement.published
223 206 end
224 207 if recent!=nil
225 208 recent_id = recent.to_i
226 209 @announcements = @announcements.find_all { |a| a.id > recent_id }
227 210 end
228 211 end
229 212
230 213 def prepare_list_information
231 214 @user = User.find(session[:user_id])
232 215 if not GraderConfiguration.multicontests?
233 216 @problems = @user.available_problems
234 217 else
235 218 @contest_problems = @user.available_problems_group_by_contests
236 219 @problems = @user.available_problems
237 220 end
238 221 @prob_submissions = {}
239 222 @problems.each do |p|
240 223 sub = Submission.find_last_by_user_and_problem(@user.id,p.id)
241 224 if sub!=nil
242 225 @prob_submissions[p.id] = { :count => sub.number, :submission => sub }
243 226 else
244 227 @prob_submissions[p.id] = { :count => 0, :submission => nil }
245 228 end
246 229 end
@@ -1,203 +1,210
1 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 6 in_place_edit_for :problem, :name
6 7 in_place_edit_for :problem, :full_name
7 8 in_place_edit_for :problem, :full_score
8 9
9 10 def index
10 - @problems = Problem.find(:all, :order => 'date_added DESC')
11 + @problems = Problem.order(date_added: :desc)
11 12 end
12 13
13 14 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
14 15 verify :method => :post, :only => [ :create, :quick_create,
15 16 :do_manage,
16 17 :do_import,
17 18 ],
18 19 :redirect_to => { :action => :index }
19 20
20 21 def show
21 22 @problem = Problem.find(params[:id])
22 23 end
23 24
24 25 def new
25 26 @problem = Problem.new
26 27 @description = nil
27 28 end
28 29
29 30 def create
30 - @problem = Problem.new(params[:problem])
31 + @problem = Problem.new(problem_params)
31 32 @description = Description.new(params[:description])
32 33 if @description.body!=''
33 34 if !@description.save
34 35 render :action => new and return
35 36 end
36 37 else
37 38 @description = nil
38 39 end
39 40 @problem.description = @description
40 41 if @problem.save
41 42 flash[:notice] = 'Problem was successfully created.'
42 43 redirect_to action: :index
43 44 else
44 45 render :action => 'new'
45 46 end
46 47 end
47 48
48 49 def quick_create
49 - @problem = Problem.new(params[:problem])
50 + @problem = Problem.new(problem_params)
50 51 @problem.full_name = @problem.name if @problem.full_name == ''
51 52 @problem.full_score = 100
52 53 @problem.available = false
53 54 @problem.test_allowed = true
54 55 @problem.output_only = false
55 56 @problem.date_added = Time.new
56 57 if @problem.save
57 58 flash[:notice] = 'Problem was successfully created.'
58 59 redirect_to action: :index
59 60 else
60 61 flash[:notice] = 'Error saving problem'
61 62 redirect_to action: :index
62 63 end
63 64 end
64 65
65 66 def edit
66 67 @problem = Problem.find(params[:id])
67 68 @description = @problem.description
68 69 end
69 70
70 71 def update
71 72 @problem = Problem.find(params[:id])
72 73 @description = @problem.description
73 74 if @description.nil? and params[:description][:body]!=''
74 75 @description = Description.new(params[:description])
75 76 if !@description.save
76 77 flash[:notice] = 'Error saving description'
77 78 render :action => 'edit' and return
78 79 end
79 80 @problem.description = @description
80 81 elsif @description
81 82 if !@description.update_attributes(params[:description])
82 83 flash[:notice] = 'Error saving description'
83 84 render :action => 'edit' and return
84 85 end
85 86 end
86 87 if params[:file] and params[:file].content_type != 'application/pdf'
87 88 flash[:notice] = 'Error: Uploaded file is not PDF'
88 89 render :action => 'edit' and return
89 90 end
90 - if @problem.update_attributes(params[:problem])
91 + if @problem.update_attributes(problem_params)
91 92 flash[:notice] = 'Problem was successfully updated.'
92 93 unless params[:file] == nil or params[:file] == ''
93 94 flash[:notice] = 'Problem was successfully updated and a new PDF file is uploaded.'
94 95 out_dirname = "#{Problem.download_file_basedir}/#{@problem.id}"
95 96 if not FileTest.exists? out_dirname
96 97 Dir.mkdir out_dirname
97 98 end
98 99
99 100 out_filename = "#{out_dirname}/#{@problem.name}.pdf"
100 101 if FileTest.exists? out_filename
101 102 File.delete out_filename
102 103 end
103 104
104 105 File.open(out_filename,"wb") do |file|
105 106 file.write(params[:file].read)
106 107 end
107 108 @problem.description_filename = "#{@problem.name}.pdf"
108 109 @problem.save
109 110 end
110 111 redirect_to :action => 'show', :id => @problem
111 112 else
112 113 render :action => 'edit'
113 114 end
114 115 end
115 116
116 117 def destroy
117 118 p = Problem.find(params[:id]).destroy
118 119 redirect_to action: :index
119 120 end
120 121
121 122 def toggle
122 123 @problem = Problem.find(params[:id])
123 124 @problem.update_attributes(available: !(@problem.available) )
124 125 respond_to do |format|
125 126 format.js { }
126 127 end
127 128 end
128 129
129 130 def toggle_test
130 131 @problem = Problem.find(params[:id])
131 132 @problem.update_attributes(test_allowed: !(@problem.test_allowed?) )
132 133 respond_to do |format|
133 134 format.js { }
134 135 end
135 136 end
136 137
138 + def toggle_view_testcase
139 + @problem = Problem.find(params[:id])
140 + @problem.update_attributes(view_testcase: !(@problem.view_testcase?) )
141 + respond_to do |format|
142 + format.js { }
143 + end
144 + end
145 +
137 146 def turn_all_off
138 - Problem.find(:all,
139 - :conditions => "available = 1").each do |problem|
147 + Problem.available.all.each do |problem|
140 148 problem.available = false
141 149 problem.save
142 150 end
143 151 redirect_to action: :index
144 152 end
145 153
146 154 def turn_all_on
147 - Problem.find(:all,
148 - :conditions => "available = 0").each do |problem|
155 + Problem.where.not(available: true).each do |problem|
149 156 problem.available = true
150 157 problem.save
151 158 end
152 159 redirect_to action: :index
153 160 end
154 161
155 162 def stat
156 163 @problem = Problem.find(params[:id])
157 164 unless @problem.available or session[:admin]
158 165 redirect_to :controller => 'main', :action => 'list'
159 166 return
160 167 end
161 168 @submissions = Submission.includes(:user).where(problem_id: params[:id]).order(:user_id,:id)
162 169
163 170 #stat summary
164 171 range =65
165 172 @histogram = { data: Array.new(range,0), summary: {} }
166 173 user = Hash.new(0)
167 174 @submissions.find_each do |sub|
168 175 d = (DateTime.now.in_time_zone - sub.submitted_at) / 24 / 60 / 60
169 176 @histogram[:data][d.to_i] += 1 if d < range
170 177 user[sub.user_id] = [user[sub.user_id], ((sub.try(:points) || 0) >= @problem.full_score) ? 1 : 0].max
171 178 end
172 179 @histogram[:summary][:max] = [@histogram[:data].max,1].max
173 180
174 181 @summary = { attempt: user.count, solve: 0 }
175 182 user.each_value { |v| @summary[:solve] += 1 if v == 1 }
176 183 end
177 184
178 185 def manage
179 - @problems = Problem.find(:all, :order => 'date_added DESC')
186 + @problems = Problem.order(date_added: :desc)
180 187 end
181 188
182 189 def do_manage
183 190 if params.has_key? 'change_date_added'
184 191 change_date_added
185 192 elsif params.has_key? 'add_to_contest'
186 193 add_to_contest
187 194 elsif params.has_key? 'enable_problem'
188 195 set_available(true)
189 196 elsif params.has_key? 'disable_problem'
190 197 set_available(false)
191 198 end
192 199 redirect_to :action => 'manage'
193 200 end
194 201
195 202 def import
196 203 @allow_test_pair_import = allow_test_pair_import?
197 204 end
198 205
199 206 def do_import
200 207 old_problem = Problem.find_by_name(params[:name])
201 208 if !allow_test_pair_import? and params.has_key? :import_to_db
202 209 params.delete :import_to_db
203 210 end
@@ -257,25 +264,31
257 264 end
258 265
259 266 def set_available(avail)
260 267 problems = get_problems_from_params
261 268 problems.each do |p|
262 269 p.available = avail
263 270 p.save
264 271 end
265 272 end
266 273
267 274 def get_problems_from_params
268 275 problems = []
269 276 params.keys.each do |k|
270 277 if k.index('prob-')==0
271 278 name, id, order = k.split('-')
272 279 problems << Problem.find(id)
273 280 end
274 281 end
275 282 problems
276 283 end
277 284
278 285 def get_problems_stat
279 286 end
280 287
288 + private
289 +
290 + def problem_params
291 + params.require(:problem).permit(:name, :full_name, :full_score, :date_added, :available, :test_allowed,:output_only, :url, :description)
292 + end
293 +
281 294 end
@@ -1,102 +1,100
1 1 require 'csv'
2 2
3 3 class ReportController < ApplicationController
4 4
5 5 before_filter :authenticate
6 6
7 7 before_filter :admin_authorization, only: [:login_stat,:submission_stat, :stuck, :cheat_report, :cheat_scruntinize, :show_max_score]
8 8
9 9 before_filter(only: [:problem_hof]) { |c|
10 10 return false unless authenticate
11 11
12 - if GraderConfiguration["right.user_view_submission"]
13 - return true;
14 - end
15 -
16 - admin_authorization
12 + admin_authorization unless GraderConfiguration["right.user_view_submission"]
17 13 }
18 14
19 15 def max_score
20 16 end
21 17
22 18 def current_score
23 - @problems = Problem.find_available_problems
19 + @problems = Problem.available_problems
24 20 @users = User.includes(:contests).includes(:contest_stat).where(enabled: true)
25 21 @scorearray = calculate_max_score(@problems, @users,0,0,true)
26 22
27 23 #rencer accordingly
28 24 if params[:button] == 'download' then
29 25 csv = gen_csv_from_scorearray(@scorearray,@problems)
30 26 send_data csv, filename: 'max_score.csv'
31 27 else
32 28 #render template: 'user_admin/user_stat'
33 29 render 'current_score'
34 30 end
35 31 end
36 32
37 33 def show_max_score
38 34 #process parameters
39 35 #problems
40 36 @problems = []
41 - params[:problem_id].each do |id|
42 - next unless id.strip != ""
43 - pid = Problem.find_by_id(id.to_i)
44 - @problems << pid if pid
37 + if params[:problem_id]
38 + params[:problem_id].each do |id|
39 + next unless id.strip != ""
40 + pid = Problem.find_by_id(id.to_i)
41 + @problems << pid if pid
42 + end
45 43 end
46 44
47 45 #users
48 46 @users = if params[:user] == "all" then
49 - User.find(:all, :include => [:contests, :contest_stat])
47 + User.includes(:contests).includes(:contest_stat)
50 48 else
51 49 User.includes(:contests).includes(:contest_stat).where(enabled: true)
52 50 end
53 51
54 52 #set up range from param
55 - since_id = params.fetch(:min_id, 0).to_i
56 - until_id = params.fetch(:max_id, 0).to_i
53 + @since_id = params.fetch(:from_id, 0).to_i
54 + @until_id = params.fetch(:to_id, 0).to_i
57 55
58 56 #calculate the routine
59 - @scorearray = calculate_max_score(@problems, @users,since_id,until_id)
57 + @scorearray = calculate_max_score(@problems, @users, @since_id, @until_id)
60 58
61 59 #rencer accordingly
62 60 if params[:button] == 'download' then
63 61 csv = gen_csv_from_scorearray(@scorearray,@problems)
64 62 send_data csv, filename: 'max_score.csv'
65 63 else
66 64 #render template: 'user_admin/user_stat'
67 65 render 'max_score'
68 66 end
69 67
70 68 end
71 69
72 70 def score
73 71 if params[:commit] == 'download csv'
74 72 @problems = Problem.all
75 73 else
76 - @problems = Problem.find_available_problems
74 + @problems = Problem.available_problems
77 75 end
78 - @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
76 + @users = User.includes(:contests, :contest_stat).where(enabled: true)
79 77 @scorearray = Array.new
80 78 @users.each do |u|
81 79 ustat = Array.new
82 80 ustat[0] = u
83 81 @problems.each do |p|
84 82 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
85 83 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
86 84 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
87 85 else
88 86 ustat << [0,false]
89 87 end
90 88 end
91 89 @scorearray << ustat
92 90 end
93 91 if params[:commit] == 'download csv' then
94 92 csv = gen_csv_from_scorearray(@scorearray,@problems)
95 93 send_data csv, filename: 'last_score.csv'
96 94 else
97 95 render template: 'user_admin/user_stat'
98 96 end
99 97
100 98 end
101 99
102 100 def login_stat
@@ -1,31 +1,31
1 1 class SiteController < ApplicationController
2 2
3 3 before_filter :site_admin_authorization, :except => 'login'
4 4
5 5 def login
6 6 # Site administrator login
7 - @countries = Country.find(:all, :include => :sites)
7 + @countries = Country.includes(:sites).all
8 8 @country_select = @countries.collect { |c| [c.name, c.id] }
9 9
10 10 @country_select_with_all = [['Any',0]]
11 11 @countries.each do |country|
12 12 @country_select_with_all << [country.name, country.id]
13 13 end
14 14
15 15 @site_select = []
16 16 @countries.each do |country|
17 17 country.sites.each do |site|
18 18 @site_select << ["#{site.name}, #{country.name}", site.id]
19 19 end
20 20 end
21 21
22 22 @default_site = Site.first if !GraderConfiguration['contest.multisites']
23 23
24 24 render :action => 'login', :layout => 'empty'
25 25 end
26 26
27 27 def index
28 28 if @site.started
29 29 render :action => 'started', :layout => 'empty'
30 30 else
31 31 render :action => 'prompt', :layout => 'empty'
@@ -38,25 +38,30
38 38 @site.save
39 39 redirect_to :action => 'index'
40 40 end
41 41
42 42 def logout
43 43 reset_session
44 44 redirect_to :controller => 'main', :action => 'login'
45 45 end
46 46
47 47 protected
48 48 def site_admin_authorization
49 49 if session[:site_id]==nil
50 50 redirect_to :controller => 'site', :action => 'login' and return
51 51 end
52 52 begin
53 53 @site = Site.find(session[:site_id], :include => :country)
54 54 rescue ActiveRecord::RecordNotFound
55 55 @site = nil
56 56 end
57 57 if @site==nil
58 58 redirect_to :controller => 'site', :action => 'login' and return
59 59 end
60 60 end
61 61
62 + private
63 + def site_params
64 + params.require(:site).permit()
65 + end
66 +
62 67 end
@@ -1,32 +1,32
1 1 class SitesController < ApplicationController
2 2
3 3 before_filter :admin_authorization
4 4
5 5 # GET /sites
6 6 # GET /sites.xml
7 7 def index
8 - @sites = Site.find(:all, :order => 'country_id')
8 + @sites = Site.order(:country_id)
9 9
10 10 respond_to do |format|
11 11 format.html # index.html.erb
12 12 format.xml { render :xml => @sites }
13 13 end
14 14 end
15 15
16 16 # GET /sites/1
17 17 # GET /sites/1.xml
18 18 def show
19 19 @site = Site.find(params[:id])
20 20
21 21 respond_to do |format|
22 22 format.html # show.html.erb
23 23 format.xml { render :xml => @site }
24 24 end
25 25 end
26 26
27 27 # GET /sites/new
28 28 # GET /sites/new.xml
29 29 def new
30 30 @site = Site.new
31 31
32 32 respond_to do |format|
@@ -44,48 +44,54
44 44 # POST /sites.xml
45 45 def create
46 46 @site = Site.new(params[:site])
47 47 @site.clear_start_time_if_not_started
48 48
49 49 respond_to do |format|
50 50 if @site.save
51 51 flash[:notice] = 'Site was successfully created.'
52 52 format.html { redirect_to(@site) }
53 53 format.xml { render :xml => @site, :status => :created, :location => @site }
54 54 else
55 55 format.html { render :action => "new" }
56 56 format.xml { render :xml => @site.errors, :status => :unprocessable_entity }
57 57 end
58 58 end
59 59 end
60 60
61 61 # PUT /sites/1
62 62 # PUT /sites/1.xml
63 63 def update
64 64 @site = Site.find(params[:id])
65 65 @site.clear_start_time_if_not_started
66 66
67 67 respond_to do |format|
68 - if @site.update_attributes(params[:site])
68 + if @site.update_attributes(site_params)
69 69 flash[:notice] = 'Site was successfully updated.'
70 70 format.html { redirect_to(@site) }
71 71 format.xml { head :ok }
72 72 else
73 73 format.html { render :action => "edit" }
74 74 format.xml { render :xml => @site.errors, :status => :unprocessable_entity }
75 75 end
76 76 end
77 77 end
78 78
79 79 # DELETE /sites/1
80 80 # DELETE /sites/1.xml
81 81 def destroy
82 82 @site = Site.find(params[:id])
83 83 @site.destroy
84 84
85 85 respond_to do |format|
86 86 format.html { redirect_to(sites_url) }
87 87 format.xml { head :ok }
88 88 end
89 89 end
90 90
91 + private
92 +
93 + def site_params
94 + params.require(:site).permit(:name,:started,:start_time,:country_id,:password)
95 + end
96 +
91 97 end
@@ -1,137 +1,108
1 1 class SubmissionsController < ApplicationController
2 - before_filter :authenticate
3 - before_filter :submission_authorization, only: [:show, :direct_edit_submission]
2 + before_action :authenticate
3 + before_action :submission_authorization, only: [:show, :direct_edit_submission, :download, :edit]
4 + before_action :admin_authorization, only: [:rejudge]
4 5
5 6 # GET /submissions
6 7 # GET /submissions.json
7 8 # Show problem selection and user's submission of that problem
8 9 def index
9 10 @user = @current_user
10 11 @problems = @user.available_problems
11 12
12 13 if params[:problem_id]==nil
13 14 @problem = nil
14 15 @submissions = nil
15 16 else
16 17 @problem = Problem.find_by_id(params[:problem_id])
17 18 if (@problem == nil) or (not @problem.available)
18 19 redirect_to main_list_path
19 20 flash[:notice] = 'Error: submissions for that problem are not viewable.'
20 21 return
21 22 end
22 - @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id)
23 + @submissions = Submission.find_all_by_user_problem(@user.id, @problem.id).order(id: :desc)
23 24 end
24 25 end
25 26
26 27 # GET /submissions/1
27 28 # GET /submissions/1.json
28 29 def show
29 30 @submission = Submission.find(params[:id])
30 31
31 32 #log the viewing
32 33 user = User.find(session[:user_id])
33 34 SubmissionViewLog.create(user_id: session[:user_id],submission_id: @submission.id) unless user.admin?
35 +
36 + @task = @submission.task
37 + end
38 +
39 + def download
40 + @submission = Submission.find(params[:id])
41 + send_data(@submission.source, {:filename => @submission.download_filename, :type => 'text/plain'})
42 + end
43 +
44 + def compiler_msg
45 + @submission = Submission.find(params[:id])
46 + respond_to do |format|
47 + format.js
48 + end
34 49 end
35 50
36 51 #on-site new submission on specific problem
37 52 def direct_edit_problem
38 53 @problem = Problem.find(params[:problem_id])
39 54 @source = ''
40 55 render 'edit'
41 56 end
42 57
43 58 # GET /submissions/1/edit
44 59 def edit
45 60 @submission = Submission.find(params[:id])
46 61 @source = @submission.source.to_s
47 62 @problem = @submission.problem
48 63 @lang_id = @submission.language.id
49 64 end
50 65
51 66
52 67 def get_latest_submission_status
53 68 @problem = Problem.find(params[:pid])
54 69 @submission = Submission.find_last_by_user_and_problem(params[:uid],params[:pid])
55 70 puts User.find(params[:uid]).login
56 71 puts Problem.find(params[:pid]).name
57 72 puts 'nil' unless @submission
58 73 respond_to do |format|
59 74 format.js
60 75 end
61 76 end
62 77
63 - # # GET /submissions/new
64 - # # GET /submissions/new.json
65 - # def new
66 - # @submission = Submission.new
67 - #
68 - # respond_to do |format|
69 - # format.html # new.html.erb
70 - # format.json { render json: @submission }
71 - # end
72 - # end
73 - #
74 - #
75 - # # POST /submissions
76 - # # POST /submissions.json
77 - # def create
78 - # @submission = Submission.new(params[:submission])
79 - #
80 - # respond_to do |format|
81 - # if @submission.save
82 - # format.html { redirect_to @submission, notice: 'Submission was successfully created.' }
83 - # format.json { render json: @submission, status: :created, location: @submission }
84 - # else
85 - # format.html { render action: "new" }
86 - # format.json { render json: @submission.errors, status: :unprocessable_entity }
87 - # end
88 - # end
89 - # end
90 - #
91 - # # PUT /submissions/1
92 - # # PUT /submissions/1.json
93 - # def update
94 - # @submission = Submission.find(params[:id])
95 - #
96 - # respond_to do |format|
97 - # if @submission.update_attributes(params[:submission])
98 - # format.html { redirect_to @submission, notice: 'Submission was successfully updated.' }
99 - # format.json { head :no_content }
100 - # else
101 - # format.html { render action: "edit" }
102 - # format.json { render json: @submission.errors, status: :unprocessable_entity }
103 - # end
104 - # end
105 - # end
106 - #
107 - # # DELETE /submissions/1
108 - # # DELETE /submissions/1.json
109 - # def destroy
110 - # @submission = Submission.find(params[:id])
111 - # @submission.destroy
112 - #
113 - # respond_to do |format|
114 - # format.html { redirect_to submissions_url }
115 - # format.json { head :no_content }
116 - # end
117 - # end
78 + # GET /submissions/:id/rejudge
79 + def rejudge
80 + @submission = Submission.find(params[:id])
81 + @task = @submission.task
82 + @task.status_inqueue! if @task
83 + respond_to do |format|
84 + format.js
85 + end
86 + end
118 87
119 88 protected
89 +
120 90 def submission_authorization
121 91 #admin always has privileged
122 92 if @current_user.admin?
123 93 return true
124 94 end
125 95
126 96 sub = Submission.find(params[:id])
127 97 if sub.problem.available?
128 98 puts "sub = #{sub.user.id}, current = #{@current_user.id}"
129 99 return true if GraderConfiguration["right.user_view_submission"] or sub.user == @current_user
130 100 end
131 101
132 102 #default to NO
133 103 unauthorized_redirect
134 104 return false
135 105 end
106 +
136 107
137 108 end
@@ -8,221 +8,233
8 8
9 9 # GETs should be safe (see http://www.w3.org/2001/tag/doc/whenToUseGet.html)
10 10 verify :method => :post, :only => [
11 11 :create, :create_from_list,
12 12 :update,
13 13 :manage_contest,
14 14 :bulk_mail
15 15 ],
16 16 :redirect_to => { :action => :list }
17 17
18 18 def index
19 19 @user_count = User.count
20 20 if params[:page] == 'all'
21 21 @users = User.all
22 22 @paginated = false
23 23 else
24 24 @users = User.paginate :page => params[:page]
25 25 @paginated = true
26 26 end
27 27 @hidden_columns = ['hashed_password', 'salt', 'created_at', 'updated_at']
28 28 @contests = Contest.enabled
29 29 end
30 30
31 31 def active
32 - sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago])
32 + sessions = ActiveRecord::SessionStore::Session.where("updated_at >= ?", 60.minutes.ago)
33 33 @users = []
34 34 sessions.each do |session|
35 35 if session.data[:user_id]
36 36 @users << User.find(session.data[:user_id])
37 37 end
38 38 end
39 39 end
40 40
41 41 def show
42 42 @user = User.find(params[:id])
43 43 end
44 44
45 45 def new
46 46 @user = User.new
47 47 end
48 48
49 49 def create
50 - @user = User.new(params[:user])
50 + @user = User.new(user_params)
51 51 @user.activated = true
52 52 if @user.save
53 53 flash[:notice] = 'User was successfully created.'
54 54 redirect_to :action => 'index'
55 55 else
56 56 render :action => 'new'
57 57 end
58 58 end
59 59
60 60 def clear_last_ip
61 61 @user = User.find(params[:id])
62 62 @user.last_ip = nil
63 63 @user.save
64 64 redirect_to action: 'index', page: params[:page]
65 65 end
66 66
67 67 def create_from_list
68 68 lines = params[:user_list]
69 69
70 70 note = []
71 71
72 72 lines.split("\n").each do |line|
73 73 items = line.chomp.split(',')
74 74 if items.length>=2
75 75 login = items[0]
76 76 full_name = items[1]
77 + remark =''
78 + user_alias = ''
77 79
78 80 added_random_password = false
79 - if items.length>=3
81 + if items.length >= 3 and items[2].chomp(" ").length > 0;
80 82 password = items[2].chomp(" ")
81 - user_alias = (items.length>=4) ? items[3] : login
82 83 else
83 84 password = random_password
84 - user_alias = (items.length>=4) ? items[3] : login
85 - added_random_password = true
85 + add_random_password=true;
86 + end
87 +
88 + if items.length>= 4 and items[3].chomp(" ").length > 0;
89 + user_alias = items[3].chomp(" ")
90 + else
91 + user_alias = login
92 + end
93 +
94 + if items.length>=5
95 + remark = items[4].strip;
86 96 end
87 97
88 98 user = User.find_by_login(login)
89 99 if (user)
90 100 user.full_name = full_name
91 101 user.password = password
102 + user.remark = remark
92 103 else
93 104 user = User.new({:login => login,
94 105 :full_name => full_name,
95 106 :password => password,
96 107 :password_confirmation => password,
97 - :alias => user_alias})
108 + :alias => user_alias,
109 + :remark => remark})
98 110 end
99 111 user.activated = true
100 112 user.save
101 113
102 114 if added_random_password
103 115 note << "'#{login}' (+)"
104 116 else
105 117 note << login
106 118 end
107 119 end
108 120 end
109 - flash[:notice] = 'User(s) ' + note.join(', ') +
121 + flash[:success] = 'User(s) ' + note.join(', ') +
110 122 ' were successfully created. ' +
111 123 '( (+) - created with random passwords.)'
112 124 redirect_to :action => 'index'
113 125 end
114 126
115 127 def edit
116 128 @user = User.find(params[:id])
117 129 end
118 130
119 131 def update
120 132 @user = User.find(params[:id])
121 - if @user.update_attributes(params[:user])
133 + if @user.update_attributes(user_params)
122 134 flash[:notice] = 'User was successfully updated.'
123 135 redirect_to :action => 'show', :id => @user
124 136 else
125 137 render :action => 'edit'
126 138 end
127 139 end
128 140
129 141 def destroy
130 142 User.find(params[:id]).destroy
131 143 redirect_to :action => 'index'
132 144 end
133 145
134 146 def user_stat
135 147 if params[:commit] == 'download csv'
136 148 @problems = Problem.all
137 149 else
138 - @problems = Problem.find_available_problems
150 + @problems = Problem.available_problems
139 151 end
140 - @users = User.includes(:contests, :contest_stat).where(enabled: true) #find(:all, :include => [:contests, :contest_stat]).where(enabled: true)
152 + @users = User.includes(:contests, :contest_stat).where(enabled: true)
141 153 @scorearray = Array.new
142 154 @users.each do |u|
143 155 ustat = Array.new
144 156 ustat[0] = u
145 157 @problems.each do |p|
146 158 sub = Submission.find_last_by_user_and_problem(u.id,p.id)
147 159 if (sub!=nil) and (sub.points!=nil) and p and p.full_score
148 160 ustat << [(sub.points.to_f*100/p.full_score).round, (sub.points>=p.full_score)]
149 161 else
150 162 ustat << [0,false]
151 163 end
152 164 end
153 165 @scorearray << ustat
154 166 end
155 167 if params[:commit] == 'download csv' then
156 168 csv = gen_csv_from_scorearray(@scorearray,@problems)
157 169 send_data csv, filename: 'last_score.csv'
158 170 else
159 171 render template: 'user_admin/user_stat'
160 172 end
161 173 end
162 174
163 175 def user_stat_max
164 176 if params[:commit] == 'download csv'
165 177 @problems = Problem.all
166 178 else
167 - @problems = Problem.find_available_problems
179 + @problems = Problem.available_problems
168 180 end
169 - @users = User.find(:all, :include => [:contests, :contest_stat])
181 + @users = User.includes(:contests).includes(:contest_stat).all
170 182 @scorearray = Array.new
171 183 #set up range from param
172 184 since_id = params.fetch(:since_id, 0).to_i
173 185 until_id = params.fetch(:until_id, 0).to_i
174 186 @users.each do |u|
175 187 ustat = Array.new
176 188 ustat[0] = u
177 189 @problems.each do |p|
178 190 max_points = 0
179 191 Submission.find_in_range_by_user_and_problem(u.id,p.id,since_id,until_id).each do |sub|
180 192 max_points = sub.points if sub and sub.points and (sub.points > max_points)
181 193 end
182 194 ustat << [(max_points.to_f*100/p.full_score).round, (max_points>=p.full_score)]
183 195 end
184 196 @scorearray << ustat
185 197 end
186 198
187 199 if params[:commit] == 'download csv' then
188 200 csv = gen_csv_from_scorearray(@scorearray,@problems)
189 201 send_data csv, filename: 'max_score.csv'
190 202 else
191 203 render template: 'user_admin/user_stat'
192 204 end
193 205 end
194 206
195 207 def import
196 208 if params[:file]==''
197 209 flash[:notice] = 'Error importing no file'
198 210 redirect_to :action => 'index' and return
199 211 end
200 212 import_from_file(params[:file])
201 213 end
202 214
203 215 def random_all_passwords
204 - users = User.find(:all)
216 + users = User.all
205 217 @prefix = params[:prefix] || ''
206 218 @non_admin_users = User.find_non_admin_with_prefix(@prefix)
207 219 @changed = false
208 220 if request.request_method == 'POST'
209 221 @non_admin_users.each do |user|
210 222 password = random_password
211 223 user.password = password
212 224 user.password_confirmation = password
213 225 user.save
214 226 end
215 227 @changed = true
216 228 end
217 229 end
218 230
219 231 # contest management
220 232
221 233 def contests
222 234 @contest, @users = find_contest_and_user_from_contest_id(params[:id])
223 235 @contests = Contest.enabled
224 236 end
225 237
226 238 def assign_from_list
227 239 contest_id = params[:users_contest_id]
228 240 org_contest, users = find_contest_and_user_from_contest_id(contest_id)
@@ -303,49 +315,49
303 315 user.contest_stat.reset_timer_and_save
304 316 end
305 317
306 318 if params[:notification_emails]
307 319 send_contest_update_notification_email(user, contest)
308 320 end
309 321
310 322 note << user.login
311 323 users << user
312 324 end
313 325 end
314 326
315 327 if params[:reset_timer]
316 328 logout_users(users)
317 329 end
318 330
319 331 flash[:notice] = 'User(s) ' + note.join(', ') +
320 332 ' were successfully modified. '
321 333 redirect_to :action => 'contest_management'
322 334 end
323 335
324 336 # admin management
325 337
326 338 def admin
327 - @admins = User.find(:all).find_all {|user| user.admin? }
339 + @admins = User.all.find_all {|user| user.admin? }
328 340 end
329 341
330 342 def grant_admin
331 343 login = params[:login]
332 344 user = User.find_by_login(login)
333 345 if user!=nil
334 346 admin_role = Role.find_by_name('admin')
335 347 user.roles << admin_role
336 348 else
337 349 flash[:notice] = 'Unknown user'
338 350 end
339 351 flash[:notice] = 'User added as admins'
340 352 redirect_to :action => 'admin'
341 353 end
342 354
343 355 def revoke_admin
344 356 user = User.find(params[:id])
345 357 if user==nil
346 358 flash[:notice] = 'Unknown user'
347 359 redirect_to :action => 'admin' and return
348 360 elsif user.login == 'root'
349 361 flash[:notice] = 'You cannot revoke admisnistrator permission from root.'
350 362 redirect_to :action => 'admin' and return
351 363 end
@@ -374,48 +386,81
374 386 redirect_to :action => 'mass_mailing' and return
375 387 end
376 388
377 389 mail_body = params[:email_body]
378 390 if !mail_body or mail_body.blank?
379 391 flash[:notice] = 'You entered an empty mail body.'
380 392 redirect_to :action => 'mass_mailing' and return
381 393 end
382 394
383 395 note = []
384 396 users = []
385 397 lines.split("\n").each do |line|
386 398 user = User.find_by_login(line.chomp)
387 399 if user
388 400 send_mail(user.email, mail_subject, mail_body)
389 401 note << user.login
390 402 end
391 403 end
392 404
393 405 flash[:notice] = 'User(s) ' + note.join(', ') +
394 406 ' were successfully modified. '
395 407 redirect_to :action => 'mass_mailing'
396 408 end
397 409
410 + #bulk manage
411 + def bulk_manage
412 +
413 + begin
414 + @users = User.where('login REGEXP ?',params[:regex]) if params[:regex]
415 + @users.count if @users #i don't know why I have to call count, but if I won't exception is not raised
416 + rescue Exception
417 + flash[:error] = 'Regular Expression is malformed'
418 + @users = nil
419 + end
420 +
421 + if params[:commit]
422 + @action = {}
423 + @action[:set_enable] = params[:enabled]
424 + @action[:enabled] = params[:enable] == "1"
425 + @action[:gen_password] = params[:gen_password]
426 + end
427 +
428 + if params[:commit] == "Perform"
429 + if @action[:set_enable]
430 + @users.update_all(enabled: @action[:enabled])
431 + end
432 + if @action[:gen_password]
433 + @users.each do |u|
434 + password = random_password
435 + u.password = password
436 + u.password_confirmation = password
437 + u.save
438 + end
439 + end
440 + end
441 + end
442 +
398 443 protected
399 444
400 445 def random_password(length=5)
401 446 chars = 'abcdefghijkmnopqrstuvwxyz23456789'
402 447 newpass = ""
403 448 length.times { newpass << chars[rand(chars.size-1)] }
404 449 return newpass
405 450 end
406 451
407 452 def import_from_file(f)
408 453 data_hash = YAML.load(f)
409 454 @import_log = ""
410 455
411 456 country_data = data_hash[:countries]
412 457 site_data = data_hash[:sites]
413 458 user_data = data_hash[:users]
414 459
415 460 # import country
416 461 countries = {}
417 462 country_data.each_pair do |id,country|
418 463 c = Country.find_by_name(country[:name])
419 464 if c!=nil
420 465 countries[id] = c
421 466 @import_log << "Found #{country[:name]}\n"
@@ -500,39 +545,44
500 545 if @contest
501 546 @users = @contest.users
502 547 else
503 548 @users = User.find_users_with_no_contest
504 549 end
505 550 return [@contest, @users]
506 551 end
507 552
508 553 def gen_csv_from_scorearray(scorearray,problem)
509 554 CSV.generate do |csv|
510 555 #add header
511 556 header = ['User','Name', 'Activated?', 'Logged in', 'Contest']
512 557 problem.each { |p| header << p.name }
513 558 header += ['Total','Passed']
514 559 csv << header
515 560 #add data
516 561 scorearray.each do |sc|
517 562 total = num_passed = 0
518 563 row = Array.new
519 564 sc.each_index do |i|
520 565 if i == 0
521 566 row << sc[i].login
522 567 row << sc[i].full_name
523 568 row << sc[i].activated
524 - row << (sc[i].try(:contest_stat).try(:started_at).nil? 'no' : 'yes')
569 + row << (sc[i].try(:contest_stat).try(:started_at).nil? ? 'no' : 'yes')
525 570 row << sc[i].contests.collect {|c| c.name}.join(', ')
526 571 else
527 572 row << sc[i][0]
528 573 total += sc[i][0]
529 574 num_passed += 1 if sc[i][1]
530 575 end
531 576 end
532 577 row << total
533 578 row << num_passed
534 579 csv << row
535 580 end
536 581 end
537 582 end
583 +
584 + private
585 + def user_params
586 + params.require(:user).permit(:login,:password,:password_confirmation,:email, :alias, :full_name,:remark)
587 + end
538 588 end
@@ -31,49 +31,49
31 31 end
32 32
33 33 def chg_passwd
34 34 user = User.find(session[:user_id])
35 35 user.password = params[:passwd]
36 36 user.password_confirmation = params[:passwd_verify]
37 37 if user.save
38 38 flash[:notice] = 'password changed'
39 39 else
40 40 flash[:notice] = 'Error: password changing failed'
41 41 end
42 42 redirect_to :action => 'index'
43 43 end
44 44
45 45 def new
46 46 @user = User.new
47 47 render :action => 'new', :layout => 'empty'
48 48 end
49 49
50 50 def register
51 51 if(params[:cancel])
52 52 redirect_to :controller => 'main', :action => 'login'
53 53 return
54 54 end
55 - @user = User.new(params[:user])
55 + @user = User.new(user_params)
56 56 @user.password_confirmation = @user.password = User.random_password
57 57 @user.activated = false
58 58 if (@user.valid?) and (@user.save)
59 59 if send_confirmation_email(@user)
60 60 render :action => 'new_splash', :layout => 'empty'
61 61 else
62 62 @admin_email = GraderConfiguration['system.admin_email']
63 63 render :action => 'email_error', :layout => 'empty'
64 64 end
65 65 else
66 66 @user.errors.add(:base,"Email cannot be blank") if @user.email==''
67 67 render :action => 'new', :layout => 'empty'
68 68 end
69 69 end
70 70
71 71 def confirm
72 72 login = params[:login]
73 73 key = params[:activation]
74 74 @user = User.find_by_login(login)
75 75 if (@user) and (@user.verify_activation_key(key))
76 76 if @user.valid? # check uniquenss of email
77 77 @user.activated = true
78 78 @user.save
79 79 @result = :successful
@@ -188,27 +188,31
188 188 :contest_name => contest_name,
189 189 :login => user.login,
190 190 :password => user.password,
191 191 :admin_email => GraderConfiguration['system.admin_email']
192 192 })
193 193
194 194 logger.info mail_body
195 195
196 196 send_mail(user.email, mail_subject, mail_body)
197 197 end
198 198
199 199 # allow viewing of regular user profile only when options allow so
200 200 # only admins can view admins profile
201 201 def profile_authorization
202 202 #if view admins' profile, allow only admin
203 203 return false unless(params[:id])
204 204 user = User.find(params[:id])
205 205 return false unless user
206 206 return admin_authorization if user.admin?
207 207 return true if GraderConfiguration["right.user_view_submission"]
208 208
209 209 #finally, we allow only admin
210 210 admin_authorization
211 211 end
212 -
212 +
213 + private
214 + def user_params
215 + params.require(:user).permit(:login, :full_name, :email)
216 + end
213 217
214 218 end
@@ -7,49 +7,49
7 7 right_menu = ''
8 8 user = User.find(session[:user_id])
9 9
10 10 if (user!=nil) and (GraderConfiguration.show_tasks_to?(user))
11 11 left_menu << add_menu("#{I18n.t 'menu.tasks'}", 'tasks', 'list')
12 12 left_menu << add_menu("#{I18n.t 'menu.submissions'}", 'main', 'submission')
13 13 left_menu << add_menu("#{I18n.t 'menu.test'}", 'test', 'index')
14 14 end
15 15
16 16 if GraderConfiguration['right.user_hall_of_fame']
17 17 left_menu << add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
18 18 end
19 19
20 20 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
21 21 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
22 22 if GraderConfiguration['system.user_setting_enabled']
23 23 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
24 24 end
25 25 right_menu << add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
26 26
27 27
28 28 result = content_tag(:ul,left_menu.html_safe,class: 'nav navbar-nav') + content_tag(:ul,right_menu.html_safe,class: 'nav navbar-nav navbar-right')
29 29 end
30 30
31 - def add_menu(title, controller, action,html_option = {})
31 + def add_menu(title, controller, action, html_option = {})
32 32 link_option = {controller: controller, action: action}
33 33 html_option[:class] = (html_option[:class] || '') + " active" if current_page?(link_option)
34 34 content_tag(:li, link_to(title,link_option),html_option)
35 35 end
36 36
37 37 def user_header
38 38 menu_items = ''
39 39 user = User.find(session[:user_id])
40 40
41 41 if (user!=nil) and (session[:admin])
42 42 # admin menu
43 43 menu_items << "<b>Administrative task:</b> "
44 44 append_to menu_items, '[Announcements]', 'announcements', 'index'
45 45 append_to menu_items, '[Msg console]', 'messages', 'console'
46 46 append_to menu_items, '[Problems]', 'problems', 'index'
47 47 append_to menu_items, '[Users]', 'user_admin', 'index'
48 48 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
49 49 append_to menu_items, '[Report]', 'report', 'multiple_login'
50 50 append_to menu_items, '[Graders]', 'graders', 'list'
51 51 append_to menu_items, '[Contests]', 'contest_management', 'index'
52 52 append_to menu_items, '[Sites]', 'sites', 'index'
53 53 append_to menu_items, '[System config]', 'configurations', 'index'
54 54 menu_items << "<br/>"
55 55 end
@@ -175,25 +175,47
175 175 result = <<TITLEBAR
176 176 <div class="title">
177 177 <table>
178 178 #{header}
179 179 <tr>
180 180 <td class="left-col">
181 181 #{user.full_name}<br/>
182 182 #{t 'title_bar.current_time'} #{format_short_time(Time.zone.now)}
183 183 #{time_left}
184 184 <br/>
185 185 </td>
186 186 <td class="right-col">#{contest_name}</td>
187 187 </tr>
188 188 </table>
189 189 </div>
190 190 TITLEBAR
191 191 result.html_safe
192 192 end
193 193
194 194 def markdown(text)
195 195 markdown = RDiscount.new(text)
196 196 markdown.to_html.html_safe
197 197 end
198 198
199 +
200 + BOOTSTRAP_FLASH_MSG = {
201 + success: 'alert-success',
202 + error: 'alert-danger',
203 + alert: 'alert-block',
204 + notice: 'alert-info'
205 + }
206 +
207 + def bootstrap_class_for(flash_type)
208 + BOOTSTRAP_FLASH_MSG.fetch(flash_type.to_sym, flash_type.to_s)
209 + end
210 +
211 + def flash_messages
212 + flash.each do |msg_type, message|
213 + concat(content_tag(:div, message, class: "alert #{bootstrap_class_for(msg_type)} fade in") do
214 + concat content_tag(:button, 'x', class: "close", data: { dismiss: 'alert' })
215 + concat message
216 + end)
217 + end
218 + nil
219 + end
220 +
199 221 end
@@ -1,21 +1,15
1 1 class Announcement < ActiveRecord::Base
2 2
3 - def self.find_published(contest_started=false)
3 + def self.published(contest_started=false)
4 4 if contest_started
5 - Announcement.find(:all,
6 - :conditions => "(published = 1) AND (frontpage = 0)",
7 - :order => "created_at DESC")
5 + where(published: true).where(frontpage: false).order(created_at: :desc)
8 6 else
9 - Announcement.find(:all,
10 - :conditions => "(published = 1) AND (frontpage = 0) AND (contest_only = 0)",
11 - :order => "created_at DESC")
7 + where(published: true).where(frontpage: false).where(contest_only: false).order(created_at: :desc)
12 8 end
13 9 end
14 10
15 - def self.find_for_frontpage
16 - Announcement.find(:all,
17 - :conditions => "(published = 1) AND (frontpage = 1)",
18 - :order => "created_at DESC")
11 + def self.frontpage
12 + where(published: 1).where(frontpage: 1).order(created_at: :desc)
19 13 end
20 14
21 15 end
@@ -1,8 +1,8
1 1 class Contest < ActiveRecord::Base
2 2
3 3 has_and_belongs_to_many :users
4 4 has_and_belongs_to_many :problems
5 5
6 - scope :enabled, :conditions => {:enabled => true}
6 + scope :enabled, -> { where(enabled: true) }
7 7
8 8 end
@@ -1,36 +1,38
1 1 require 'yaml'
2 2
3 3 #
4 4 # This class also contains various login of the system.
5 5 #
6 6 class GraderConfiguration < ActiveRecord::Base
7 7
8 8 SYSTEM_MODE_CONF_KEY = 'system.mode'
9 9 TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout'
10 10 MULTICONTESTS_KEY = 'system.multicontests'
11 11 CONTEST_TIME_LIMIT_KEY = 'contest.time_limit'
12 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 16 cattr_accessor :config_cache
15 17 cattr_accessor :task_grading_info_cache
16 18 cattr_accessor :contest_time_str
17 19 cattr_accessor :contest_time
18 20
19 21 GraderConfiguration.config_cache = nil
20 22 GraderConfiguration.task_grading_info_cache = nil
21 23
22 24 def self.config_cached?
23 25 (defined? CONFIGURATION_CACHE_ENABLED) and (CONFIGURATION_CACHE_ENABLED)
24 26 end
25 27
26 28 def self.get(key)
27 29 if GraderConfiguration.config_cached?
28 30 if GraderConfiguration.config_cache == nil
29 31 self.read_config
30 32 end
31 33 return GraderConfiguration.config_cache[key]
32 34 else
33 35 return GraderConfiguration.read_one_key(key)
34 36 end
35 37 end
36 38
@@ -49,48 +51,52
49 51 #
50 52 # View decision
51 53 #
52 54 def self.show_submitbox_to?(user)
53 55 mode = get(SYSTEM_MODE_CONF_KEY)
54 56 return false if mode=='analysis'
55 57 if (mode=='contest')
56 58 return false if (user.site!=nil) and
57 59 ((user.site.started!=true) or (user.site.finished?))
58 60 end
59 61 return true
60 62 end
61 63
62 64 def self.show_tasks_to?(user)
63 65 if time_limit_mode?
64 66 return false if not user.contest_started?
65 67 end
66 68 return true
67 69 end
68 70
69 71 def self.show_grading_result
70 72 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
71 73 end
72 74
75 + def self.show_testcase
76 + return get(VIEW_TESTCASE)
77 + end
78 +
73 79 def self.allow_test_request(user)
74 80 mode = get(SYSTEM_MODE_CONF_KEY)
75 81 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
76 82 if (mode=='contest')
77 83 return false if ((user.site!=nil) and
78 84 ((user.site.started!=true) or
79 85 (early_timeout and (user.site.time_left < 30.minutes))))
80 86 end
81 87 return false if mode=='analysis'
82 88 return true
83 89 end
84 90
85 91 def self.task_grading_info
86 92 if GraderConfiguration.task_grading_info_cache==nil
87 93 read_grading_info
88 94 end
89 95 return GraderConfiguration.task_grading_info_cache
90 96 end
91 97
92 98 def self.standard_mode?
93 99 return get(SYSTEM_MODE_CONF_KEY) == 'standard'
94 100 end
95 101
96 102 def self.contest_mode?
@@ -131,47 +137,47
131 137 else
132 138 GraderConfiguration.contest_time = nil
133 139 end
134 140 end
135 141 return GraderConfiguration.contest_time
136 142 end
137 143
138 144 protected
139 145
140 146 def self.convert_type(val,type)
141 147 case type
142 148 when 'string'
143 149 return val
144 150
145 151 when 'integer'
146 152 return val.to_i
147 153
148 154 when 'boolean'
149 155 return (val=='true')
150 156 end
151 157 end
152 158
153 159 def self.read_config
154 160 GraderConfiguration.config_cache = {}
155 - GraderConfiguration.find(:all).each do |conf|
161 + GraderConfiguration.all.each do |conf|
156 162 key = conf.key
157 163 val = conf.value
158 164 GraderConfiguration.config_cache[key] = GraderConfiguration.convert_type(val,conf.value_type)
159 165 end
160 166 end
161 167
162 168 def self.read_one_key(key)
163 169 conf = GraderConfiguration.find_by_key(key)
164 170 if conf
165 171 return GraderConfiguration.convert_type(conf.value,conf.value_type)
166 172 else
167 173 return nil
168 174 end
169 175 end
170 176
171 177 def self.read_grading_info
172 178 f = File.open(TASK_GRADING_INFO_FILENAME)
173 179 GraderConfiguration.task_grading_info_cache = YAML.load(f)
174 180 f.close
175 181 end
176 182
177 183 end
@@ -1,67 +1,58
1 1 class GraderProcess < ActiveRecord::Base
2 2
3 3 def self.find_by_host_and_pid(host,pid)
4 - return GraderProcess.find(:first,
5 - :conditions => {
6 - :host => host,
7 - :pid => pid
8 - })
4 + return GraderProcess.where(host:host).where(pid: pid).first
9 5 end
10 6
11 7 def self.register(host,pid,mode)
12 8 grader = GraderProcess.find_by_host_and_pid(host,pid)
13 9 if grader
14 10 grader.mode = mode
15 11 grader.active = nil
16 12 grader.task_id = nil
17 13 grader.task_type = nil
18 14 grader.terminated = false
19 15 grader.save
20 16 else
21 17 grader = GraderProcess.create(:host => host,
22 18 :pid => pid,
23 19 :mode => mode,
24 20 :terminated => false)
25 21 end
26 22 grader
27 23 end
28 24
29 25 def self.find_running_graders
30 - GraderProcess.find(:all,
31 - :conditions => {:terminated => 0})
26 + where(terminated: false)
32 27 end
33 28
34 29 def self.find_terminated_graders
35 - GraderProcess.find(:all,
36 - :conditions => "`terminated`")
30 + where(terminated: true)
37 31 end
38 32
39 33 def self.find_stalled_process
40 - GraderProcess.find(:all,
41 - :conditions => ["(`terminated` = 0) AND active AND " +
42 - "(updated_at < ?)",
43 - Time.now.gmtime - GraderProcess.stalled_time])
34 + where(terminated: false).where(active: true).where("updated_at < ?",Time.now.gmtime - GraderProcess.stalled_time)
44 35 end
45 36
46 37 def report_active(task=nil)
47 38 self.active = true
48 39 if task!=nil
49 40 self.task_id = task.id
50 41 self.task_type = task.class.to_s
51 42 else
52 43 self.task_id = nil
53 44 self.task_type = nil
54 45 end
55 46 self.save
56 47 end
57 48
58 49 def report_inactive(task=nil)
59 50 self.active = false
60 51 if task!=nil
61 52 self.task_id = task.id
62 53 self.task_type = task.class.to_s
63 54 else
64 55 self.task_id = nil
65 56 self.task_type = nil
66 57 end
67 58 self.save
@@ -1,24 +1,24
1 1 class Language < ActiveRecord::Base
2 2
3 3 @@languages_by_ext = {}
4 4
5 5 def self.cache_ext_hash
6 6 @@languages_by_ext = {}
7 - Language.find(:all).each do |language|
7 + Language.all.each do |language|
8 8 language.common_ext.split(',').each do |ext|
9 9 @@languages_by_ext[ext] = language
10 10 end
11 11 end
12 12 end
13 13
14 14 def self.find_by_extension(ext)
15 15 if @@languages_by_ext.length == 0
16 16 Language.cache_ext_hash
17 17 end
18 18 if @@languages_by_ext.has_key? ext
19 19 return @@languages_by_ext[ext]
20 20 else
21 21 return nil
22 22 end
23 23 end
24 24 end
@@ -1,5 +1,4
1 1 class Login < ActiveRecord::Base
2 2 belongs_to :user
3 3
4 - attr_accessible :ip_address, :logged_in_at, :user_id
5 4 end
@@ -2,52 +2,50
2 2
3 3 belongs_to :sender, :class_name => "User"
4 4 belongs_to :receiver, :class_name => "User"
5 5
6 6 belongs_to :replying_message, :class_name => "Message"
7 7
8 8 # commented manually do it
9 9 #
10 10 #has_many :replied_messages, {
11 11 # :class_name => "Message",
12 12 # :foreign_key => "replying_message_id"
13 13 #}
14 14 #
15 15
16 16 attr_accessor :replied_messages
17 17
18 18 def self.find_all_sent_by_user(user)
19 19 messages = user.messages
20 20 replied_messages = user.replied_messages
21 21 Message.build_replying_message_hierarchy messages, replied_messages
22 22 return messages
23 23 end
24 24
25 25 def self.find_all_system_unreplied_messages
26 - self.find(:all,
27 - :conditions => 'ISNULL(receiver_id) ' +
28 - 'AND (ISNULL(replied) OR replied=0)',
29 - :order => 'created_at')
26 + where('ISNULL(receiver_id) ' +
27 + 'AND (ISNULL(replied) OR replied=0)')
30 28 end
31 29
32 30 def self.build_replying_message_hierarchy(*args)
33 31 # manually build replies hierarchy (to improve efficiency)
34 32 all_messages = {}
35 33
36 34 args.each do |collection|
37 35 collection.each do |m|
38 36 all_messages[m.id] = m
39 37 m.replied_messages = []
40 38 end
41 39 end
42 40
43 41 all_messages.each_value do |m|
44 42 rep_id = m.replying_message_id
45 43 if all_messages[rep_id]!=nil
46 44 all_messages[rep_id].add_replied_message(m)
47 45 end
48 46 end
49 47 end
50 48
51 49 def add_replied_message(m)
52 50 if @replied_messages==nil
53 51 @replied_messages = [m]
@@ -1,87 +1,90
1 1 class Problem < ActiveRecord::Base
2 2
3 3 belongs_to :description
4 4 has_and_belongs_to_many :contests, :uniq => true
5 5 has_many :test_pairs, :dependent => :delete_all
6 6 has_many :testcases, :dependent => :destroy
7 7
8 8 validates_presence_of :name
9 - validates_format_of :name, :with => /^\w+$/
9 + validates_format_of :name, :with => /\A\w+\z/
10 10 validates_presence_of :full_name
11 11
12 - scope :available, :conditions => {:available => true}
12 + scope :available, -> { where(available: true) }
13 13
14 14 DEFAULT_TIME_LIMIT = 1
15 15 DEFAULT_MEMORY_LIMIT = 32
16 16
17 - def self.find_available_problems
18 - Problem.available.all(:order => "date_added DESC, name ASC")
17 + def self.available_problems
18 + available.order(date_added: :desc).order(:name)
19 + #Problem.available.all(:order => "date_added DESC, name ASC")
19 20 end
20 21
21 22 def self.create_from_import_form_params(params, old_problem=nil)
22 23 org_problem = old_problem || Problem.new
23 24 import_params, problem = Problem.extract_params_and_check(params,
24 25 org_problem)
25 26
26 27 if !problem.errors.empty?
27 28 return problem, 'Error importing'
28 29 end
29 30
30 31 problem.full_score = 100
31 32 problem.date_added = Time.new
32 33 problem.test_allowed = true
33 34 problem.output_only = false
34 35 problem.available = false
35 36
36 37 if not problem.save
37 38 return problem, 'Error importing'
38 39 end
39 40
40 41 import_to_db = params.has_key? :import_to_db
41 42
42 43 importer = TestdataImporter.new(problem)
43 44
44 45 if not importer.import_from_file(import_params[:file],
45 46 import_params[:time_limit],
46 47 import_params[:memory_limit],
47 48 import_params[:checker_name],
48 49 import_to_db)
49 50 problem.errors.add(:base,'Import error.')
50 51 end
51 52
52 53 return problem, importer.log_msg
53 54 end
54 55
55 56 def self.download_file_basedir
56 57 return "#{Rails.root}/data/tasks"
57 58 end
58 59
59 60 def get_submission_stat
60 61 result = Hash.new
61 62 #total number of submission
62 63 result[:total_sub] = Submission.where(problem_id: self.id).count
63 - result[:attempted_user] = Submission.where(problem_id: self.id).group_by(:user_id)
64 + result[:attempted_user] = Submission.where(problem_id: self.id).group(:user_id)
65 + result[:pass] = Submission.where(problem_id: self.id).where("points >= ?",self.full_score).count
66 + return result
64 67 end
65 68
66 69 def long_name
67 70 "[#{name}] #{full_name}"
68 71 end
69 72
70 73 protected
71 74
72 75 def self.to_i_or_default(st, default)
73 76 if st!=''
74 77 result = st.to_i
75 78 end
76 79 result ||= default
77 80 end
78 81
79 82 def self.to_f_or_default(st, default)
80 83 if st!=''
81 84 result = st.to_f
82 85 end
83 86 result ||= default
84 87 end
85 88
86 89 def self.extract_params_and_check(params, problem)
87 90 time_limit = Problem.to_f_or_default(params[:time_limit],
@@ -1,92 +1,81
1 1 class Submission < ActiveRecord::Base
2 2
3 3 belongs_to :language
4 4 belongs_to :problem
5 5 belongs_to :user
6 6
7 7 before_validation :assign_problem
8 8 before_validation :assign_language
9 9
10 10 validates_presence_of :source
11 11 validates_length_of :source, :maximum => 100_000, :allow_blank => true, :message => 'too long'
12 12 validates_length_of :source, :minimum => 1, :allow_blank => true, :message => 'too short'
13 13 validate :must_have_valid_problem
14 14 validate :must_specify_language
15 15
16 + has_one :task
17 +
16 18 before_save :assign_latest_number_if_new_recond
17 19
18 20 def self.find_last_by_user_and_problem(user_id, problem_id)
19 - last_sub = find(:first,
20 - :conditions => {:user_id => user_id,
21 - :problem_id => problem_id},
22 - :order => 'number DESC')
23 - return last_sub
21 + where("user_id = ? AND problem_id = ?",user_id,problem_id).last
24 22 end
25 23
26 24 def self.find_all_last_by_problem(problem_id)
27 25 # need to put in SQL command, maybe there's a better way
28 26 Submission.includes(:user).find_by_sql("SELECT * FROM submissions " +
29 27 "WHERE id = " +
30 28 "(SELECT MAX(id) FROM submissions AS subs " +
31 29 "WHERE subs.user_id = submissions.user_id AND " +
32 30 "problem_id = " + problem_id.to_s + " " +
33 31 "GROUP BY user_id) " +
34 32 "ORDER BY user_id")
35 33 end
36 34
37 35 def self.find_in_range_by_user_and_problem(user_id, problem_id,since_id,until_id)
38 36 records = Submission.where(problem_id: problem_id,user_id: user_id)
39 37 records = records.where('id >= ?',since_id) if since_id > 0
40 38 records = records.where('id <= ?',until_id) if until_id > 0
41 39 records.all
42 40 end
43 41
44 42 def self.find_last_for_all_available_problems(user_id)
45 43 submissions = Array.new
46 - problems = Problem.find_available_problems
44 + problems = Problem.available_problems
47 45 problems.each do |problem|
48 46 sub = Submission.find_last_by_user_and_problem(user_id, problem.id)
49 47 submissions << sub if sub!=nil
50 48 end
51 49 submissions
52 50 end
53 51
54 52 def self.find_by_user_problem_number(user_id, problem_id, number)
55 - Submission.find(:first,
56 - :conditions => {
57 - :user_id => user_id,
58 - :problem_id => problem_id,
59 - :number => number
60 - })
53 + where("user_id = ? AND problem_id = ? AND number = ?",user_id,problem_id,number).first
61 54 end
62 55
63 56 def self.find_all_by_user_problem(user_id, problem_id)
64 - Submission.find(:all,
65 - :conditions => {
66 - :user_id => user_id,
67 - :problem_id => problem_id,
68 - })
57 + where("user_id = ? AND problem_id = ?",user_id,problem_id)
69 58 end
70 59
71 60 def download_filename
72 61 if self.problem.output_only
73 62 return self.source_filename
74 63 else
75 64 timestamp = self.submitted_at.localtime.strftime("%H%M%S")
76 65 return "#{self.problem.name}-#{timestamp}.#{self.language.ext}"
77 66 end
78 67 end
79 68
80 69 protected
81 70
82 71 def self.find_option_in_source(option, source)
83 72 if source==nil
84 73 return nil
85 74 end
86 75 i = 0
87 76 source.each_line do |s|
88 77 if s =~ option
89 78 words = s.split
90 79 return words[1]
91 80 end
92 81 i = i + 1
@@ -1,3 +1,3
1 1 class SubmissionViewLog < ActiveRecord::Base
2 - attr_accessible :submission_id, :user_id
2 + #attr_accessible :submission_id, :user_id
3 3 end
@@ -27,42 +27,39
27 27 def status_complete
28 28 self.status = Task::STATUS_COMPLETE
29 29 end
30 30
31 31 def status_complete!
32 32 status_complete
33 33 self.save
34 34 end
35 35
36 36 def status_str
37 37 case self.status
38 38 when Task::STATUS_INQUEUE
39 39 "inqueue"
40 40 when Task::STATUS_GRADING
41 41 "grading"
42 42 when Task::STATUS_COMPLETE
43 43 "complete"
44 44 end
45 45 end
46 46
47 47 def self.get_inqueue_and_change_status(status)
48 48 task = nil
49 49 begin
50 50 Task.transaction do
51 - task = Task.find(:first,
52 - :order => "created_at",
53 - :conditions => {:status=> Task::STATUS_INQUEUE},
54 - :lock => true)
51 + task = Task.where(status: Task::STATUS_INQUEUE).lock(true).first
55 52 if task!=nil
56 53 task.status = status
57 54 task.save!
58 55 end
59 56 end
60 57
61 58 rescue
62 59 task = nil
63 60
64 61 end
65 62 task
66 63 end
67 64
68 65 end
@@ -1,67 +1,64
1 1 #
2 2 # A TestRequest is a composition of submission with user's testdata.
3 3 #
4 4 # Note about TestRequest#problem: Usually, A TestRequest has to be
5 5 # associated with a problem, so that execution environment can be
6 6 # determined. However, to be more flexible, we have to ensure that
7 7 # it works as well with problem=nil. In this case, we shall provide
8 8 # a "default" execution environment for it. This can be done
9 9 # seamlessly by using TestRequest#problem_name or
10 10 # TestRequest#name_of(problem) when retrieving the name of the
11 11 # problem: #name_of would return problem.name when problem!=nil and
12 12 # it would return "default" when problem=nil, #problem_name just
13 13 # call #name_of.
14 14 #
15 15
16 16 require 'fileutils'
17 17
18 18 class TestRequest < Task
19 -
20 - set_table_name "test_requests"
19 + self.table_name = "test_requests"
21 20
22 21 belongs_to :user
23 22 belongs_to :problem
24 23 belongs_to :submission
25 24
26 25 validates_presence_of :submission
27 26 validate :must_have_valid_problem
28 27
29 28 def problem_name
30 29 TestRequest.name_of(self.problem)
31 30 end
32 31
33 32 def language
34 33 self.submission.language
35 34 end
36 35
37 36 def self.get_inqueue_and_change_status(status)
38 37 # since there will be only one grader grading TestRequest
39 38 # we do not need locking (hopefully)
40 39
41 - test_request = TestRequest.find(:first,
42 - :order => "created_at",
43 - :conditions => {:status=> Task::STATUS_INQUEUE})
40 + test_request = TestRequest.where(status: Task::STATUS_INQUEUE).first
44 41 if test_request!=nil
45 42 test_request.status = status
46 43 test_request.save!
47 44 end
48 45
49 46 test_request
50 47 end
51 48
52 49 # interfacing with form
53 50 def self.new_from_form_params(user,params)
54 51 test_request = TestRequest.new
55 52 test_request.user = user
56 53 begin
57 54 problem = Problem.find(params[:problem_id])
58 55 rescue ActiveRecord::RecordNotFound
59 56 problem = nil
60 57 end
61 58 test_request.problem = problem
62 59 if problem!=nil
63 60 test_request.submission =
64 61 Submission.find_by_user_problem_number(user.id,
65 62 problem.id,
66 63 params[:submission_number])
67 64 else
@@ -1,4 +1,4
1 1 class Testcase < ActiveRecord::Base
2 2 belongs_to :problem
3 - attr_accessible :group, :input, :num, :score, :sol
3 + #attr_accessible :group, :input, :num, :score, :sol
4 4 end
@@ -1,58 +1,56
1 1 require 'digest/sha1'
2 2 require 'net/pop'
3 3 require 'net/https'
4 4 require 'net/http'
5 5 require 'json'
6 6
7 7 class User < ActiveRecord::Base
8 8
9 9 has_and_belongs_to_many :roles
10 10
11 - has_many :test_requests, :order => "submitted_at DESC"
11 + has_many :test_requests, -> {order(submitted_at: DESC)}
12 12
13 - has_many :messages,
13 + has_many :messages, -> { order(created_at: DESC) },
14 14 :class_name => "Message",
15 - :foreign_key => "sender_id",
16 - :order => 'created_at DESC'
15 + :foreign_key => "sender_id"
17 16
18 - has_many :replied_messages,
17 + has_many :replied_messages, -> { order(created_at: DESC) },
19 18 :class_name => "Message",
20 - :foreign_key => "receiver_id",
21 - :order => 'created_at DESC'
19 + :foreign_key => "receiver_id"
22 20
23 21 has_one :contest_stat, :class_name => "UserContestStat", :dependent => :destroy
24 22
25 23 belongs_to :site
26 24 belongs_to :country
27 25
28 - has_and_belongs_to_many :contests, :uniq => true, :order => 'name'
26 + has_and_belongs_to_many :contests, -> { order(:name); uniq}
29 27
30 - scope :activated_users, :conditions => {:activated => true}
28 + scope :activated_users, -> {where activated: true}
31 29
32 30 validates_presence_of :login
33 31 validates_uniqueness_of :login
34 - validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
32 + validates_format_of :login, :with => /\A[\_A-Za-z0-9]+\z/
35 33 validates_length_of :login, :within => 3..30
36 34
37 35 validates_presence_of :full_name
38 36 validates_length_of :full_name, :minimum => 1
39 37
40 38 validates_presence_of :password, :if => :password_required?
41 39 validates_length_of :password, :within => 4..20, :if => :password_required?
42 40 validates_confirmation_of :password, :if => :password_required?
43 41
44 42 validates_format_of :email,
45 43 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
46 44 :if => :email_validation?
47 45 validate :uniqueness_of_email_from_activated_users,
48 46 :if => :email_validation?
49 47 validate :enough_time_interval_between_same_email_registrations,
50 48 :if => :email_validation?
51 49
52 50 # these are for ytopc
53 51 # disable for now
54 52 #validates_presence_of :province
55 53
56 54 attr_accessor :password
57 55
58 56 before_save :encrypt_new_password
@@ -108,56 +106,56
108 106
109 107 def alias_for_editing=(e)
110 108 self.alias=e
111 109 end
112 110
113 111 def activation_key
114 112 if self.hashed_password==nil
115 113 encrypt_new_password
116 114 end
117 115 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
118 116 end
119 117
120 118 def verify_activation_key(key)
121 119 key == activation_key
122 120 end
123 121
124 122 def self.random_password(length=5)
125 123 chars = 'abcdefghjkmnopqrstuvwxyz'
126 124 password = ''
127 125 length.times { password << chars[rand(chars.length - 1)] }
128 126 password
129 127 end
130 128
131 129 def self.find_non_admin_with_prefix(prefix='')
132 - users = User.find(:all)
130 + users = User.all
133 131 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
134 132 end
135 133
136 134 # Contest information
137 135
138 136 def self.find_users_with_no_contest()
139 - users = User.find(:all)
137 + users = User.all
140 138 return users.find_all { |u| u.contests.length == 0 }
141 139 end
142 140
143 141
144 142 def contest_time_left
145 143 if GraderConfiguration.contest_mode?
146 144 return nil if site==nil
147 145 return site.time_left
148 146 elsif GraderConfiguration.indv_contest_mode?
149 147 time_limit = GraderConfiguration.contest_time_limit
150 148 if time_limit == nil
151 149 return nil
152 150 end
153 151 if contest_stat==nil or contest_stat.started_at==nil
154 152 return (Time.now.gmtime + time_limit) - Time.now.gmtime
155 153 else
156 154 finish_time = contest_stat.started_at + time_limit
157 155 current_time = Time.now.gmtime
158 156 if current_time > finish_time
159 157 return 0
160 158 else
161 159 return finish_time - current_time
162 160 end
163 161 end
@@ -212,51 +210,60
212 210 end
213 211 end
214 212 return false
215 213 end
216 214
217 215 def available_problems_group_by_contests
218 216 contest_problems = []
219 217 pin = {}
220 218 contests.enabled.each do |contest|
221 219 available_problems = contest.problems.available
222 220 contest_problems << {
223 221 :contest => contest,
224 222 :problems => available_problems
225 223 }
226 224 available_problems.each {|p| pin[p.id] = true}
227 225 end
228 226 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
229 227 contest_problems << {
230 228 :contest => nil,
231 229 :problems => other_avaiable_problems
232 230 }
233 231 return contest_problems
234 232 end
235 233
234 + def solve_all_available_problems?
235 + available_problems.each do |p|
236 + u = self
237 + sub = Submission.find_last_by_user_and_problem(u.id,p.id)
238 + return false if !p or !sub or sub.points < p.full_score
239 + end
240 + return true
241 + end
242 +
236 243 def available_problems
237 244 if not GraderConfiguration.multicontests?
238 - return Problem.find_available_problems
245 + return Problem.available_problems
239 246 else
240 247 contest_problems = []
241 248 pin = {}
242 249 contests.enabled.each do |contest|
243 250 contest.problems.available.each do |problem|
244 251 if not pin.has_key? problem.id
245 252 contest_problems << problem
246 253 end
247 254 pin[problem.id] = true
248 255 end
249 256 end
250 257 other_avaiable_problems = Problem.available.find_all {|p| pin[p.id]==nil and p.contests.length==0}
251 258 return contest_problems + other_avaiable_problems
252 259 end
253 260 end
254 261
255 262 def can_view_problem?(problem)
256 263 if not GraderConfiguration.multicontests?
257 264 return problem.available
258 265 else
259 266 return problem_in_user_contests? problem
260 267 end
261 268 end
262 269
@@ -1,26 +1,26
1 1
2 2 %tr
3 3 %td{:align => "center"}
4 - = submission_counter+1
5 - %td{:align => "center"}
4 + = submission.number
5 + %td.text-right
6 6 = link_to "##{submission.id}", submission_path(submission.id)
7 7 %td
8 8 = l submission.submitted_at, format: :long
9 9 = "( #{time_ago_in_words(submission.submitted_at)} ago)"
10 10 %td
11 11 = submission.source_filename
12 12 = " (#{submission.language.pretty_name}) "
13 13 = link_to('[load]',{:action => 'source', :id => submission.id})
14 14 %td
15 15 - if submission.graded_at
16 16 = "Graded at #{format_short_time(submission.graded_at)}."
17 17 %br/
18 18 = "Score: #{(submission.points*100/submission.problem.full_score).to_i} " if GraderConfiguration['ui.show_score']
19 19 = " ["
20 20 %tt
21 21 = submission.grader_comment
22 22 = "]"
23 23 %td
24 24 = render :partial => 'compiler_message', :locals => {:compiler_message => submission.compiler_message }
25 25 %td
26 26 = link_to 'Edit', edit_submission_path(submission.id), class: 'btn btn-success'
@@ -1,26 +1,26
1 1
2 2 - if submission.nil?
3 3 = "-"
4 4 - else
5 - - if submission.graded_at.nil?
5 + - unless submission.graded_at
6 6 = t 'main.submitted_at'
7 7 = format_short_time(submission.submitted_at.localtime)
8 8 - else
9 - = t 'main.graded_at'
10 - = "#{format_short_time(submission.graded_at.localtime)}, "
9 + %strong= t 'main.graded_at'
10 + = "#{format_short_time(submission.graded_at.localtime)} "
11 + %br
11 12 - if GraderConfiguration['ui.show_score']
12 - = t 'main.score'
13 + %strong=t 'main.score'
13 14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
14 15 = " ["
15 16 %tt
16 17 = submission.grader_comment
17 18 = "]"
19 + %br
20 + %strong View:
18 21 - if GraderConfiguration.show_grading_result
19 - = " | "
20 22 = link_to '[detailed result]', :action => 'result', :id => submission.id
21 - = " | "
22 - = link_to("[#{t 'main.cmp_msg'}]", {:action => 'compiler_msg', :id => submission.id}, {:popup => true})
23 - = " | "
24 - = link_to("[#{t 'main.src_link'}]",{:action => 'source', :id => submission.id})
25 - //= " | "
26 - //= link_to "[#{t 'main.submissions_link'}]", main_submission_path(submission.problem.id)
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.src_link'}", download_submission_path(submission.id), class: 'btn btn-xs btn-info'
25 + = link_to "#{t 'main.submissions_link'}", problem_submissions_path(problem_id), class: 'btn btn-xs btn-info'
26 +
@@ -1,34 +1,37
1 1 /- content_for :header do
2 2 / = javascript_include_tag 'local_jquery'
3 3
4 4 %h1 System configuration
5 5
6 - %table.info
7 - %tr.info-head
8 - %th Key
9 - %th Type
10 - %th Value
11 - %th Description
12 - - @configurations.each do |conf|
13 - - @grader_configuration = conf
14 - %tr{:class => cycle("info-odd", "info-even")}
15 - %td
16 - /= in_place_editor_field :grader_configuration, :key, {}, :rows=>1
17 - = @grader_configuration.key
18 - %td
19 - /= in_place_editor_field :grader_configuration, :value_type, {}, :rows=>1
20 - = @grader_configuration.value_type
21 - %td
22 - = best_in_place @grader_configuration, :value, ok_button: "ok", cancel_button: "cancel"
23 - %td= conf.description
6 + - @group.each do |g|
7 + %h2= g
8 + %table.table.table-striped
9 + %thead
10 + %th{style: 'width: 25%'} Key
11 + %th{style: 'width: 10%'}Type
12 + %th{style: 'width: 15%'} Value
13 + %th Description
14 + - @configurations.each do |conf|
15 + - next if conf.key[0...(conf.key.index('.'))] != g
16 + - @grader_configuration = conf
17 + %tr
18 + %td
19 + /= in_place_editor_field :grader_configuration, :key, {}, :rows=>1
20 + = @grader_configuration.key
21 + %td
22 + /= in_place_editor_field :grader_configuration, :value_type, {}, :rows=>1
23 + = @grader_configuration.value_type
24 + %td
25 + = best_in_place @grader_configuration, :value, ok_button: "ok", cancel_button: "cancel"
26 + %td= conf.description
24 27
25 28 - if GraderConfiguration.config_cached?
26 29 %br/
27 30 Your config is saved, but it does not automatically take effect.
28 31 %br/
29 32 If you have one mongrel process running, you can
30 33 = link_to '[click]', :action => 'reload'
31 34 here to reload.
32 35 %br/
33 36 If you have more than one process running, you should restart
34 37 them manually.
@@ -33,50 +33,50
33 33
34 34 %h2 Stalled graders
35 35
36 36 = render :partial => 'grader_list', :locals => {:grader_list => @stalled_processes}
37 37
38 38 %h2 Terminated graders
39 39
40 40 %p= link_to 'Clear data for terminated graders', { action: 'clear_terminated'}, class: 'btn btn-default', method: 'post'
41 41
42 42 = render :partial => 'grader_list', :locals => {:grader_list => @terminated_processes}
43 43 .col-md-6
44 44 %h2 Last 20 submissions
45 45 %table.table.table-striped.table-condensed
46 46 %thead
47 47 %th ID
48 48 %th User
49 49 %th Problem
50 50 %th Submitted
51 51 %th Graded
52 52 %th Result
53 53 %tbody
54 54 - @submission.each do |sub|
55 55 %tr.inactive
56 56 %td= link_to sub.id, submission_path(sub.id)
57 - %td= ("" unless sub.user) || link_to sub.try(:user).try(:full_name), stat_user_path(sub.user.id)
58 - %td= ("" unless sub.problem) || link_to sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id)
57 + %td= ("" unless sub.user) || link_to(sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
58 + %td= ("" unless sub.problem) || link_to(sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
59 59 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
60 60 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
61 61 %td= sub.grader_comment
62 62 %h2 Ungraded submission
63 63 %table.table.table-striped.table-condensed
64 64 %thead
65 65 %th ID
66 66 %th User
67 67 %th Problem
68 68 %th Submitted
69 69 %th Graded
70 70 %th Result
71 71 %tbody
72 72 - @backlog_submission.each do |sub|
73 73 %tr.inactive
74 74 %td= link_to sub.id, submission_path(sub.id)
75 - %td= ("" unless sub.user) || link_to sub.try(:user).try(:full_name), stat_user_path(sub.user.id)
76 - %td= ("" unless sub.problem) || link_to sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id)
75 + %td= ("" unless sub.user) || link_to( sub.try(:user).try(:full_name), stat_user_path(sub.user.id))
76 + %td= ("" unless sub.problem) || link_to( sub.try(:problem).try(:full_name), stat_problem_path(sub.problem.id))
77 77 %td= "#{time_ago_in_words(sub.submitted_at)} ago"
78 78 %td= sub.graded_at ? "#{time_ago_in_words(sub.graded_at)} ago" : " "
79 79 %td= sub.grader_comment
80 80
81 81
82 82
@@ -1,79 +1,88
1 1 %header.navbar.navbar-default.navbar-fixed-top
2 2 %nav
3 3 .container-fluid
4 4 .navbar-header
5 + %button.navbar-toggle.collapsed{ data: {toggle: 'collapse', target: '#navbar-collapse'} }
6 + %span.sr-only Togggle Navigation
7 + %span.icon-bar
8 + %span.icon-bar
9 + %span.icon-bar
5 10 %a.navbar-brand{href: main_list_path}
6 11 %span.glyphicon.glyphicon-home
7 12 MAIN
8 - .collapse.navbar-collapse
13 + .collapse.navbar-collapse#navbar-collapse
9 14 %ul.nav.navbar-nav
15 + / submission
10 16 - if (@current_user!=nil) and (GraderConfiguration.show_tasks_to?(@current_user))
11 - //= add_menu("#{I18n.t 'menu.tasks'}", 'tasks', 'list')
12 17 %li.dropdown
13 18 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
14 19 = "#{I18n.t 'menu.submissions'}"
15 20 %span.caret
16 21 %ul.dropdown-menu
17 - = add_menu("View", 'main', 'submission')
22 + = add_menu("View", 'submissions', 'index')
18 23 = add_menu("Self Test", 'test', 'index')
24 + / hall of fame
19 25 - if GraderConfiguration['right.user_hall_of_fame']
20 26 = add_menu("#{I18n.t 'menu.hall_of_fame'}", 'report', 'problem_hof')
21 27 / display MODE button (with countdown in contest mode)
22 28 - if GraderConfiguration.analysis_mode?
23 29 %div.navbar-btn.btn.btn-success#countdown= "ANALYSIS MODE"
24 30 - elsif GraderConfiguration.time_limit_mode?
25 31 - if @current_user.contest_finished?
26 32 %div.navbar-btn.btn.btn-danger#countdown= "Contest is over"
27 33 - elsif !@current_user.contest_started?
28 34 %div.navbar-btn.btn.btn-primary#countdown= (t 'title_bar.contest_not_started')
29 35 - else
30 36 %div.navbar-btn.btn.btn-primary#countdown asdf
31 37 :javascript
32 38 $("#countdown").countdown({until: "+#{@current_user.contest_time_left.to_i}s", layout: 'Time left: {hnn}:{mnn}:{snn}'});
33 39 / admin section
34 40 - if (@current_user!=nil) and (session[:admin])
41 + / management
35 42 %li.dropdown
36 43 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
37 44 Manage
38 45 %span.caret
39 46 %ul.dropdown-menu
40 47 = add_menu( 'Announcements', 'announcements', 'index')
41 48 = add_menu( 'Problems', 'problems', 'index')
42 49 = add_menu( 'Users', 'user_admin', 'index')
43 50 = add_menu( 'Graders', 'graders', 'list')
44 51 = add_menu( 'Message ', 'messages', 'console')
45 52 %li.divider{role: 'separator'}
46 53 = add_menu( 'System config', 'configurations', 'index')
47 54 %li.divider{role: 'separator'}
48 55 = add_menu( 'Sites', 'sites', 'index')
49 56 = add_menu( 'Contests', 'contest_management', 'index')
57 + / report
50 58 %li.dropdown
51 59 %a.dropdown-toggle{href: '#', data: {toggle:'dropdown'}, aria: {haspopup:"true", expanded:"false"}, role: "button"}
52 60 Report
53 61 %span.caret
54 62 %ul.dropdown-menu
55 - = add_menu( 'Results', 'report', 'current_score')
63 + = add_menu( 'Current Score', 'report', 'current_score')
64 + = add_menu( 'Score Report', 'report', 'max_score')
56 65 = add_menu( 'Report', 'report', 'multiple_login')
57 66 - if (ungraded = Submission.where('graded_at is null').where('submitted_at < ?', 1.minutes.ago).count) > 0
58 67 =link_to "#{ungraded} backlogs!",
59 68 grader_list_path,
60 69 class: 'navbar-btn btn btn-default btn-warning', data: {toggle: 'tooltip'},title: 'Number of ungraded submission'
61 70
62 71 %ul.nav.navbar-nav.navbar-right
63 72 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-question-sign')}".html_safe, 'main', 'help')
64 73 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-comment')}".html_safe, 'messages', 'list', {title: I18n.t('menu.messages'), data: {toggle: 'tooltip'}})
65 74 - if GraderConfiguration['system.user_setting_enabled']
66 75 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-cog')}".html_safe, 'users', 'index', {title: I18n.t('menu.settings'), data: {toggle: 'tooltip'}})
67 76 = add_menu("#{content_tag(:span,'',class: 'glyphicon glyphicon-log-out')} #{@current_user.full_name}".html_safe, 'main', 'login', {title: I18n.t('menu.log_out'), data: {toggle: 'tooltip'}})
68 77
69 78 /
70 79 - if (@current_user!=nil) and (session[:admin])
71 80 %nav.navbar.navbar-fixed-top.navbar-inverse.secondnavbar
72 81 .container-fluid
73 82 .collapse.navbar-collapse
74 83 %ul.nav.navbar-nav
75 84 = add_menu( '[Announcements]', 'announcements', 'index')
76 85 = add_menu( '[Msg console]', 'messages', 'console')
77 86 = add_menu( '[Problems]', 'problems', 'index')
78 87 = add_menu( '[Users]', 'user_admin', 'index')
79 88 = add_menu( '[Results]', 'user_admin', 'user_stat')
@@ -1,15 +1,16
1 1 <!DOCTYPE html>
2 2 %html
3 3 %head
4 4 %title= GraderConfiguration['contest.name']
5 5 = stylesheet_link_tag "application", params[:controller], :media => "all"
6 6 = javascript_include_tag "application", params[:controller]
7 7 = csrf_meta_tags
8 8 = content_for :header
9 9 = yield :head
10 10
11 11 %body
12 12 = render 'layouts/header'
13 13
14 - = content_tag(:p,flash[:notice],class: 'alert alert-success') if flash[:notice]!=nil
14 + /= content_tag(:p,flash[:notice],class: 'alert alert-success') if flash[:notice]!=nil
15 + = flash_messages
15 16 = yield
@@ -1,39 +1,39
1 1 %b= GraderConfiguration['ui.front.welcome_message']
2 2 %br/
3 3
4 4 - if !@hidelogin
5 5 =t 'login.message'
6 6 %br/
7 7 %br/
8 8
9 9 - if flash[:notice]
10 10 %hr/
11 11 %b= flash[:notice]
12 12 %hr/
13 13
14 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 16 %table
17 17 %tr
18 18 %td{:align => "right"}
19 19 ="#{t 'login_label'}:"
20 20 %td= text_field_tag 'login'
21 21 %tr
22 22 %td{:align => "right"}
23 23 ="#{t 'password_label'}:"
24 24 %td= password_field_tag
25 25 - unless GraderConfiguration['right.bypass_agreement']
26 26 %tr
27 27 %td{:align => "right"}= check_box_tag 'accept_agree'
28 28 %td ยอมรับข้อตกลงการใช้งาน
29 29
30 30 = submit_tag t('login.login_submit')
31 31 %br/
32 32
33 33 - if GraderConfiguration['system.online_registration']
34 34 =t 'login.participation'
35 35 %b
36 36 = "#{t 'login.please'} "
37 37 = link_to "#{t 'login.register'}", :controller => :users, :action => :new
38 38 %br/
39 39 = link_to "#{t 'login.forget_password'}", :controller => :users, :action => :forget
@@ -1,18 +1,22
1 1 %tr
2 2 %td
3 - = "#{problem.name}"
3 + - if @current_user and @current_user.admin?
4 + = link_to problem.name, stat_problem_path(problem)
5 + - else
6 + = "#{problem.name}"
4 7 %td
5 8 = "#{problem.full_name}"
9 +
6 10 %br
7 11 = link_to_description_if_any "[#{t 'main.problem_desc'}] <span class='glyphicon glyphicon-file'></span>".html_safe, problem
8 12 %td
9 13 = @prob_submissions[problem.id][:count]
10 14 = link_to "[subs]", main_submission_path(problem.id)
11 15 %td
12 16 = render :partial => 'submission_short',
13 17 :locals => {:submission => @prob_submissions[problem.id][:submission], :problem_name => problem.name, :problem_id => problem.id }
14 18 %td
15 19 - if @prob_submissions[problem.id][:submission]
16 20 = link_to 'Edit', edit_submission_path(@prob_submissions[problem.id][:submission]), class: 'btn btn-success'
17 21 - else
18 22 = link_to 'New', direct_edit_problem_submissions_path(problem.id), class: 'btn btn-success'
@@ -1,20 +1,20
1 1 = form_tag({:action => 'submit'}, :multipart => true, class: 'form') do
2 2 - if @submission and @submission.errors.any?
3 3 #error_explanation
4 4 .alert.alert-danger
5 5 %h3= "#{pluralize(@submission.errors.count, "error")} prohibited this user from being saved:"
6 6 %ul
7 7 - @submission.errors.full_messages.each do |msg|
8 8 %li= msg
9 9 .form-group
10 10 = label_tag :submission, 'Problem:'
11 - = select 'submission', 'problem_id', [[(t 'main.specified_in_header'),'-1']] + @problems.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]}, {:selected => '-1'}, { class: 'select2 form-control' }
11 + = select 'submission', 'problem_id', [[(t 'main.specified_in_header'),'-1']] + @problems.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]}, {:selected => '-1'}, { class: 'select2 form-control', style: "width: 100%" }
12 12 .form-group
13 13 = label_tag :file, 'File:'
14 14 .input-group
15 15 %span.input-group-btn
16 16 %span.btn.btn-default.btn-file
17 17 Browse
18 18 = file_field_tag 'file'
19 19 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
20 20 = submit_tag 'Submit', class: 'btn btn-default'
@@ -1,26 +1,29
1 1
2 2 - if submission.nil?
3 3 = "-"
4 4 - else
5 5 - unless submission.graded_at
6 - =t 'main.submitted_at'
6 + = t 'main.submitted_at'
7 7 = format_short_time(submission.submitted_at.localtime)
8 8 - else
9 9 %strong= t 'main.graded_at'
10 10 = "#{format_short_time(submission.graded_at.localtime)} "
11 11 %br
12 12 - if GraderConfiguration['ui.show_score']
13 - =t 'main.score'
13 + %strong=t 'main.score'
14 14 = "#{(submission.points*100/submission.problem.full_score).to_i} "
15 15 = " ["
16 16 %tt
17 17 = submission.grader_comment
18 18 = "]"
19 19 %br
20 20 %strong View:
21 21 - if GraderConfiguration.show_grading_result
22 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 25 = link_to "#{t 'main.src_link'}",{:action => 'source', :id => submission.id}, class: 'btn btn-xs btn-info'
25 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_problem_testcases_path(problem_id), class: 'btn btn-xs btn-info'
26 29
@@ -22,31 +22,43
22 22 %th Task name
23 23 %th Full name
24 24 %th # of sub(s)
25 25 %th Results
26 26 %th
27 27 %tbody
28 28 = render :partial => 'problem', :collection => @problems
29 29 - else
30 30 - @contest_problems.each do |cp|
31 31 - if cp[:problems].length > 0
32 32 %h2{:class =>'contest-title'}
33 33 = "#{cp[:contest] ? cp[:contest].title : 'Public problems'}"
34 34 %table.info
35 35 %tr.info-head
36 36 %th Task name
37 37 %th Full name
38 38 %th # of sub(s)
39 39 %th Results
40 40 %th
41 41 = render :partial => 'problem', :collection => cp[:problems]
42 42 .col-md-5
43 43 .panel.panel-info
44 44 .panel-heading
45 45 Announcement
46 + = link_to 'Manage', announcements_path, class: 'btn btn-xs btn-default'
46 47 %ul.list-group
47 48 = render :partial => 'announcement', :collection => @announcements
48 49
49 50 %script{:type => 'text/javascript'}
50 51 = "Announcement.refreshUrl = '#{url_for :controller => 'main', :action => 'announcements'}';"
51 52 Announcement.registerRefreshEventTimer();
52 53
54 + .modal.fade#compiler{tabindex: -1,role: 'dialog'}
55 + .modal-dialog.modal-lg{role:'document'}
56 + .modal-content
57 + .modal-header
58 + %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
59 + %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
60 + %h4 Compiler message
61 + .modal-body
62 + %pre#compiler_msg
63 + .modal-footer
64 + %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -5,46 +5,50
5 5 = link_to 'New problem', new_problem_path, class: 'btn btn-default btn-sm'
6 6 = link_to 'Manage problems', { action: 'manage'}, class: 'btn btn-default btn-sm'
7 7 = link_to 'Import problems', {:action => 'import'}, class: 'btn btn-default btn-sm'
8 8 = link_to 'Turn off all problems', {:action => 'turn_all_off'}, class: 'btn btn-default btn-sm'
9 9 = link_to 'Turn on all problems', {:action => 'turn_all_on'}, class: 'btn btn-default btn-sm'
10 10 .submitbox
11 11 = form_tag :action => 'quick_create' do
12 12 %b Quick New:
13 13 %label{:for => "problem_name"} Name
14 14 = text_field 'problem', 'name'
15 15 |
16 16 %label{:for => "problem_full_name"} Full name
17 17 = text_field 'problem', 'full_name'
18 18 = submit_tag "Create"
19 19 %table.table.table-condense.table-hover
20 20 %thead
21 21 %th Name
22 22 %th Full name
23 23 %th.text-right Full score
24 24 %th Date added
25 25 %th.text-center
26 26 Avail?
27 27 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user submits to this problem?' } [?]
28 28 %th.text-center
29 + View Data?
30 + %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user view the testcase of this problem?' } [?]
31 + %th.text-center
29 32 Test?
30 33 %sup{class: 'text-primary',data: {toggle: 'tooltip'}, title: 'Let user uses test interface on this problem?' } [?]
31 34 - if GraderConfiguration.multicontests?
32 35 %th Contests
33 36 - for problem in @problems
34 37 %tr{:class => "#{(problem.available) ? "success" : "danger"}", :id => "prob-#{problem.id}", :name => "prob-#{problem.id}"}
35 38 - @problem=problem
36 39 %td= problem.name #in_place_editor_field :problem, :name, {}, :rows=>1
37 40 %td= problem.full_name #in_place_editor_field :problem, :full_name, {}, :rows=>1
38 41 %td.text-right= problem.full_score #in_place_editor_field :problem, :full_score, {}, :rows=>1
39 42 %td= problem.date_added
40 43 %td= toggle_button(@problem.available?, toggle_problem_path(@problem), "problem-avail-#{@problem.id}")
44 + %td= toggle_button(@problem.view_testcase?, toggle_view_testcase_problem_path(@problem), "problem-view-testcase-#{@problem.id}")
41 45 %td= toggle_button(@problem.test_allowed?, toggle_test_problem_path(@problem), "problem-test-#{@problem.id}")
42 46 - if GraderConfiguration.multicontests?
43 47 %td
44 48 = problem.contests.collect { |c| c.name }.join(', ')
45 49 %td= link_to 'Stat', {:action => 'stat', :id => problem.id}, class: 'btn btn-info btn-xs btn-block'
46 50 %td= link_to 'Show', {:action => 'show', :id => problem}, class: 'btn btn-info btn-xs btn-block'
47 51 %td= link_to 'Edit', {:action => 'edit', :id => problem}, class: 'btn btn-info btn-xs btn-block'
48 52 %td= link_to 'Destroy', { :action => 'destroy', :id => problem }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-xs btn-block'
49 53 %br/
50 54 = link_to '[New problem]', :action => 'new'
@@ -1,24 +1,24
1 1 <% for column in Problem.content_columns %>
2 2 <p>
3 3 <b><%= column.human_name %>:</b>
4 4 <%=h @problem.send(column.name) %>
5 5 </p>
6 6 <% end %>
7 7
8 8 <p>
9 9 <b>Description:</b><br/>
10 10 <% if @problem.description!=nil %>
11 11 <% if @problem.description.markdowned %>
12 12 <%= markdown(@problem.description.body) %>
13 13 <% else %>
14 14 <pre>
15 15 <%= @problem.description.body %>
16 16 </pre>
17 17 <% end %>
18 18 <% else %>
19 19 (not available)
20 20 <% end %>
21 21 </p>
22 22
23 23 <%= link_to 'Edit', :action => 'edit', :id => @problem %> |
24 - <%= link_to 'Back', :action => 'list' %>
24 + <%= link_to 'Back', problems_path %>
@@ -1,34 +1,34
1 1 %table.table.sortable.table-striped.table-bordered.table-condensed
2 2 %thead
3 3 %tr
4 4 %th Login
5 5 %th Name
6 - %th Activated?
7 - %th Logged_in
8 - %th Contest(s)
6 + / %th Activated?
7 + / %th Logged_in
8 + / %th Contest(s)
9 9 %th Remark
10 10 - @problems.each do |p|
11 - %th.text-right= p.name
11 + %th.text-right= p.name.gsub('_',' ')
12 12 %th.text-right Total
13 13 %th.text-right Passed
14 14 %tbody
15 15 - @scorearray.each do |sc|
16 16 %tr
17 17 - total,num_passed = 0,0
18 18 - sc.each_index do |i|
19 19 - if i == 0
20 - %td= link_to sc[i].login, controller: 'users', action: 'profile', id: sc[i]
20 + %td= link_to sc[i].login, stat_user_path(sc[i])
21 21 %td= sc[i].full_name
22 - %td= sc[i].activated
23 - %td= sc[i].try(:contest_stat).try(:started_at) ? 'yes' : 'no'
24 - %td= sc[i].contests.collect {|c| c.name}.join(', ')
22 + / %td= sc[i].activated
23 + / %td= sc[i].try(:contest_stat).try(:started_at) ? 'yes' : 'no'
24 + / %td= sc[i].contests.collect {|c| c.name}.join(', ')
25 25 %td= sc[i].remark
26 26 - else
27 27 %td.text-right= sc[i][0]
28 28 - total += sc[i][0]
29 29 - num_passed += 1 if sc[i][1]
30 30 %td.text-right= total
31 31 %td.text-right= num_passed
32 32
33 33 :javascript
34 34 $.bootstrapSortable(true,'reversed')
@@ -23,114 +23,114
23 23 overflow: auto;
24 24 }
25 25
26 26
27 27 .container
28 28 .row
29 29 .col-md-4
30 30 %h2 Overall Stat
31 31 %table.table.table-hover
32 32 %thead
33 33 %tr
34 34 %th
35 35 %th
36 36 %tbody
37 37 %tr
38 38 %td.info_param Submissions
39 39 %td= @summary[:count]
40 40 %tr
41 41 %td.info_param Solved/Attempted User
42 42 %td #{@summary[:solve]}/#{@summary[:attempt]} (#{(@summary[:solve]*100.0/@summary[:attempt]).round(1)}%)
43 43 - if @best
44 44 %tr
45 45 %td.info_param Best Runtime
46 46 %td
47 - by #{link_to @best[:runtime][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
47 + by #{link_to @best[:runtime][:user], stat_user_path(@best[:runtime][:user_id])}
48 48 %br
49 49 using <span class="text-success">#{@best[:runtime][:lang]}</span>
50 50 %br
51 51 with <span class="text-success">#{@best[:runtime][:value] * 1000} milliseconds</span>
52 52 %br
53 53 at submission
54 54 = link_to "#" + @best[:runtime][:sub_id].to_s, submission_path(@best[:runtime][:sub_id])
55 55
56 56 %tr
57 57 %td.info_param
58 58 Best Memory Usage
59 59 %sup{ id: "xmem_remark",
60 60 style: "position:relative; color: blue;",
61 61 data: {toggle: 'tooltip', placement: 'top', animation: 'false', delay: 20},
62 62 title: "This counts only for submission with 100% score. Right now, java is excluded from memory usage competition. (Because it always uses 2GB memory...)"}
63 63 [?]
64 64 %td
65 - by #{link_to @best[:memory][:user], controller:'users', action:'profile', id:@best[:memory][:user_id]}
65 + by #{link_to @best[:memory][:user], stat_user_path(@best[:memory][:user_id])}
66 66 %br
67 67 using <span class="text-success">#{@best[:memory][:lang]}</span>
68 68 %br
69 69 with <span class="text-success">#{number_with_delimiter(@best[:memory][:value])} kbytes </span>
70 70 %br
71 71 at submission
72 72 = link_to "#" + @best[:memory][:sub_id].to_s, submission_path(@best[:memory][:sub_id])
73 73
74 74 %tr
75 75 %td.info_param Shortest Code
76 76 %td
77 - by #{link_to @best[:length][:user], controller:'users', action:'profile', id:@best[:length][:user_id]}
77 + by #{link_to @best[:length][:user], stat_user_path(@best[:length][:user_id])}
78 78 %br
79 79 using <span class="text-success">#{@best[:length][:lang]}</span>
80 80 %br
81 81 with <span class="text-success">#{@best[:length][:value]} bytes</span>
82 82 %br
83 83 at submission
84 84 = link_to "#" + @best[:length][:sub_id].to_s, submission_path(@best[:length][:sub_id])
85 85
86 86 %tr
87 87 %td.info_param First solver
88 88 %td
89 89 - if @best[:first][:user] != '(NULL)'
90 - #{link_to @best[:first][:user], controller:'users', action:'profile', id:@best[:first][:user_id]} is the first solver
90 + #{link_to @best[:first][:user], stat_user_path(@best[:first][:user_id])} is the first solver
91 91 %br
92 92 using <span class="text-success">#{@best[:first][:lang]}</span>
93 93 %br
94 94 on <span class="text-success">#{@best[:first][:value]}</span>
95 95 %br
96 96 at submission
97 97 = link_to "#" + @best[:first][:sub_id].to_s, submission_path( @best[:first][:sub_id])
98 98 - else
99 99 no first solver
100 100 .col-md-8
101 101 - if @best
102 102 %h2 By Language
103 103 %table.table.table-hover
104 104 %thead
105 105 %tr
106 106 %th Language
107 107 %th Best runtime (ms)
108 108 %th Best memory (kbytes)
109 109 %th Shortest Code (bytes)
110 110 %th First solver
111 111 %tbody
112 112 - @by_lang.each do |lang,value|
113 113 %tr
114 114 %td= lang
115 115 %td
116 - = link_to value[:runtime][:user], controller: 'users', action: 'profile', id: value[:runtime][:user_id]
116 + = link_to value[:runtime][:user], stat_user_path(value[:runtime][:user_id])
117 117 %br
118 118 = "#{(value[:runtime][:value] * 1000).to_i} @"
119 119 = link_to "#" + value[:runtime][:sub_id].to_s, submission_path( value[:runtime][:sub_id])
120 120 %td
121 - = link_to value[:memory][:user], controller: 'users', action: 'profile', id: value[:memory][:user_id]
121 + = link_to value[:memory][:user], stat_user_path( value[:memory][:user_id])
122 122 %br
123 123 = "#{number_with_delimiter(value[:memory][:value])} @"
124 124 = link_to "#" + value[:memory][:sub_id].to_s, submission_path(value[:memory][:sub_id])
125 125 %td
126 - = link_to value[:length][:user], controller: 'users', action: 'profile', id: value[:length][:user_id]
126 + = link_to value[:length][:user], stat_user_path(value[:length][:user_id])
127 127 %br
128 128 = "#{value[:length][:value]} @"
129 129 = link_to "#" + value[:length][:sub_id].to_s, submission_path(value[:length][:sub_id])
130 130 %td
131 131 - if value[:first][:user] != '(NULL)' #TODO: i know... this is wrong...
132 - = link_to value[:first][:user], controller: 'users', action: 'profile', id: value[:first][:user_id]
132 + = link_to value[:first][:user], stat_user_path(value[:first][:user_id])
133 133 %br
134 134 = "#{value[:first][:value]} @"
135 135 = link_to "#" + value[:first][:sub_id].to_s, submission_path( value[:first][:sub_id])
136 136
@@ -1,49 +1,49
1 1 %h1 Maximum score
2 2
3 3 = form_tag report_show_max_score_path
4 4 .row
5 5 .col-md-4
6 6 .panel.panel-primary
7 7 .panel-heading
8 8 Problems
9 9 .panel-body
10 10 %p
11 11 Select problem(s) that we wish to know the score.
12 12 = label_tag :problem_id, "Problems"
13 13 = select_tag 'problem_id[]',
14 14 options_for_select(Problem.all.collect {|p| ["[#{p.name}] #{p.full_name}", p.id]},params[:problem_id]),
15 15 { class: 'select2 form-control', multiple: "true" }
16 16 .col-md-4
17 17 .panel.panel-primary
18 18 .panel-heading
19 19 Submission range
20 20 .panel-body
21 21 %p
22 22 Input minimum and maximum range of submission ID that should be included. A blank value for min and max means -1 and infinity, respectively.
23 23 .form-group
24 24 = label_tag :from, "Min"
25 - = text_field_tag 'from_id', nil, class: "form-control"
25 + = text_field_tag 'from_id', @since_id, class: "form-control"
26 26 .form-group
27 27 = label_tag :from, "Max"
28 - = text_field_tag 'to_id', nil, class: "form-control"
28 + = text_field_tag 'to_id', @until_id, class: "form-control"
29 29 .col-md-4
30 30 .panel.panel-primary
31 31 .panel-heading
32 32 Users
33 33 .panel-body
34 34 .radio
35 35 %label
36 36 = radio_button_tag 'users', 'all', true
37 37 All users
38 38 .radio
39 39 %label
40 40 = radio_button_tag 'users', 'enabled'
41 41 Only enabled users
42 42 .row
43 43 .col-md-12
44 44 = button_tag 'Show', class: "btn btn-primary btn-large", value: "show"
45 45 = button_tag 'Download CSV', class: "btn btn-primary btn-large", value: "download"
46 46
47 47 - if @scorearray
48 48 %h2 Result
49 49 =render "score_table"
@@ -1,67 +1,68
1 1 %h2 Live submit
2 2 %br
3 3
4 - %textarea#text_haha{style: "display:none"}~ @source
4 + %textarea#text_sourcecode{style: "display:none"}~ @source
5 5 .container
6 6 .row
7 7 .col-md-12
8 8 .alert.alert-info
9 9 Write your code in the following box, choose language, and click submit button when finished
10 10 .row
11 11 .col-md-8
12 12 %div#editor{style: 'height: 500px; border-radius: 7px; font-size: 14px;'}
13 13 .col-md-4
14 14 = form_tag({controller: :main, :action => 'submit'}, :multipart => true, class: 'form') do
15 15
16 16 = hidden_field_tag 'editor_text', @source
17 17 = hidden_field_tag 'submission[problem_id]', @problem.id
18 18 .form-group
19 19 = label_tag "Task:"
20 20 = text_field_tag 'asdf', "#{@problem.long_name}", class: 'form-control', disabled: true
21 21
22 22 .form-group
23 23 = label_tag 'Language'
24 24 = select_tag 'language_id', options_from_collection_for_select(Language.all, 'id', 'pretty_name', @lang_id || Language.find_by_pretty_name("Python").id || Language.first.id), class: 'form-control select', style: "width: 100px"
25 25 .form-group
26 26 = submit_tag 'Submit', class: 'btn btn-success', id: 'live_submit',
27 27 data: {confirm: "Submitting this source code for task #{@problem.long_name}?"}
28 28 .panel.panel-info
29 29 .panel-heading
30 30 Latest Submission Status
31 + = link_to "Refresh",get_latest_submission_status_submissions_path(@submission.user,@problem), class: "btn btn-default btn-sm", remote: true if @submission
31 32 .panel-body
32 33 - if @submission
33 34 = render :partial => 'submission_short',
34 - :locals => {:submission => @submission, :problem_name => @problem.name }
35 + :locals => {submission: @submission, problem_name: @problem.name, problem_id: @problem.id }
35 36 .row
36 37 .col-md-12
37 38 %h2 Console
38 39 %textarea#console{style: 'height: 100%; width: 100%;background-color:#000;color:#fff;font-family: consolas, monaco, "Droid Sans Mono";',rows: 20}
39 40
40 41 :javascript
41 42 $(document).ready(function() {
42 43 e = ace.edit("editor")
43 - e.setValue($("#text_haha").val());
44 + e.setValue($("#text_sourcecode").val());
44 45 e.gotoLine(1);
45 46 $("#language_id").trigger('change');
46 47 brython();
47 48 });
48 49
49 50
50 51 %script#__main__{type:'text/python3'}
51 52 :plain
52 53 import sys
53 54 import traceback
54 55
55 56 from browser import document as doc
56 57 from browser import window, alert, console
57 58
58 59 _credits = """ Thanks to CWI, CNRI, BeOpen.com, Zope Corporation and a cast of thousands
59 60 for supporting Python development. See www.python.org for more information."""
60 61
61 62 _copyright = """Copyright (c) 2012, Pierre Quentel pierre.quentel@gmail.com
62 63 All Rights Reserved.
63 64
64 65 Copyright (c) 2001-2013 Python Software Foundation.
65 66 All Rights Reserved.
66 67
67 68 Copyright (c) 2000 BeOpen.com.
@@ -1,2 +1,2
1 - :javascript
1 + :plain
2 2 $("#latest_status").html("#{j render({partial: 'submission_short', locals: {submission: @submission, problem_name: @problem.name}})}")
@@ -1,29 +1,29
1 1 .panel.panel-info
2 2 .panel-heading
3 3 Select Problems
4 4 .panel-body
5 5 .form-inline
6 6 = select 'submission',
7 7 'problem_id',
8 8 @problems.collect {|p| ["[#{p.name}] #{p.full_name}", problem_submissions_url(p.id)]},
9 9 { selected: (@problem ? problem_submissions_url(@problem) : -1) },
10 10 { class: 'select2 form-control'}
11 11 %button.btn.btn-primary.btn-sm.go-button#problem_go{data: {source: '#submission_problem_id'}} Go
12 12
13 13 - if @problem!=nil
14 14 %h2= "Task: #{@problem.full_name} (#{@problem.name})"
15 15
16 16 - if @submissions!=nil
17 17 - if @submissions.length>0
18 18 %table.table
19 19 %thead
20 20 %th No.
21 - %th #
21 + %th.text-right #
22 22 %th At
23 23 %th Source
24 24 %th Result
25 25 %th{:width => "300px"} Compiler message
26 26 %th
27 27 = render :partial => 'submission', :collection => @submissions
28 28 - else
29 29 No submission
@@ -1,32 +1,34
1 1 %h1= "Submission: #{@submission.id}"
2 2
3 3 %textarea#data{style: "display:none;"}
4 4 :preserve
5 5 #{@submission.source}
6 6
7 7 //%div.highlight{:style => "border: 1px solid black;"}
8 8 //=@formatted_code.html_safe
9 +
10 +
9 11 .containter
10 12 .row
11 13 .col-md-7
12 14 %h2 Source Code
13 15 .col-md-5
14 16 %h2 Stat
15 17 .row
16 18 .col-md-7
17 19 %div#editor{ style: "font-size: 14px; height: 400px; border-radius:5px;" }
18 20 :javascript
19 21 e = ace.edit("editor")
20 22 e.setOptions({ maxLines: Infinity })
21 23 e.setValue($("#data").text())
22 24 e.gotoLine(1)
23 25 e.getSession().setMode("#{get_ace_mode(@submission.language)}")
24 26 e.setReadOnly(true)
25 27 .col-md-5
26 28 %table.table.table-striped
27 29 %tr
28 30 %td.text-right
29 31 %strong User
30 32 %td
31 33 - if @submission.user
32 34 = link_to "#{@submission.user.login}", stat_user_path(@submission.user)
@@ -43,47 +45,68
43 45 - else
44 46 = "(n/a)"
45 47 %tr
46 48 %td.text-right
47 49 %strong Tries
48 50 %td= @submission.number
49 51 %tr
50 52 %td.text-right
51 53 %strong Language
52 54 %td= @submission.language.pretty_name
53 55 %tr
54 56 %td.text-right
55 57 %strong Submitted
56 58 %td #{time_ago_in_words(@submission.submitted_at)} ago (at #{@submission.submitted_at.to_formatted_s(:long)})
57 59 %tr
58 60 %td.text-right
59 61 %strong Graded
60 62 - if @submission.graded_at
61 63 %td #{time_ago_in_words(@submission.graded_at)} ago (at #{@submission.graded_at.to_formatted_s(:long)})
62 64 - else
63 65 %td -
64 66 %tr
65 67 %td.text-right
66 68 %strong Points
67 - %td #{@submission.points}/#{@submission.problem.full_score}
69 + %td #{@submission.points}/#{@submission.try(:problem).try(:full_score)}
68 70 %tr
69 71 %td.text-right
70 72 %strong Comment
71 73 %td #{@submission.grader_comment}
72 74 %tr
73 75 %td.text-right
74 76 %strong Runtime (s)
75 77 %td #{@submission.max_runtime}
76 78 %tr
77 79 %td.text-right
78 80 %strong Memory (kb)
79 81 %td #{@submission.peak_memory}
80 82 %tr
81 83 %td.text-right
82 84 %strong Compiler result
83 85 %td
84 - %pre= @submission.compiler_message
86 + %button.btn.btn-info.btn-xs{type: 'button', data: {toggle: 'modal', target: '#compiler'}}
87 + view
85 88 - if session[:admin]
86 89 %tr
87 90 %td.text-right
88 91 %strong IP
89 92 %td #{@submission.ip_address}
93 + %tr
94 + %td.text-right
95 + %strong Grading Task Status
96 + %td
97 + = @task.status_str if @task
98 + - if session[:admin]
99 + = link_to "rejudge", rejudge_submission_path, data: {remote: true}, class: 'btn btn-info btn-xs'
100 +
101 +
102 + .modal.fade#compiler{tabindex: -1,role: 'dialog'}
103 + .modal-dialog.modal-lg{role:'document'}
104 + .modal-content
105 + .modal-header
106 + %button.close{type: 'button', data: {dismissed: :modal}, aria: {label: 'close'}}
107 + %span{aria: {hidden: 'true'}, data: {dismiss: 'modal'}} &times;
108 + %h4 Compiler message
109 + .modal-body
110 + %pre#compiler_msg= @submission.compiler_message
111 + .modal-footer
112 + %button.btn.btn-default{type: 'button', data: {dismiss: 'modal'}} Close
@@ -21,80 +21,81
21 21 = label_tag 'user_email', 'email'
22 22 = text_field 'user', 'email', :size => 10,class: 'form-control'
23 23 =submit_tag "Create", class: 'btn btn-primary'
24 24
25 25 .panel.panel-primary
26 26 .panel-title.panel-heading
27 27 Import from site management
28 28 .panel-body
29 29 = form_tag({:action => 'import'}, :multipart => true,class: 'form form-inline') do
30 30 .form-group
31 31 = label_tag :file, 'File:'
32 32 .input-group
33 33 %span.input-group-btn
34 34 %span.btn.btn-default.btn-file
35 35 Browse
36 36 = file_field_tag 'file'
37 37 = text_field_tag '' , nil, {readonly: true, class: 'form-control'}
38 38 = submit_tag 'Submit', class: 'btn btn-default'
39 39
40 40
41 41 %p
42 42 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
43 43 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
44 44 = link_to 'View administrators',{ :action => 'admin'}, { class: 'btn btn-default '}
45 + = link_to 'Bulk Manage', bulk_manage_user_admin_path , { class: 'btn btn-default '}
45 46 = link_to 'Random passwords',{ :action => 'random_all_passwords'}, { class: 'btn btn-default '}
46 47 = link_to 'View active users',{ :action => 'active'}, { class: 'btn btn-default '}
47 48 = link_to 'Mass mailing',{ :action => 'mass_mailing'}, { class: 'btn btn-default '}
48 49
49 50 - if GraderConfiguration.multicontests?
50 51 %br/
51 52 %b Multi-contest:
52 53 = link_to '[Manage bulk users in contests]', :action => 'contest_management'
53 54 View users in:
54 55 - @contests.each do |contest|
55 56 = link_to "[#{contest.name}]", :action => 'contests', :id => contest.id
56 57 = link_to "[no contest]", :action => 'contests', :id => 'none'
57 58
58 59 Total #{@user_count} users |
59 60 - if !@paginated
60 61 Display all users.
61 62 \#{link_to '[show in pages]', :action => 'index', :page => '1'}
62 63 - else
63 64 Display in pages.
64 65 \#{link_to '[display all]', :action => 'index', :page => 'all'} |
65 66 \#{will_paginate @users, :container => false}
66 67
67 68
68 69 %table.table.table-hover.table-condense
69 70 %thead
70 71 %th Login
71 72 %th Full name
72 73 %th email
73 74 %th Remark
74 75 %th
75 76 Activated
76 77 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'User has already confirmed the email?' } [?]
77 78 %th
78 79 Enabled
79 80 %sup{class: 'text-primary',data: {toggle: 'tooltip', placement: 'top'}, title: 'Allow the user to login?' } [?]
80 81 %th Last IP
81 82 %th
82 83 %th
83 84 %th
84 85 %th
85 86 - for user in @users
86 87 %tr
87 - %td= link_to user.login, controller: :users, :action => 'profile', :id => user
88 + %td= link_to user.login, stat_user_path(user)
88 89 %td= user.full_name
89 90 %td= user.email
90 91 %td= user.remark
91 92 %td= toggle_button(user.activated?, toggle_activate_user_path(user),"toggle_activate_user_#{user.id}")
92 93 %td= toggle_button(user.enabled?, toggle_enable_user_path(user),"toggle_enable_user_#{user.id}")
93 94 %td= user.last_ip
94 95 %td= link_to 'Clear IP', {:action => 'clear_last_ip', :id => user, :page=>params[:page]}, :confirm => 'This will reset last logging in ip of the user, are you sure?', class: 'btn btn-default btn-xs btn-block'
95 96 %td= link_to 'Show', {:action => 'show', :id => user}, class: 'btn btn-default btn-xs btn-block'
96 97 %td= link_to 'Edit', {:action => 'edit', :id => user}, class: 'btn btn-default btn-xs btn-block'
97 98 %td= link_to 'Destroy', { :action => 'destroy', :id => user }, :confirm => 'Are you sure?', :method => :delete, class: 'btn btn-danger btn-xs btn-block'
98 99 %br/
99 100 = link_to '+ New user', { :action => 'new' }, { class: 'btn btn-success '}
100 101 = link_to '+ New list of users', { :action => 'new_list' }, { class: 'btn btn-success '}
@@ -1,8 +1,9
1 1 <h1>Adding list of users</h1>
2 2
3 3 <%= form_tag :action => 'create_from_list' do %>
4 - <%= submit_tag 'create users' %><br/>
5 - List of user information in this format: <tt>user_id,name(,passwd(,alias))</tt><br/>
6 - Note that <tt>passwd</tt> and <tt>alias</tt> is optional.<br/>
4 + <%= submit_tag 'create users',class: 'btn btn-success'%><br/>
5 + List of user information in this format: <tt>user_id,name(,passwd(,alias(,remark)))</tt><br/>
6 + Note that <tt>passwd, alias</tt> and <tt> remark </tt>is optional.<br />
7 + When <tt>passwd</tt> or <tt>alias</tt> is empty, the original value will be used instead.<br/>
7 8 <%= text_area_tag 'user_list', nil, :rows => 50, :cols => 80 %>
8 9 <% end %>
@@ -1,40 +1,42
1 1 CafeGrader::Application.configure do
2 2 # Settings specified here will take precedence over those in config/application.rb
3 3
4 4 # In the development environment your application's code is reloaded on
5 5 # every request. This slows down response time but is perfect for development
6 6 # since you don't have to restart the web server when you make code changes.
7 7 config.cache_classes = false
8 8
9 - # Log error messages when you accidentally call methods on nil.
10 - config.whiny_nils = true
9 + # Log error messages when you accidentally call methods on nil. //DEPRICATED
10 + # config.whiny_nils = true // DEPRICATED
11 11
12 12 # Show full error reports and disable caching
13 13 config.consider_all_requests_local = true
14 14 config.action_controller.perform_caching = false
15 15
16 16 # Don't care if the mailer can't send
17 17 config.action_mailer.raise_delivery_errors = false
18 18
19 19 # Print deprecation notices to the Rails logger
20 20 config.active_support.deprecation = :log
21 21
22 22 # Only use best-standards-support built into browsers
23 23 config.action_dispatch.best_standards_support = :builtin
24 24
25 25 # Raise exception on mass assignment protection for Active Record models
26 - config.active_record.mass_assignment_sanitizer = :strict
26 + # config.active_record.mass_assignment_sanitizer = :strict //DEPRICATED
27 27
28 - # Log the query plan for queries taking more than this (works
29 - # with SQLite, MySQL, and PostgreSQL)
30 - config.active_record.auto_explain_threshold_in_seconds = 0.5
28 + # Log the query plan for queries taking more than this (works // DEPRICATED
29 + # with SQLite, MySQL, and PostgreSQL) // DEPRICATED
30 + # config.active_record.auto_explain_threshold_in_seconds = 0.5 // DEPRICATED
31 31
32 32 # Do not compress assets
33 33 config.assets.compress = false
34 34
35 35 # Expands the lines which load the assets
36 36 config.assets.debug = true
37 37
38 38 # Prevents assets from rendering twice
39 - config.serve_static_assets = true
39 + config.serve_static_files = true
40 +
41 + config.eager_load = false
40 42 end
@@ -1,36 +1,36
1 1 CafeGrader::Application.configure do
2 2 # Settings specified here will take precedence over those in config/application.rb
3 3
4 4 # Code is not reloaded between requests
5 5 config.cache_classes = true
6 6
7 7 # Full error reports are disabled and caching is turned on
8 8 config.consider_all_requests_local = false
9 9 config.action_controller.perform_caching = true
10 10
11 11 # Disable Rails's static asset server (Apache or nginx will already do this)
12 - config.serve_static_assets = false
12 + config.serve_static_files = false
13 13
14 14 # Compress JavaScripts and CSS
15 15 config.assets.compress = true
16 16
17 17 # Don't fallback to assets pipeline if a precompiled asset is missed
18 18 config.assets.compile = false
19 19
20 20 # Generate digests for assets URLs
21 21 config.assets.digest = true
22 22
23 23 # Defaults to nil and saved in location specified by config.assets.prefix
24 24 # config.assets.manifest = YOUR_PATH
25 25
26 26 # Specifies the header that your server uses for sending files
27 27 # config.action_dispatch.x_sendfile_header = "X-Sendfile" # for apache
28 28 # config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for nginx
29 29
30 30 # Force all access to the app over SSL, use Strict-Transport-Security, and use secure cookies.
31 31 # config.force_ssl = true
32 32
33 33 # See everything in the log (default is :info)
34 34 # config.log_level = :debug
35 35
36 36 # Prepend all log lines with the following tags
@@ -43,25 +43,27
43 43 # config.cache_store = :mem_cache_store
44 44
45 45 # Enable serving of images, stylesheets, and JavaScripts from an asset server
46 46 # config.action_controller.asset_host = "http://assets.example.com"
47 47
48 48 # Precompile additional assets (application.js, application.css, and all non-JS/CSS are already added)
49 49 # config.assets.precompile += %w( search.js )
50 50
51 51 # Disable delivery errors, bad email addresses will be ignored
52 52 # config.action_mailer.raise_delivery_errors = false
53 53
54 54 # Enable threaded mode
55 55 # config.threadsafe!
56 56
57 57 # Enable locale fallbacks for I18n (makes lookups for any locale fall back to
58 58 # the I18n.default_locale when a translation can not be found)
59 59 config.i18n.fallbacks = true
60 60
61 61 # Send deprecation notices to registered listeners
62 62 config.active_support.deprecation = :notify
63 63
64 64 # Log the query plan for queries taking more than this (works
65 65 # with SQLite, MySQL, and PostgreSQL)
66 66 # config.active_record.auto_explain_threshold_in_seconds = 0.5
67 +
68 + config.eager_load = true
67 69 end
@@ -1,37 +1,43
1 1 CafeGrader::Application.configure do
2 2 # Settings specified here will take precedence over those in config/application.rb
3 3
4 4 # The test environment is used exclusively to run your application's
5 5 # test suite. You never need to work with it otherwise. Remember that
6 6 # your test database is "scratch space" for the test suite and is wiped
7 7 # and recreated between test runs. Don't rely on the data there!
8 8 config.cache_classes = true
9 9
10 10 # Configure static asset server for tests with Cache-Control for performance
11 - config.serve_static_assets = true
11 + config.serve_static_files = true
12 12 config.static_cache_control = "public, max-age=3600"
13 13
14 14 # Log error messages when you accidentally call methods on nil
15 15 config.whiny_nils = true
16 16
17 17 # Show full error reports and disable caching
18 18 config.consider_all_requests_local = true
19 19 config.action_controller.perform_caching = false
20 20
21 21 # Raise exceptions instead of rendering exception templates
22 22 config.action_dispatch.show_exceptions = false
23 23
24 24 # Disable request forgery protection in test environment
25 25 config.action_controller.allow_forgery_protection = false
26 26
27 27 # Tell Action Mailer not to deliver emails to the real world.
28 28 # The :test delivery method accumulates sent emails in the
29 29 # ActionMailer::Base.deliveries array.
30 30 config.action_mailer.delivery_method = :test
31 31
32 32 # Raise exception on mass assignment protection for Active Record models
33 - config.active_record.mass_assignment_sanitizer = :strict
33 + #config.active_record.mass_assignment_sanitizer = :strict // DEPRICATED
34 34
35 35 # Print deprecation notices to the stderr
36 36 config.active_support.deprecation = :stderr
37 +
38 + config.eager_load = false
39 +
40 + #test order
41 + config.active_support.test_order = :sorted
42 +
37 43 end
@@ -1,6 +1,5
1 1 # Be sure to restart your server when you modify this file.
2 2
3 3 # Add new mime types for use in respond_to blocks:
4 4 # Mime::Type.register "text/richtext", :rtf
5 5 # Mime::Type.register_alias "text/html", :iphone
6 - Mime::Type.register 'application/pdf', :pdf
@@ -1,73 +1,98
1 1 CafeGrader::Application.routes.draw do
2 2 get "sources/direct_edit"
3 3
4 4 root :to => 'main#login'
5 5
6 + #logins
7 + get 'login/login', to: 'login#login'
8 +
6 9 resources :contests
7 10
8 11 resources :sites
9 12
10 13 resources :announcements do
11 14 member do
12 15 get 'toggle','toggle_front'
13 16 end
14 17 end
15 18
16 19 resources :problems do
17 20 member do
18 21 get 'toggle'
19 22 get 'toggle_test'
23 + get 'toggle_view_testcase'
20 24 get 'stat'
21 25 end
22 26 collection do
23 27 get 'turn_all_off'
24 28 get 'turn_all_on'
25 29 get 'import'
26 30 get 'manage'
27 31 end
32 +
33 + end
34 +
35 + resources :testcases, only: [] do
36 + member do
37 + get 'download_input'
38 + get 'download_sol'
39 + end
40 + collection do
41 + get 'show_problem/:problem_id(/:test_num)' => 'testcases#show_problem', as: 'show_problem'
42 + end
28 43 end
29 44
30 45 resources :grader_configuration, controller: 'configurations'
31 46
32 47 resources :users do
33 48 member do
34 49 get 'toggle_activate', 'toggle_enable'
35 50 get 'stat'
36 51 end
37 52 end
38 53
39 54 resources :submissions do
55 + member do
56 + get 'download'
57 + get 'compiler_msg'
58 + get 'rejudge'
59 + end
40 60 collection do
41 61 get 'prob/:problem_id', to: 'submissions#index', as: 'problem'
42 62 get 'direct_edit_problem/:problem_id', to: 'submissions#direct_edit_problem', as: 'direct_edit_problem'
43 63 get 'get_latest_submission_status/:uid/:pid', to: 'submissions#get_latest_submission_status', as: 'get_latest_submission_status'
44 64 end
45 65 end
46 66
47 - match 'tasks/view/:file.:ext' => 'tasks#view'
48 - match 'tasks/download/:id/:file.:ext' => 'tasks#download'
49 - match 'heartbeat/:id/edit' => 'heartbeat#edit'
67 +
50 68
51 69 #main
52 70 get "main/list"
53 71 get 'main/submission(/:id)', to: 'main#submission', as: 'main_submission'
54 72
73 + #user admin
74 + get 'user_admin/bulk_manage', to: 'user_admin#bulk_manage', as: 'bulk_manage_user_admin'
75 +
55 76 #report
56 77 get 'report/current_score', to: 'report#current_score', as: 'report_current_score'
57 78 get 'report/problem_hof(/:id)', to: 'report#problem_hof', as: 'report_problem_hof'
58 79 get "report/login"
59 80 get 'report/max_score', to: 'report#max_score', as: 'report_max_score'
60 81 post 'report/show_max_score', to: 'report#show_max_score', as: 'report_show_max_score'
61 82
83 +
84 + #
85 + get 'tasks/view/:file.:ext' => 'tasks#view'
86 + get 'tasks/download/:id/:file.:ext' => 'tasks#download'
87 + get 'heartbeat/:id/edit' => 'heartbeat#edit'
88 +
62 89 #grader
63 90 get 'graders/list', to: 'graders#list', as: 'grader_list'
64 -
65 91
66 - match 'heartbeat/:id/edit' => 'heartbeat#edit'
67 92
68 93 # See how all your routes lay out with "rake routes"
69 94
70 95 # This is a legacy wild controller route that's not recommended for RESTful applications.
71 96 # Note: This route will make all actions in every controller accessible via GET requests.
72 - match ':controller(/:action(/:id))(.:format)'
97 + match ':controller(/:action(/:id))(.:format)', via: [:get, :post]
73 98 end
@@ -1,280 +1,283
1 1 # encoding: UTF-8
2 2 # This file is auto-generated from the current state of the database. Instead
3 3 # of editing this file, please use the migrations feature of Active Record to
4 4 # incrementally modify your database, and then regenerate this schema definition.
5 5 #
6 6 # Note that this schema.rb definition is the authoritative source for your
7 7 # database schema. If you need to create the application database on another
8 8 # system, you should be using db:schema:load, not running all the migrations
9 9 # from scratch. The latter is a flawed and unsustainable approach (the more migrations
10 10 # you'll amass, the slower it'll run and the greater likelihood for issues).
11 11 #
12 - # It's strongly recommended to 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 => 20161014091417) do
14 + ActiveRecord::Schema.define(version: 20170427070345) do
15 15
16 - create_table "announcements", :force => true do |t|
17 - t.string "author"
18 - t.text "body"
16 + create_table "announcements", force: :cascade do |t|
17 + t.string "author", limit: 255
18 + t.text "body", limit: 65535
19 19 t.boolean "published"
20 - t.datetime "created_at", :null => false
21 - t.datetime "updated_at", :null => false
22 - t.boolean "frontpage", :default => false
23 - t.boolean "contest_only", :default => false
24 - t.string "title"
25 - t.string "notes"
20 + t.datetime "created_at", null: false
21 + t.datetime "updated_at", null: false
22 + t.boolean "frontpage", default: false
23 + t.boolean "contest_only", default: false
24 + t.string "title", limit: 255
25 + t.string "notes", limit: 255
26 26 end
27 27
28 - create_table "contests", :force => true do |t|
29 - t.string "title"
28 + create_table "contests", force: :cascade do |t|
29 + t.string "title", limit: 255
30 30 t.boolean "enabled"
31 - t.datetime "created_at", :null => false
32 - t.datetime "updated_at", :null => false
33 - t.string "name"
31 + t.datetime "created_at", null: false
32 + t.datetime "updated_at", null: false
33 + t.string "name", limit: 255
34 34 end
35 35
36 - create_table "contests_problems", :id => false, :force => true do |t|
37 - t.integer "contest_id"
38 - t.integer "problem_id"
36 + create_table "contests_problems", id: false, force: :cascade do |t|
37 + t.integer "contest_id", limit: 4
38 + t.integer "problem_id", limit: 4
39 39 end
40 40
41 - create_table "contests_users", :id => false, :force => true do |t|
42 - t.integer "contest_id"
43 - t.integer "user_id"
41 + create_table "contests_users", id: false, force: :cascade do |t|
42 + t.integer "contest_id", limit: 4
43 + t.integer "user_id", limit: 4
44 44 end
45 45
46 - create_table "countries", :force => true do |t|
47 - t.string "name"
48 - t.datetime "created_at", :null => false
49 - t.datetime "updated_at", :null => false
46 + create_table "countries", force: :cascade do |t|
47 + t.string "name", limit: 255
48 + t.datetime "created_at", null: false
49 + t.datetime "updated_at", null: false
50 50 end
51 51
52 - create_table "descriptions", :force => true do |t|
53 - t.text "body"
52 + create_table "descriptions", force: :cascade do |t|
53 + t.text "body", limit: 65535
54 54 t.boolean "markdowned"
55 - t.datetime "created_at", :null => false
56 - t.datetime "updated_at", :null => false
55 + t.datetime "created_at", null: false
56 + t.datetime "updated_at", null: false
57 57 end
58 58
59 - create_table "grader_configurations", :force => true do |t|
60 - t.string "key"
61 - t.string "value_type"
62 - t.string "value"
63 - t.datetime "created_at", :null => false
64 - t.datetime "updated_at", :null => false
65 - t.text "description"
59 + create_table "grader_configurations", force: :cascade do |t|
60 + t.string "key", limit: 255
61 + t.string "value_type", limit: 255
62 + t.string "value", limit: 255
63 + t.datetime "created_at", null: false
64 + t.datetime "updated_at", null: false
65 + t.text "description", limit: 65535
66 66 end
67 67
68 - create_table "grader_processes", :force => true do |t|
69 - t.string "host"
70 - t.integer "pid"
71 - t.string "mode"
68 + create_table "grader_processes", force: :cascade do |t|
69 + t.string "host", limit: 255
70 + t.integer "pid", limit: 4
71 + t.string "mode", limit: 255
72 72 t.boolean "active"
73 - t.datetime "created_at", :null => false
74 - t.datetime "updated_at", :null => false
75 - t.integer "task_id"
76 - t.string "task_type"
73 + t.datetime "created_at", null: false
74 + t.datetime "updated_at", null: false
75 + t.integer "task_id", limit: 4
76 + t.string "task_type", limit: 255
77 77 t.boolean "terminated"
78 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 => true do |t|
83 - t.integer "user_id"
84 - t.string "ip_address"
85 - t.datetime "created_at", :null => false
86 - t.datetime "updated_at", :null => false
87 - t.string "status"
82 + create_table "heart_beats", force: :cascade do |t|
83 + t.integer "user_id", limit: 4
84 + t.string "ip_address", limit: 255
85 + t.datetime "created_at", null: false
86 + t.datetime "updated_at", null: false
87 + t.string "status", limit: 255
88 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 => true do |t|
93 - t.string "name", :limit => 10
94 - t.string "pretty_name"
95 - t.string "ext", :limit => 10
96 - t.string "common_ext"
92 + create_table "languages", force: :cascade do |t|
93 + t.string "name", limit: 10
94 + t.string "pretty_name", limit: 255
95 + t.string "ext", limit: 10
96 + t.string "common_ext", limit: 255
97 97 end
98 98
99 - create_table "logins", :force => true do |t|
100 - t.integer "user_id"
101 - t.string "ip_address"
102 - t.datetime "created_at", :null => false
103 - t.datetime "updated_at", :null => false
99 + create_table "logins", force: :cascade do |t|
100 + t.integer "user_id", limit: 4
101 + t.string "ip_address", limit: 255
102 + t.datetime "created_at", null: false
103 + t.datetime "updated_at", null: false
104 104 end
105 105
106 - create_table "messages", :force => true do |t|
107 - t.integer "sender_id"
108 - t.integer "receiver_id"
109 - t.integer "replying_message_id"
110 - t.text "body"
106 + create_table "messages", force: :cascade do |t|
107 + t.integer "sender_id", limit: 4
108 + t.integer "receiver_id", limit: 4
109 + t.integer "replying_message_id", limit: 4
110 + t.text "body", limit: 65535
111 111 t.boolean "replied"
112 - t.datetime "created_at", :null => false
113 - t.datetime "updated_at", :null => false
112 + t.datetime "created_at", null: false
113 + t.datetime "updated_at", null: false
114 114 end
115 115
116 - create_table "problems", :force => true do |t|
117 - t.string "name", :limit => 30
118 - t.string "full_name"
119 - t.integer "full_score"
116 + create_table "problems", force: :cascade do |t|
117 + t.string "name", limit: 30
118 + t.string "full_name", limit: 255
119 + t.integer "full_score", limit: 4
120 120 t.date "date_added"
121 121 t.boolean "available"
122 - t.string "url"
123 - t.integer "description_id"
122 + t.string "url", limit: 255
123 + t.integer "description_id", limit: 4
124 124 t.boolean "test_allowed"
125 125 t.boolean "output_only"
126 - t.string "description_filename"
126 + t.string "description_filename", limit: 255
127 + t.boolean "view_testcase"
127 128 end
128 129
129 - create_table "rights", :force => true do |t|
130 - t.string "name"
131 - t.string "controller"
132 - t.string "action"
130 + create_table "rights", force: :cascade do |t|
131 + t.string "name", limit: 255
132 + t.string "controller", limit: 255
133 + t.string "action", limit: 255
133 134 end
134 135
135 - create_table "rights_roles", :id => false, :force => true do |t|
136 - t.integer "right_id"
137 - t.integer "role_id"
136 + create_table "rights_roles", id: false, force: :cascade do |t|
137 + t.integer "right_id", limit: 4
138 + t.integer "role_id", limit: 4
138 139 end
139 140
140 - add_index "rights_roles", ["role_id"], :name => "index_rights_roles_on_role_id"
141 + add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree
141 142
142 - create_table "roles", :force => true do |t|
143 - t.string "name"
143 + create_table "roles", force: :cascade do |t|
144 + t.string "name", limit: 255
144 145 end
145 146
146 - create_table "roles_users", :id => false, :force => true do |t|
147 - t.integer "role_id"
148 - t.integer "user_id"
147 + create_table "roles_users", id: false, force: :cascade do |t|
148 + t.integer "role_id", limit: 4
149 + t.integer "user_id", limit: 4
149 150 end
150 151
151 - add_index "roles_users", ["user_id"], :name => "index_roles_users_on_user_id"
152 + add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree
152 153
153 - create_table "sessions", :force => true do |t|
154 - t.string "session_id"
155 - t.text "data"
154 + create_table "sessions", force: :cascade do |t|
155 + t.string "session_id", limit: 255
156 + t.text "data", limit: 65535
156 157 t.datetime "updated_at"
157 158 end
158 159
159 - add_index "sessions", ["session_id"], :name => "index_sessions_on_session_id"
160 - add_index "sessions", ["updated_at"], :name => "index_sessions_on_updated_at"
160 + add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree
161 + add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree
161 162
162 - create_table "sites", :force => true do |t|
163 - t.string "name"
163 + create_table "sites", force: :cascade do |t|
164 + t.string "name", limit: 255
164 165 t.boolean "started"
165 166 t.datetime "start_time"
166 - t.datetime "created_at", :null => false
167 - t.datetime "updated_at", :null => false
168 - t.integer "country_id"
169 - t.string "password"
167 + t.datetime "created_at", null: false
168 + t.datetime "updated_at", null: false
169 + t.integer "country_id", limit: 4
170 + t.string "password", limit: 255
170 171 end
171 172
172 - create_table "submission_view_logs", :force => true do |t|
173 - t.integer "user_id"
174 - t.integer "submission_id"
175 - t.datetime "created_at", :null => false
176 - t.datetime "updated_at", :null => false
173 + create_table "submission_view_logs", force: :cascade do |t|
174 + t.integer "user_id", limit: 4
175 + t.integer "submission_id", limit: 4
176 + t.datetime "created_at", null: false
177 + t.datetime "updated_at", null: false
177 178 end
178 179
179 - create_table "submissions", :force => true do |t|
180 - t.integer "user_id"
181 - t.integer "problem_id"
182 - t.integer "language_id"
183 - t.text "source"
184 - t.binary "binary"
180 + create_table "submissions", force: :cascade do |t|
181 + t.integer "user_id", limit: 4
182 + t.integer "problem_id", limit: 4
183 + t.integer "language_id", limit: 4
184 + t.text "source", limit: 65535
185 + t.binary "binary", limit: 65535
185 186 t.datetime "submitted_at"
186 187 t.datetime "compiled_at"
187 - t.text "compiler_message"
188 + t.text "compiler_message", limit: 65535
188 189 t.datetime "graded_at"
189 - t.integer "points"
190 - t.text "grader_comment"
191 - t.integer "number"
192 - t.string "source_filename"
193 - t.float "max_runtime"
194 - t.integer "peak_memory"
195 - t.integer "effective_code_length"
196 - t.string "ip_address"
190 + t.integer "points", limit: 4
191 + t.text "grader_comment", limit: 65535
192 + t.integer "number", limit: 4
193 + t.string "source_filename", limit: 255
194 + t.float "max_runtime", limit: 24
195 + t.integer "peak_memory", limit: 4
196 + t.integer "effective_code_length", limit: 4
197 + t.string "ip_address", limit: 255
197 198 end
198 199
199 - add_index "submissions", ["user_id", "problem_id", "number"], :name => "index_submissions_on_user_id_and_problem_id_and_number", :unique => true
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", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree
201 + add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree
201 202
202 - create_table "tasks", :force => true do |t|
203 - t.integer "submission_id"
203 + create_table "tasks", force: :cascade do |t|
204 + t.integer "submission_id", limit: 4
204 205 t.datetime "created_at"
205 - t.integer "status"
206 + t.integer "status", limit: 4
206 207 t.datetime "updated_at"
207 208 end
208 209
209 - create_table "test_pairs", :force => true do |t|
210 - t.integer "problem_id"
211 - t.text "input", :limit => 16777215
212 - t.text "solution", :limit => 16777215
213 - t.datetime "created_at", :null => false
214 - t.datetime "updated_at", :null => false
210 + add_index "tasks", ["submission_id"], name: "index_tasks_on_submission_id", using: :btree
211 +
212 + create_table "test_pairs", force: :cascade do |t|
213 + t.integer "problem_id", limit: 4
214 + t.text "input", limit: 16777215
215 + t.text "solution", limit: 16777215
216 + t.datetime "created_at", null: false
217 + t.datetime "updated_at", null: false
215 218 end
216 219
217 - create_table "test_requests", :force => true do |t|
218 - t.integer "user_id"
219 - t.integer "problem_id"
220 - t.integer "submission_id"
221 - t.string "input_file_name"
222 - t.string "output_file_name"
223 - t.string "running_stat"
224 - t.integer "status"
225 - t.datetime "updated_at", :null => false
220 + create_table "test_requests", force: :cascade do |t|
221 + t.integer "user_id", limit: 4
222 + t.integer "problem_id", limit: 4
223 + t.integer "submission_id", limit: 4
224 + t.string "input_file_name", limit: 255
225 + t.string "output_file_name", limit: 255
226 + t.string "running_stat", limit: 255
227 + t.integer "status", limit: 4
228 + t.datetime "updated_at", null: false
226 229 t.datetime "submitted_at"
227 230 t.datetime "compiled_at"
228 - t.text "compiler_message"
231 + t.text "compiler_message", limit: 65535
229 232 t.datetime "graded_at"
230 - t.string "grader_comment"
231 - t.datetime "created_at", :null => false
232 - t.float "running_time"
233 - t.string "exit_status"
234 - t.integer "memory_usage"
233 + t.string "grader_comment", limit: 255
234 + t.datetime "created_at", null: false
235 + t.float "running_time", limit: 24
236 + t.string "exit_status", limit: 255
237 + t.integer "memory_usage", limit: 4
235 238 end
236 239
237 - add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
240 + add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree
238 241
239 - create_table "testcases", :force => true do |t|
240 - t.integer "problem_id"
241 - t.integer "num"
242 - t.integer "group"
243 - t.integer "score"
244 - t.text "input"
245 - t.text "sol"
246 - t.datetime "created_at", :null => false
247 - t.datetime "updated_at", :null => false
242 + create_table "testcases", force: :cascade do |t|
243 + t.integer "problem_id", limit: 4
244 + t.integer "num", limit: 4
245 + t.integer "group", limit: 4
246 + t.integer "score", limit: 4
247 + t.text "input", limit: 4294967295
248 + t.text "sol", limit: 4294967295
249 + t.datetime "created_at"
250 + t.datetime "updated_at"
248 251 end
249 252
250 - add_index "testcases", ["problem_id"], :name => "index_testcases_on_problem_id"
253 + add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree
251 254
252 - create_table "user_contest_stats", :force => true do |t|
253 - t.integer "user_id"
255 + create_table "user_contest_stats", force: :cascade do |t|
256 + t.integer "user_id", limit: 4
254 257 t.datetime "started_at"
255 - t.datetime "created_at", :null => false
256 - t.datetime "updated_at", :null => false
258 + t.datetime "created_at", null: false
259 + t.datetime "updated_at", null: false
257 260 t.boolean "forced_logout"
258 261 end
259 262
260 - create_table "users", :force => true do |t|
261 - t.string "login", :limit => 50
262 - t.string "full_name"
263 - t.string "hashed_password"
264 - t.string "salt", :limit => 5
265 - t.string "alias"
266 - t.string "email"
267 - t.integer "site_id"
268 - t.integer "country_id"
269 - t.boolean "activated", :default => false
263 + create_table "users", force: :cascade do |t|
264 + t.string "login", limit: 50
265 + t.string "full_name", limit: 255
266 + t.string "hashed_password", limit: 255
267 + t.string "salt", limit: 5
268 + t.string "alias", limit: 255
269 + t.string "email", limit: 255
270 + t.integer "site_id", limit: 4
271 + t.integer "country_id", limit: 4
272 + t.boolean "activated", default: false
270 273 t.datetime "created_at"
271 274 t.datetime "updated_at"
272 - t.boolean "enabled", :default => true
273 - t.string "remark"
274 - t.string "last_ip"
275 - t.string "section"
275 + t.boolean "enabled", default: true
276 + t.string "remark", limit: 255
277 + t.string "last_ip", limit: 255
278 + t.string "section", limit: 255
276 279 end
277 280
278 - add_index "users", ["login"], :name => "index_users_on_login", :unique => true
281 + add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree
279 282
280 283 end
@@ -32,69 +32,97
32 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 36 :key => 'system.mode',
37 37 :value_type => 'string',
38 38 :default_value => 'standard',
39 39 :description => 'Current modes are "standard", "contest", "indv-contest", and "analysis".'
40 40 },
41 41
42 42 {
43 43 :key => 'contest.name',
44 44 :value_type => 'string',
45 45 :default_value => 'Grader',
46 46 :description => 'This name will be shown on the user header bar.'
47 47 },
48 48
49 49 {
50 50 :key => 'contest.multisites',
51 51 :value_type => 'boolean',
52 52 :default_value => 'false',
53 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 57 {
57 58 :key => 'right.user_hall_of_fame',
58 59 :value_type => 'boolean',
59 60 :default_value => 'false',
60 61 :description => 'If true, any user can access hall of fame page.'
61 62 },
62 63
63 64 {
64 65 :key => 'right.multiple_ip_login',
65 66 :value_type => 'boolean',
66 67 :default_value => 'true',
67 68 :description => 'When change from true to false, a user can login from the first IP they logged into afterward.'
68 69 },
69 70
70 71 {
71 72 :key => 'right.user_view_submission',
72 73 :value_type => 'boolean',
73 74 :default_value => 'false',
74 75 :description => 'If true, any user can view submissions of every one.'
75 76 },
76 77
78 + {
79 + :key => 'right.bypass_agreement',
80 + :value_type => 'boolean',
81 + :default_value => 'true',
82 + :description => 'When false, a user must accept usage agreement before login'
83 + },
84 +
85 + {
86 + :key => 'right.heartbeat_response',
87 + :value_type => 'string',
88 + :default_value => 'OK',
89 + :description => 'Heart beat response text'
90 + },
91 +
92 + {
93 + :key => 'right.heartbeat_response_full',
94 + :value_type => 'string',
95 + :default_value => 'OK',
96 + :description => 'Heart beat response text when user got full score (set this value to the empty string to disable this feature)'
97 + },
98 +
99 + {
100 + :key => 'right.view_testcase',
101 + :value_type => 'boolean',
102 + :default_value => 'false',
103 + :description => 'When true, any user can view/download test data'
104 + },
77 105 # If Configuration['system.online_registration'] is true, the
78 106 # system allows online registration, and will use these
79 107 # information for sending confirmation emails.
80 108 {
81 109 :key => 'system.online_registration.smtp',
82 110 :value_type => 'string',
83 111 :default_value => 'smtp.somehost.com'
84 112 },
85 113
86 114 {
87 115 :key => 'system.online_registration.from',
88 116 :value_type => 'string',
89 117 :default_value => 'your.email@address'
90 118 },
91 119
92 120 {
93 121 :key => 'system.admin_email',
94 122 :value_type => 'string',
95 123 :default_value => 'admin@admin.email'
96 124 },
97 125
98 126 {
99 127 :key => 'system.user_setting_enabled',
100 128 :value_type => 'boolean',
@@ -28,31 +28,46
28 28 GraderScript.call_grader "stop #{pid_str}"
29 29 end
30 30
31 31 def self.start_grader(env)
32 32 GraderScript.call_grader "#{env} queue --err-log &"
33 33 GraderScript.call_grader "#{env} test_request -err-log &"
34 34 end
35 35
36 36 def self.call_import_problem(problem_name,
37 37 problem_dir,
38 38 time_limit=1,
39 39 memory_limit=32,
40 40 checker_name='text')
41 41 if GraderScript.grader_control_enabled?
42 42 cur_dir = `pwd`.chomp
43 43 Dir.chdir(GRADER_ROOT_DIR)
44 44
45 45 script_name = File.join(GRADER_ROOT_DIR, "scripts/import_problem")
46 46 cmd = "#{script_name} #{problem_name} #{problem_dir} #{checker_name}" +
47 47 " -t #{time_limit} -m #{memory_limit}"
48 48
49 49 output = `#{cmd}`
50 50
51 51 Dir.chdir(cur_dir)
52 -
52 +
53 53 return "import CMD: #{cmd}\n" + output
54 54 end
55 55 return ''
56 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 73 end
@@ -17,48 +17,51
17 17 dirname = extract(tempfile)
18 18 return false if not dirname
19 19 if not import_to_db
20 20 @log_msg = GraderScript.call_import_problem(@problem.name,
21 21 dirname,
22 22 time_limit,
23 23 memory_limit,
24 24 checker_name)
25 25 else
26 26 # Import test data to test pairs.
27 27
28 28 @problem.test_pairs.clear
29 29 if import_test_pairs(dirname)
30 30 test_pair_count = TestPair.count :conditions => "problem_id = #{@problem.id}"
31 31 @log_msg = "Importing test pair successful. (#{test_pair_count} test pairs imported)"
32 32 else
33 33 @log_msg = "Importing test pair failed. (0 test pairs imported)"
34 34 end
35 35 end
36 36
37 37 @log_msg << import_problem_description(dirname)
38 38 @log_msg << import_problem_pdf(dirname)
39 39 @log_msg << import_full_score(dirname)
40 40
41 + #import test data
42 + @log_msg << GraderScript.call_import_testcase(@problem.name)
43 +
41 44 return true
42 45 end
43 46
44 47 protected
45 48
46 49 def self.long_ext(filename)
47 50 i = filename.index('.')
48 51 len = filename.length
49 52 return filename.slice(i..len)
50 53 end
51 54
52 55 def extract(tempfile)
53 56 testdata_filename = save_testdata_file(tempfile)
54 57 ext = TestdataImporter.long_ext(tempfile.original_filename)
55 58
56 59 extract_dir = File.join(GraderScript.raw_dir, @problem.name)
57 60 if File.exists? extract_dir
58 61 backup_count = 0
59 62 begin
60 63 backup_count += 1
61 64 backup_dirname = "#{extract_dir}.backup.#{backup_count}"
62 65 end while File.exists? backup_dirname
63 66 File.rename(extract_dir, backup_dirname)
64 67 end
@@ -1,18 +1,18
1 1 ENV["RAILS_ENV"] = "test"
2 2 require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
3 3
4 4 def clear_all_tasks
5 - Task.find(:all).each do |task|
5 + Task.all.each do |task|
6 6 task.destroy
7 7 end
8 8 end
9 9
10 10
11 11 clear_all_tasks
12 12
13 13 (1..1000).each do |i|
14 14 Task.create(:id => i,
15 15 :submission_id => i,
16 16 :status => Task::STATUS_INQUEUE)
17 17 end
18 18
@@ -1,14 +1,13
1 1 ENV["RAILS_ENV"] = "test"
2 2 require File.expand_path(File.dirname(__FILE__) + "/../../config/environment")
3 3
4 4 def clear_all_tasks
5 - Task.find(:all).each do |task|
5 + Task.all.each do |task|
6 6 task.destroy
7 7 end
8 8 end
9 9
10 - puts Task.find(:all,
11 - :conditions => {:status => Task::STATUS_COMPLETE}).length
10 + puts Task.where(status: Task::STATUS_COMPLETE).length
12 11
13 12 clear_all_tasks
14 13
@@ -1,5 +1,36
1 - # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 - one:
3 - id: 1
4 - two:
5 - id: 2
1 + Language_1:
2 + name: c
3 + pretty_name: C
4 + ext: c
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 1 # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 2
3 3 <%
4 4 User.public_class_method :encrypt
5 5
6 6 salt = "abc"
7 7 %>
8 8
9 9 john:
10 10 login: john
11 11 full_name: john
12 12 hashed_password: <%= User.encrypt("hello",salt) %>
13 13 salt: <%= salt %>
14 14 activated: true
15 15
16 - mary:
17 - login: mary
18 - full_name: mary
19 - hashed_password: <%= User.encrypt("goodbye",salt) %>
16 + admin:
17 + login: admin
18 + full_name: admin
19 + hashed_password: <%= User.encrypt("admin",salt) %>
20 20 salt: <%= salt %>
21 21 roles: admin
22 22 activated: true
23 23
24 24 james:
25 25 login: james
26 26 full_name: James
27 27 hashed_password: <%= User.encrypt("morning",salt) %>
28 28 salt: <%= salt %>
29 29 contests: contest_a
30 30 activated: true
31 31
32 32 jack:
33 33 login: jack
34 34 full_name: Jack
35 35 hashed_password: <%= User.encrypt("morning",salt) %>
36 36 salt: <%= salt %>
37 37 contests: contest_a, contest_b
38 38 activated: true
@@ -1,16 +1,27
1 1 ENV["RAILS_ENV"] = "test"
2 2 require File.expand_path('../../config/environment', __FILE__)
3 3 require 'rails/test_help'
4 4
5 + #reporter for beautiful result
6 + require "minitest/reporters"
7 + Minitest::Reporters.use!
8 +
9 + module SignInHelper
10 + def sign_in_as(user,password)
11 + post login_login_path, {login: user, password: password }
12 + end
13 + end
14 +
5 15 class ActiveSupport::TestCase
16 + include SignInHelper
6 17 # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order.
7 18 #
8 19 # Note: You'll currently still have to declare fixtures explicitly in integration tests
9 20 # -- they do not yet inherit this setting
10 21 fixtures :all
11 22
12 23 # Add more helper methods to be used by all tests here...
13 24
14 25 self.use_transactional_fixtures = true
15 26 self.use_instantiated_fixtures = false
16 27 end
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
deleted file
You need to be logged in to leave comments. Login now