diff --git a/app/controllers/user_admin_controller.rb b/app/controllers/user_admin_controller.rb --- a/app/controllers/user_admin_controller.rb +++ b/app/controllers/user_admin_controller.rb @@ -196,24 +196,31 @@ end note = [] + user_ids = {} lines.split("\n").each do |line| - puts line user = User.find_by_login(line.chomp) - puts user if user if operation=='add' - user.contests << contest + if ! user.contests.include? contest + user.contests << contest + end elsif operation=='remove' user.contests.delete(contest) else user.contests = [contest] end - + user.contest_stat.destroy if params[:reset_timer] note << user.login + user_ids[user.id] = true end end + + if params[:reset_timer] + logout_users(user_ids) + end + flash[:notice] = 'User(s) ' + note.join(', ') + ' were successfully modified. ' redirect_to :action => 'contest_management' @@ -324,4 +331,13 @@ end + def logout_users(user_ids) + sessions = ActiveRecord::SessionStore::Session.find(:all, :conditions => ["updated_at >= ?", 60.minutes.ago]) + sessions.each do |session| + if user_ids.has_key? session.data[:user_id] + session.destroy + end + end + end + end diff --git a/app/models/configuration.rb b/app/models/configuration.rb --- a/app/models/configuration.rb +++ b/app/models/configuration.rb @@ -7,6 +7,8 @@ SYSTEM_MODE_CONF_KEY = 'system.mode' TEST_REQUEST_EARLY_TIMEOUT_KEY = 'contest.test_request.early_timeout' + MULTICONTESTS_KEY = 'system.multicontests' + CONTEST_TIME_LIMIT_KEY = 'contest.time_limit' cattr_accessor :cache cattr_accessor :config_cache @@ -107,8 +109,7 @@ end def self.multicontests? - g = get('system.multicontests') - return get('system.multicontests') == true + return get(MULTICONTESTS_KEY) == true end def self.time_limit_mode? @@ -121,7 +122,7 @@ end def self.contest_time_limit - contest_time_str = Configuration['contest.time_limit'] + contest_time_str = Configuration[CONTEST_TIME_LIMIT_KEY] if not defined? Configuration.contest_time_str Configuration.contest_time_str = nil diff --git a/app/models/user.rb b/app/models/user.rb --- a/app/models/user.rb +++ b/app/models/user.rb @@ -154,10 +154,7 @@ return false if site==nil return site.finished? elsif Configuration.indv_contest_mode? - time_limit = Configuration.contest_time_limit - - return false if contest_stat==nil - + return false if self.contest_stat(true)==nil return contest_time_left == 0 else return false diff --git a/db/seeds.rb b/db/seeds.rb --- a/db/seeds.rb +++ b/db/seeds.rb @@ -29,7 +29,7 @@ :key => 'contest.time_limit', :value_type => 'string', :default_value => 'unlimited', - :description => 'Time limit in format hh:mm, or "unlimited" for contests with no time limits.' + :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.' }, { diff --git a/spec/config_spec_helper.rb b/spec/config_spec_helper.rb --- a/spec/config_spec_helper.rb +++ b/spec/config_spec_helper.rb @@ -10,11 +10,29 @@ end def enable_multicontest - find_or_create_and_set_config('system.multicontests','boolean','true') + find_or_create_and_set_config(Configuration::MULTICONTESTS_KEY, + 'boolean','true') end def disable_multicontest - find_or_create_and_set_config('system.multicontests','boolean','false') + find_or_create_and_set_config(Configuration::MULTICONTESTS_KEY, + 'boolean','false') + end + + def set_indv_contest_mode + find_or_create_and_set_config(Configuration::SYSTEM_MODE_CONF_KEY, + 'string','indv-contest') end + def set_standard_mode + find_or_create_and_set_config(Configuration::SYSTEM_MODE_CONF_KEY, + 'string','standard') + end + + def set_contest_time_limit(limit) + find_or_create_and_set_config(Configuration::CONTEST_TIME_LIMIT_KEY, + 'string',limit) + # clear old value + Configuration.contest_time_str = nil + end end diff --git a/spec/controllers/main_controller_spec.rb b/spec/controllers/main_controller_spec.rb --- a/spec/controllers/main_controller_spec.rb +++ b/spec/controllers/main_controller_spec.rb @@ -1,3 +1,5 @@ +require 'delorean' + require File.dirname(__FILE__) + '/../spec_helper' require File.dirname(__FILE__) + '/../config_spec_helper' @@ -142,3 +144,50 @@ end +describe MainController, "during individual contest mode" do + + integrate_views + + include ConfigSpecHelperMethods + + fixtures :users + fixtures :problems + fixtures :contests + + before(:each) do + set_contest_time_limit('3:00') # 3 hours + set_indv_contest_mode + end + + it "should allow newly login user to see problem list" do + john = users(:john) + get "list", {}, {:user_id => john.id} + + response.should render_template 'main/list' + response.should have_text(/add/) + response.should have_text(/easy_problem/) + response.should have_text(/hard_problem/) + end + + it "should not show 'contest over' sign before the contest ends" do + john = users(:john) + get "list", {}, {:user_id => john.id} + + Delorean.time_travel_to(179.minutes.since) do + get "list", {}, {:user_id => john.id} + response.should_not have_text(/OVER/) + end + end + + it "should show 'contest over' sign after the contest ends" do + john = users(:john) + get "list", {}, {:user_id => john.id} + + Delorean.time_travel_to(181.minutes.since) do + get "list", {}, {:user_id => john.id} + response.should have_text(/OVER/) + end + end + +end + diff --git a/spec/integration/contest_managements_spec.rb b/spec/integration/contest_managements_spec.rb new file mode 100644 --- /dev/null +++ b/spec/integration/contest_managements_spec.rb @@ -0,0 +1,87 @@ +require 'spec_helper' +require 'config_spec_helper' +require 'delorean' + +describe "ContestManagements" do + include ConfigSpecHelperMethods + + fixtures :users + fixtures :problems + fixtures :contests + fixtures :roles + + before(:each) do + @admin_user = users(:mary) + @contest_b = contests(:contest_b) + @james = users(:james) + @jack = users(:jack) + + set_contest_time_limit('3:00') + set_indv_contest_mode + end + + it "should reset users' timer when their contests change" do + james_session = open_session + james_session.extend(MainSessionMethods) + + james_login_and_get_main_list(james_session) + james_session.response.should_not have_text(/OVER/) + + Delorean.time_travel_to(190.minutes.since) do + james_session.get_main_list + james_session.response.should have_text(/OVER/) + + james_session.get '/' # logout + james_session.get '/main/list' # clearly log out + james_session.response.should_not render_template 'main/list' + + admin_change_users_contest_to("james", @contest_b, true) + + james_login_and_get_main_list(james_session) + james_session.response.should_not have_text(/OVER/) + end + end + + private + + module MainSessionMethods + def login(login_name, password) + post '/login/login', :login => login_name, :password => password + assert_redirected_to '/main/list' + end + + def get_main_list + get '/main/list' + assert_template 'main/list' + end + end + + module ContestManagementSessionMethods + def change_users_contest_to(user_login_list, contest, reset_timer=false) + post_data = { + :contest => {:id => contest.id}, + :operation => 'assign', + :login_list => user_login_list + } + post_data[:reset_timer] = true if reset_timer + post '/user_admin/manage_contest', post_data + end + end + + def admin_change_users_contest_to(user_list, contest, reset_timer) + admin_session = open_session + admin_session.extend(MainSessionMethods) + admin_session.extend(ContestManagementSessionMethods) + + admin_session.login('mary','goodbye') + admin_session.get '/main/list' + admin_session.change_users_contest_to(user_list, contest, reset_timer) + end + + def james_login_and_get_main_list(session) + session.login('james', 'morning') + session.get_main_list + end + +end + diff --git a/test/fixtures/roles.yml b/test/fixtures/roles.yml --- a/test/fixtures/roles.yml +++ b/test/fixtures/roles.yml @@ -1,3 +1,4 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html admin: + name: admin rights: graders_right, user_admin_right, problems_right \ No newline at end of file diff --git a/test/fixtures/sites.yml b/test/fixtures/sites.yml --- a/test/fixtures/sites.yml +++ b/test/fixtures/sites.yml @@ -1,11 +1,11 @@ # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html -one: - name: MyString +first_site: + name: First site started: false start_time: 2008-04-09 14:08:28 -two: - name: MyString +second_site: + name: Second site started: false start_time: 2008-04-09 14:08:28 diff --git a/test/fixtures/users.yml b/test/fixtures/users.yml --- a/test/fixtures/users.yml +++ b/test/fixtures/users.yml @@ -11,6 +11,7 @@ full_name: john hashed_password: <%= User.encrypt("hello",salt) %> salt: <%= salt %> + activated: true mary: login: mary @@ -18,6 +19,7 @@ hashed_password: <%= User.encrypt("goodbye",salt) %> salt: <%= salt %> roles: admin + activated: true james: login: james @@ -25,6 +27,7 @@ hashed_password: <%= User.encrypt("morning",salt) %> salt: <%= salt %> contests: contest_a + activated: true jack: login: jack @@ -32,3 +35,4 @@ hashed_password: <%= User.encrypt("morning",salt) %> salt: <%= salt %> contests: contest_a, contest_b + activated: true diff --git a/test/functional/announcements_controller_test.rb b/test/functional/announcements_controller_test.rb deleted file mode 100644 --- a/test/functional/announcements_controller_test.rb +++ /dev/null @@ -1,4 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class AnnouncementsControllerTest < ActionController::TestCase -end diff --git a/test/functional/configurations_controller_test.rb b/test/functional/configurations_controller_test.rb deleted file mode 100644 --- a/test/functional/configurations_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class ConfigurationsControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/test/functional/contest_management_controller_test.rb b/test/functional/contest_management_controller_test.rb deleted file mode 100644 --- a/test/functional/contest_management_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require 'test_helper' - -class ContestManagementControllerTest < ActionController::TestCase - # Replace this with your real tests. - test "the truth" do - assert true - end -end diff --git a/test/functional/contests_controller_test.rb b/test/functional/contests_controller_test.rb deleted file mode 100644 --- a/test/functional/contests_controller_test.rb +++ /dev/null @@ -1,4 +0,0 @@ -require 'test_helper' - -class ContestsControllerTest < ActionController::TestCase -end diff --git a/test/functional/main_controller_test.rb b/test/functional/main_controller_test.rb deleted file mode 100644 --- a/test/functional/main_controller_test.rb +++ /dev/null @@ -1,4 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class MainControllerTest < ActionController::TestCase -end diff --git a/test/functional/messages_controller_test.rb b/test/functional/messages_controller_test.rb deleted file mode 100644 --- a/test/functional/messages_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class MessagesControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/test/functional/problems_controller_test.rb b/test/functional/problems_controller_test.rb deleted file mode 100644 --- a/test/functional/problems_controller_test.rb +++ /dev/null @@ -1,92 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'problems_controller' - -# Re-raise errors caught by the controller. -class ProblemsController; def rescue_action(e) raise e end; end - -class ProblemsControllerTest < ActionController::TestCase - fixtures :problems - - def setup - @controller = ProblemsController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - - @first_id = problems(:first).id - end - - def test_index - get :index - assert_response :success - assert_template 'list' - end - - def test_list - get :list - - assert_response :success - assert_template 'list' - - assert_not_nil assigns(:problems) - end - - def test_show - get :show, :id => @first_id - - assert_response :success - assert_template 'show' - - assert_not_nil assigns(:problem) - assert assigns(:problem).valid? - end - - def test_new - get :new - - assert_response :success - assert_template 'new' - - assert_not_nil assigns(:problem) - end - - def test_create - num_problems = Problem.count - - post :create, :problem => {} - - assert_response :redirect - assert_redirected_to :action => 'list' - - assert_equal num_problems + 1, Problem.count - end - - def test_edit - get :edit, :id => @first_id - - assert_response :success - assert_template 'edit' - - assert_not_nil assigns(:problem) - assert assigns(:problem).valid? - end - - def test_update - post :update, :id => @first_id - assert_response :redirect - assert_redirected_to :action => 'show', :id => @first_id - end - - def test_destroy - assert_nothing_raised { - Problem.find(@first_id) - } - - post :destroy, :id => @first_id - assert_response :redirect - assert_redirected_to :action => 'list' - - assert_raise(ActiveRecord::RecordNotFound) { - Problem.find(@first_id) - } - end -end diff --git a/test/functional/site_controller_test.rb b/test/functional/site_controller_test.rb deleted file mode 100644 --- a/test/functional/site_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class SiteControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/test/functional/sites_controller_test.rb b/test/functional/sites_controller_test.rb deleted file mode 100644 --- a/test/functional/sites_controller_test.rb +++ /dev/null @@ -1,4 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class SitesControllerTest < ActionController::TestCase -end diff --git a/test/functional/tasks_controller_test.rb b/test/functional/tasks_controller_test.rb deleted file mode 100644 --- a/test/functional/tasks_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TasksControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/test/functional/test_controller_test.rb b/test/functional/test_controller_test.rb deleted file mode 100644 --- a/test/functional/test_controller_test.rb +++ /dev/null @@ -1,8 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' - -class TestControllerTest < ActionController::TestCase - # Replace this with your real tests. - def test_truth - assert true - end -end diff --git a/test/functional/users_controller_test.rb b/test/functional/users_controller_test.rb deleted file mode 100644 --- a/test/functional/users_controller_test.rb +++ /dev/null @@ -1,18 +0,0 @@ -require File.dirname(__FILE__) + '/../test_helper' -require 'users_controller' - -# Re-raise errors caught by the controller. -class UsersController; def rescue_action(e) raise e end; end - -class UsersControllerTest < ActionController::TestCase - def setup - @controller = UsersController.new - @request = ActionController::TestRequest.new - @response = ActionController::TestResponse.new - end - - # Replace this with your real tests. - def test_truth - assert true - end -end