diff --git a/Gemfile b/Gemfile --- a/Gemfile +++ b/Gemfile @@ -1,15 +1,20 @@ source 'https://rubygems.org' +#rails gem 'rails', '~>4.2.0' gem 'activerecord-session_store' -gem 'select2-rails' # Bundle edge Rails instead: # gem 'rails', :git => 'git://github.com/rails/rails.git' +#---------------- database --------------------- +#the database gem 'mysql2' +#for testing gem 'sqlite3' +#for dumping database into yaml +gem 'yaml_db' # Gems used only for assets and not required # in production environments by default. @@ -21,7 +26,8 @@ gem 'uglifier' - +gem 'haml' +gem 'haml-rails' # gem 'prototype-rails' # To use ActiveModel has_secure_password @@ -63,16 +69,20 @@ gem 'momentjs-rails' gem 'rails_bootstrap_sortable' +#----------- user interface ----------------- +#select 2 +gem 'select2-rails' #ace editor gem 'ace-rails-ap' +#paginator +gem 'will_paginate', '~> 3.0.7' -gem 'haml' -gem 'haml-rails' gem 'mail' gem 'rdiscount' -#gem 'test-unit' -gem 'will_paginate', '~> 3.0.7' gem 'dynamic_form' gem 'in_place_editing' gem 'verification', :git => 'https://github.com/sikachu/verification.git' + +#---------------- testiing ----------------------- +gem 'minitest-reporters' diff --git a/Gemfile.lock b/Gemfile.lock --- a/Gemfile.lock +++ b/Gemfile.lock @@ -51,6 +51,7 @@ minitest (~> 5.1) thread_safe (~> 0.3, >= 0.3.4) tzinfo (~> 1.1) + ansi (1.5.0) arel (6.0.4) autoprefixer-rails (6.6.0) execjs @@ -111,6 +112,11 @@ mime-types-data (3.2016.0521) mini_portile2 (2.1.0) minitest (5.10.1) + minitest-reporters (1.1.13) + ansi + builder + minitest (>= 5.0) + ruby-progressbar momentjs-rails (2.15.1) railties (>= 3.1) multi_json (1.12.1) @@ -149,6 +155,7 @@ rake (12.0.0) rdiscount (2.2.0.1) rouge (2.0.7) + ruby-progressbar (1.8.1) ruby_parser (3.8.3) sexp_processor (~> 4.1) sass (3.4.23) @@ -177,6 +184,9 @@ uglifier (3.0.4) execjs (>= 0.3.0, < 3) will_paginate (3.0.12) + yaml_db (0.4.2) + rails (>= 3.0, < 5.1) + rake (>= 0.8.7) PLATFORMS ruby @@ -200,6 +210,7 @@ jquery-timepicker-addon-rails jquery-ui-rails mail + minitest-reporters momentjs-rails mysql2 rails (~> 4.2.0) @@ -212,6 +223,7 @@ uglifier verification! will_paginate (~> 3.0.7) + yaml_db BUNDLED WITH 1.13.6 diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,7 +1,7 @@ class ApplicationController < ActionController::Base protect_from_forgery - before_filter :current_user + before_filter :current_user SINGLE_USER_MODE_CONF_KEY = 'system.single_user_mode' MULTIPLE_IP_LOGIN_CONF_KEY = 'right.multiple_ip_login' diff --git a/app/models/grader_configuration.rb b/app/models/grader_configuration.rb --- a/app/models/grader_configuration.rb +++ b/app/models/grader_configuration.rb @@ -11,7 +11,7 @@ CONTEST_TIME_LIMIT_KEY = 'contest.time_limit' MULTIPLE_IP_LOGIN_KEY = 'right.multiple_ip_login' VIEW_TESTCASE = 'right.view_testcase' - SINGLE_USER_KEY = 'system.single_user' + SINGLE_USER_KEY = 'system.single_user_mode' cattr_accessor :config_cache cattr_accessor :task_grading_info_cache diff --git a/db/schema.rb b/db/schema.rb --- a/db/schema.rb +++ b/db/schema.rb @@ -14,200 +14,200 @@ ActiveRecord::Schema.define(version: 20161031063337) do create_table "announcements", force: :cascade do |t| - t.string "author" - t.text "body" + t.string "author", limit: 255 + t.text "body", limit: 65535 t.boolean "published" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.boolean "frontpage", default: false - t.boolean "contest_only", default: false - t.string "title" - t.string "notes" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.boolean "frontpage", default: false + t.boolean "contest_only", default: false + t.string "title", limit: 255 + t.string "notes", limit: 255 end create_table "contests", force: :cascade do |t| - t.string "title" + t.string "title", limit: 255 t.boolean "enabled" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "name" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "name", limit: 255 end create_table "contests_problems", id: false, force: :cascade do |t| - t.integer "contest_id" - t.integer "problem_id" + t.integer "contest_id", limit: 4 + t.integer "problem_id", limit: 4 end create_table "contests_users", id: false, force: :cascade do |t| - t.integer "contest_id" - t.integer "user_id" + t.integer "contest_id", limit: 4 + t.integer "user_id", limit: 4 end create_table "countries", force: :cascade do |t| - t.string "name" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.string "name", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "descriptions", force: :cascade do |t| - t.text "body" + t.text "body", limit: 65535 t.boolean "markdowned" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "grader_configurations", force: :cascade do |t| - t.string "key" - t.string "value_type" - t.string "value" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.text "description" + t.string "key", limit: 255 + t.string "value_type", limit: 255 + t.string "value", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.text "description", limit: 65535 end create_table "grader_processes", force: :cascade do |t| - t.string "host" - t.integer "pid" - t.string "mode" + t.string "host", limit: 255 + t.integer "pid", limit: 4 + t.string "mode", limit: 255 t.boolean "active" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "task_id" - t.string "task_type" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "task_id", limit: 4 + t.string "task_type", limit: 255 t.boolean "terminated" end - add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid" + add_index "grader_processes", ["host", "pid"], name: "index_grader_processes_on_ip_and_pid", using: :btree create_table "heart_beats", force: :cascade do |t| - t.integer "user_id" - t.string "ip_address" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.string "status" + t.integer "user_id", limit: 4 + t.string "ip_address", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.string "status", limit: 255 end - add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at" + add_index "heart_beats", ["updated_at"], name: "index_heart_beats_on_updated_at", using: :btree create_table "languages", force: :cascade do |t| t.string "name", limit: 10 - t.string "pretty_name" + t.string "pretty_name", limit: 255 t.string "ext", limit: 10 - t.string "common_ext" + t.string "common_ext", limit: 255 end create_table "logins", force: :cascade do |t| - t.integer "user_id" - t.string "ip_address" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id", limit: 4 + t.string "ip_address", limit: 255 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "messages", force: :cascade do |t| - t.integer "sender_id" - t.integer "receiver_id" - t.integer "replying_message_id" - t.text "body" + t.integer "sender_id", limit: 4 + t.integer "receiver_id", limit: 4 + t.integer "replying_message_id", limit: 4 + t.text "body", limit: 65535 t.boolean "replied" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "problems", force: :cascade do |t| t.string "name", limit: 30 - t.string "full_name" - t.integer "full_score" + t.string "full_name", limit: 255 + t.integer "full_score", limit: 4 t.date "date_added" t.boolean "available" - t.string "url" - t.integer "description_id" + t.string "url", limit: 255 + t.integer "description_id", limit: 4 t.boolean "test_allowed" t.boolean "output_only" - t.string "description_filename" + t.string "description_filename", limit: 255 end create_table "rights", force: :cascade do |t| - t.string "name" - t.string "controller" - t.string "action" + t.string "name", limit: 255 + t.string "controller", limit: 255 + t.string "action", limit: 255 end create_table "rights_roles", id: false, force: :cascade do |t| - t.integer "right_id" - t.integer "role_id" + t.integer "right_id", limit: 4 + t.integer "role_id", limit: 4 end - add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id" + add_index "rights_roles", ["role_id"], name: "index_rights_roles_on_role_id", using: :btree create_table "roles", force: :cascade do |t| - t.string "name" + t.string "name", limit: 255 end create_table "roles_users", id: false, force: :cascade do |t| - t.integer "role_id" - t.integer "user_id" + t.integer "role_id", limit: 4 + t.integer "user_id", limit: 4 end - add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id" + add_index "roles_users", ["user_id"], name: "index_roles_users_on_user_id", using: :btree create_table "sessions", force: :cascade do |t| - t.string "session_id" - t.text "data" + t.string "session_id", limit: 255 + t.text "data", limit: 65535 t.datetime "updated_at" end - add_index "sessions", ["session_id"], name: "index_sessions_on_session_id" - add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at" + add_index "sessions", ["session_id"], name: "index_sessions_on_session_id", using: :btree + add_index "sessions", ["updated_at"], name: "index_sessions_on_updated_at", using: :btree create_table "sites", force: :cascade do |t| - t.string "name" + t.string "name", limit: 255 t.boolean "started" t.datetime "start_time" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false - t.integer "country_id" - t.string "password" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.integer "country_id", limit: 4 + t.string "password", limit: 255 end create_table "submission_view_logs", force: :cascade do |t| - t.integer "user_id" - t.integer "submission_id" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "user_id", limit: 4 + t.integer "submission_id", limit: 4 + t.datetime "created_at", null: false + t.datetime "updated_at", null: false end create_table "submissions", force: :cascade do |t| - t.integer "user_id" - t.integer "problem_id" - t.integer "language_id" - t.text "source" - t.binary "binary" + t.integer "user_id", limit: 4 + t.integer "problem_id", limit: 4 + t.integer "language_id", limit: 4 + t.text "source", limit: 65535 + t.binary "binary", limit: 65535 t.datetime "submitted_at" t.datetime "compiled_at" - t.text "compiler_message" + t.text "compiler_message", limit: 65535 t.datetime "graded_at" - t.integer "points" - t.text "grader_comment" - t.integer "number" - t.string "source_filename" - t.float "max_runtime" - t.integer "peak_memory" - t.integer "effective_code_length" - t.string "ip_address" + t.integer "points", limit: 4 + t.text "grader_comment", limit: 65535 + t.integer "number", limit: 4 + t.string "source_filename", limit: 255 + t.float "max_runtime", limit: 24 + t.integer "peak_memory", limit: 4 + t.integer "effective_code_length", limit: 4 + t.string "ip_address", limit: 255 end - add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true - add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id" + add_index "submissions", ["user_id", "problem_id", "number"], name: "index_submissions_on_user_id_and_problem_id_and_number", unique: true, using: :btree + add_index "submissions", ["user_id", "problem_id"], name: "index_submissions_on_user_id_and_problem_id", using: :btree create_table "tasks", force: :cascade do |t| - t.integer "submission_id" + t.integer "submission_id", limit: 4 t.datetime "created_at" - t.integer "status" + t.integer "status", limit: 4 t.datetime "updated_at" end create_table "test_pairs", force: :cascade do |t| - t.integer "problem_id" + t.integer "problem_id", limit: 4 t.text "input", limit: 16777215 t.text "solution", limit: 16777215 t.datetime "created_at", null: false @@ -215,66 +215,66 @@ end create_table "test_requests", force: :cascade do |t| - t.integer "user_id" - t.integer "problem_id" - t.integer "submission_id" - t.string "input_file_name" - t.string "output_file_name" - t.string "running_stat" - t.integer "status" - t.datetime "updated_at", null: false + t.integer "user_id", limit: 4 + t.integer "problem_id", limit: 4 + t.integer "submission_id", limit: 4 + t.string "input_file_name", limit: 255 + t.string "output_file_name", limit: 255 + t.string "running_stat", limit: 255 + t.integer "status", limit: 4 + t.datetime "updated_at", null: false t.datetime "submitted_at" t.datetime "compiled_at" - t.text "compiler_message" + t.text "compiler_message", limit: 65535 t.datetime "graded_at" - t.string "grader_comment" - t.datetime "created_at", null: false - t.float "running_time" - t.string "exit_status" - t.integer "memory_usage" + t.string "grader_comment", limit: 255 + t.datetime "created_at", null: false + t.float "running_time", limit: 24 + t.string "exit_status", limit: 255 + t.integer "memory_usage", limit: 4 end - add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id" + add_index "test_requests", ["user_id", "problem_id"], name: "index_test_requests_on_user_id_and_problem_id", using: :btree create_table "testcases", force: :cascade do |t| - t.integer "problem_id" - t.integer "num" - t.integer "group" - t.integer "score" - t.text "input" - t.text "sol" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.integer "problem_id", limit: 4 + t.integer "num", limit: 4 + t.integer "group", limit: 4 + t.integer "score", limit: 4 + t.text "input", limit: 65535 + t.text "sol", limit: 65535 + t.datetime "created_at" + t.datetime "updated_at" end - add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id" + add_index "testcases", ["problem_id"], name: "index_testcases_on_problem_id", using: :btree create_table "user_contest_stats", force: :cascade do |t| - t.integer "user_id" + t.integer "user_id", limit: 4 t.datetime "started_at" - t.datetime "created_at", null: false - t.datetime "updated_at", null: false + t.datetime "created_at", null: false + t.datetime "updated_at", null: false t.boolean "forced_logout" end create_table "users", force: :cascade do |t| t.string "login", limit: 50 - t.string "full_name" - t.string "hashed_password" + t.string "full_name", limit: 255 + t.string "hashed_password", limit: 255 t.string "salt", limit: 5 - t.string "alias" - t.string "email" - t.integer "site_id" - t.integer "country_id" - t.boolean "activated", default: false + t.string "alias", limit: 255 + t.string "email", limit: 255 + t.integer "site_id", limit: 4 + t.integer "country_id", limit: 4 + t.boolean "activated", default: false t.datetime "created_at" t.datetime "updated_at" - t.boolean "enabled", default: true - t.string "remark" - t.string "last_ip" - t.string "section" + t.boolean "enabled", default: true + t.string "remark", limit: 255 + t.string "last_ip", limit: 255 + t.string "section", limit: 255 end - add_index "users", ["login"], name: "index_users_on_login", unique: true + add_index "users", ["login"], name: "index_users_on_login", unique: true, using: :btree end diff --git a/lib/tasks/fixtures.rake b/lib/tasks/fixtures.rake new file mode 100644 --- /dev/null +++ b/lib/tasks/fixtures.rake @@ -0,0 +1,41 @@ +# Original from http://snippets.dzone.com/posts/show/4468 by MichaelBoutros +# +# Optimized version which uses to_yaml for content creation and checks +# that models are ActiveRecord::Base models before trying to fetch +# them from database. +namespace :db do + namespace :fixtures do + desc 'Dumps all models into fixtures.' + task :dump => :environment do + puts "rails root = #{Rails.root}" + models = Dir.glob(Rails.root.to_s + '/app/models/**.rb').map do |s| + Pathname.new(s).basename.to_s.gsub(/\.rb$/,'').camelize + end + + puts "Found models: " + models.join(', ') + + models.each do |m| + model = m.constantize + next unless model.ancestors.include?(ActiveRecord::Base) + + puts "Dumping model: " + m + entries = model.all.order(id: :asc) + + increment = 1 + + model_file = Rails.root.to_s + '/test/fixtures2/' + m.underscore.pluralize + '.yml' + File.open(model_file, 'w') do |f| + entries.each do |a| + attrs = a.attributes + attrs.delete_if{|k,v| v.blank?} + + output = {m + '_' + increment.to_s => attrs} + f << output.to_yaml.gsub(/^--- \n/,'') + "\n" + + increment += 1 + end + end + end + end + end +end diff --git a/test/fixtures/grader_configurations.yml b/test/fixtures/grader_configurations.yml new file mode 100644 --- /dev/null +++ b/test/fixtures/grader_configurations.yml @@ -0,0 +1,144 @@ +GraderConfiguration_1: + key: system.single_user_mode + value_type: boolean + value: 'false' + description: Only admins can log in to the system when running under single user mode. + +GraderConfiguration_2: + key: ui.front.title + value_type: string + value: Grader + +GraderConfiguration_3: + key: ui.front.welcome_message + value_type: string + value: Welcome! + +GraderConfiguration_4: + key: ui.show_score + value_type: boolean + value: 'true' + +GraderConfiguration_5: + key: contest.time_limit + value_type: string + value: unlimited + 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. + +GraderConfiguration_6: + key: system.mode + value_type: string + value: standard + description: Current modes are "standard", "contest", "indv-contest", and "analysis". + + +GraderConfiguration_7: + key: contest.name + value_type: string + value: Grader + description: This name will be shown on the user header bar. + + +GraderConfiguration_8: + key: contest.multisites + value_type: boolean + value: 'false' + 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. + + +GraderConfiguration_9: + key: right.user_hall_of_fame + value_type: boolean + value: 'false' + description: If true, any user can access hall of fame page. + + +GraderConfiguration_10: + key: right.multiple_ip_login + value_type: boolean + value: 'true' + description: When change from true to false, a user can login from the first IP + they logged into afterward. + + +GraderConfiguration_11: + key: right.user_view_submission + value_type: boolean + value: 'false' + description: If true, any user can view submissions of every one. + + +GraderConfiguration_12: + key: right.bypass_agreement + value_type: boolean + value: 'true' + description: When false, a user must accept usage agreement before login + + +GraderConfiguration_13: + key: right.heartbeat_response + value_type: string + value: OK + description: Heart beat response text + + +GraderConfiguration_14: + key: right.view_testcase + value_type: boolean + value: 'false' + description: When true, any user can view/download test data + + +GraderConfiguration_15: + key: system.online_registration.smtp + value_type: string + value: smtp.somehost.com + + +GraderConfiguration_16: + key: system.online_registration.from + value_type: string + value: your.email@address + + +GraderConfiguration_17: + key: system.admin_email + value_type: string + value: admin@admin.email + + +GraderConfiguration_18: + key: system.user_setting_enabled + value_type: boolean + value: 'true' + description: If this option is true, users can change their settings + + +GraderConfiguration_19: + key: contest.test_request.early_timeout + value_type: boolean + value: 'false' + + +GraderConfiguration_20: + key: system.multicontests + value_type: boolean + value: 'false' + + +GraderConfiguration_21: + key: contest.confirm_indv_contest_start + value_type: boolean + value: 'false' + + +GraderConfiguration_22: + key: contest.default_contest_name + value_type: string + value: none + description: New user will be assigned to this contest automatically, if it exists. Set + to 'none' if there is no default contest. + diff --git a/test/fixtures/languages.yml b/test/fixtures/languages.yml --- a/test/fixtures/languages.yml +++ b/test/fixtures/languages.yml @@ -1,5 +1,36 @@ -# Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -one: - id: 1 -two: - id: 2 +Language_1: + name: c + pretty_name: C + ext: c + common_ext: c + +Language_2: + name: cpp + pretty_name: C++ + ext: cpp + common_ext: cpp,cc + +Language_3: + name: pas + pretty_name: Pascal + ext: pas + common_ext: pas + +Language_4: + name: ruby + pretty_name: Ruby + ext: rb + common_ext: rb + +Language_5: + name: python + pretty_name: Python + ext: py + common_ext: py + +Language_6: + name: java + pretty_name: Java + ext: java + common_ext: java + diff --git a/test/integration/login_test.rb b/test/integration/login_test.rb --- a/test/integration/login_test.rb +++ b/test/integration/login_test.rb @@ -20,15 +20,18 @@ end test "normal user login in single_user mode" do - GraderConfiguration[GraderConfiguration::SINGLE_USER_KEY] = 'true' + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true') + GraderConfiguration.reload get root_path assert_response :success post login_login_path, {login: "john", password: "hello" } + follow_redirect! assert_redirected_to root_path end test "root login in in single_user mode" do - GraderConfiguration[GraderConfiguration::SINGLE_USER_KEY] = 'true' + GraderConfiguration.find_by(key: GraderConfiguration::SINGLE_USER_KEY).update_attributes(value: 'true') + GraderConfiguration.reload get root_path assert_response :success post login_login_path, {login: "admin", password: "admin" } diff --git a/test/test_helper.rb b/test/test_helper.rb --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,6 +2,10 @@ require File.expand_path('../../config/environment', __FILE__) require 'rails/test_help' +#reporter +require "minitest/reporters" +Minitest::Reporters.use! + class ActiveSupport::TestCase # Setup all fixtures in test/fixtures/*.(yml|csv) for all tests in alphabetical order. #