Description:
Merge branch 'master' into codejom: added individual contest mode
Commit status:
[Not Reviewed]
References:
merge default
Comments:
0 Commit comments 0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
Add another comment

r218:915a5c2d7529 - - 22 files changed: 274 inserted, 58 deleted

@@ -0,0 +1,30
1 + class ContestsController < ApplicationController
2 +
3 + before_filter :admin_authorization
4 +
5 + def index
6 + end
7 +
8 + def user_stat
9 + if not Configuration.indv_contest_mode?
10 + redirect_to :action => 'index' and return
11 + end
12 +
13 + @users = User.find(:all)
14 + @start_times = {}
15 + UserContestStat.find(:all).each do |stat|
16 + @start_times[stat.user_id] = stat.started_at
17 + end
18 + end
19 +
20 + def clear_all_stat
21 + if not Configuration.indv_contest_mode?
22 + redirect_to :action => 'index' and return
23 + end
24 +
25 + UserContestStat.delete_all()
26 + flash[:notice] = 'All start time statistic cleared.'
27 + redirect_to :action => 'index'
28 + end
29 +
30 + end
@@ -0,0 +1,2
1 + module ContestsHelper
2 + end
@@ -0,0 +1,14
1 + class UserContestStat < ActiveRecord::Base
2 +
3 + belongs_to :user
4 +
5 + def self.update_user_start_time(user)
6 + stat = user.contest_stat
7 + if stat == nil
8 + stat = UserContestStat.new(:user => user,
9 + :started_at => Time.now.gmtime)
10 + stat.save
11 + end
12 + end
13 +
14 + end
@@ -0,0 +1,4
1 + .submitbox
2 + %b Menu:
3 + = link_to '[View user start time]', :action => 'user_stat'
4 + = link_to '[Clear all start times]', {:action => 'clear_all_stat'}, {:confirm => 'Do you really want to clear all start time statistics?'}
@@ -0,0 +1,9
1 + %h1 Contest management
2 +
3 + - if (not Configuration.contest_mode?) and (not Configuration.indv_contest_mode?)
4 + Currently the system is not running in contest mode.
5 + - elsif Configuration.contest_mode?
6 + System running in normal contest mode.
7 + - else
8 + System running in individual contest mode.
9 + = render :partial => 'indv_contest_mode_index'
@@ -0,0 +1,24
1 + %h1 Individual Contest: User start time
2 +
3 + If you want to restart contest, you may want to
4 + %b
5 + = link_to '[clear all start times]', {:action => 'clear_all_stat'}, {:confirm => 'Do you really want to clear all start time statistics?'}
6 + so that users can participate again.
7 +
8 + %table.info
9 + %tr.info-head
10 + %th Login
11 + %th Start time
12 + %th Time left
13 + %th
14 + - @users.each_with_index do |user,i|
15 + %tr{:class => 'info-' + cycle('even','odd')}
16 + %td= user.login
17 + %td
18 + - if @start_times.has_key? user.id
19 + = @start_times[user.id]
20 + - else
21 + n/a
22 + %td= format_short_duration(user.contest_time_left)
23 + %td
24 + = link_to '[reset]', {:action => 'clear_stat', :id => user.id}, :confirm => 'Are you sure?'
@@ -0,0 +1,9
1 + class AddDescriptionToConfig < ActiveRecord::Migration
2 + def self.up
3 + add_column :configurations, :description, :text
4 + end
5 +
6 + def self.down
7 + remove_column :configurations, :description
8 + end
9 + end
@@ -0,0 +1,14
1 + class CreateUserContestStats < ActiveRecord::Migration
2 + def self.up
3 + create_table :user_contest_stats do |t|
4 + t.integer :user_id
5 + t.timestamp :started_at
6 +
7 + t.timestamps
8 + end
9 + end
10 +
11 + def self.down
12 + drop_table :user_contest_stats
13 + end
14 + end
@@ -0,0 +1,9
1 + # Read about fixtures at http://ar.rubyonrails.org/classes/Fixtures.html
2 +
3 + one:
4 + user_id: 1
5 + started_at: 2010-01-24 12:44:58
6 +
7 + two:
8 + user_id: 1
9 + started_at: 2010-01-24 12:44:58
@@ -0,0 +1,8
1 + require 'test_helper'
2 +
3 + class ContestsControllerTest < ActionController::TestCase
4 + # Replace this with your real tests.
5 + test "the truth" do
6 + assert true
7 + end
8 + end
@@ -0,0 +1,4
1 + require 'test_helper'
2 +
3 + class ContestsHelperTest < ActionView::TestCase
4 + end
@@ -0,0 +1,8
1 + require 'test_helper'
2 +
3 + class UserContestStatTest < ActiveSupport::TestCase
4 + # Replace this with your real tests.
5 + test "the truth" do
6 + assert true
7 + end
8 + end
@@ -17,58 +17,58
17 17 unless user.roles.detect { |role| allowed_roles.member?(role.name) }
18 18 flash[:notice] = 'You are not authorized to view the page you requested'
19 19 redirect_to :controller => 'main', :action => 'login'
20 20 return false
21 21 end
22 22 end
23 23
24 24 protected
25 25
26 26 def authenticate
27 27 unless session[:user_id]
28 28 redirect_to :controller => 'main', :action => 'login'
29 29 return false
30 30 end
31 31
32 32 #Configuration.reload
33 33 # check if run in single user mode
34 34 if (Configuration[SINGLE_USER_MODE_CONF_KEY])
35 35 user = User.find(session[:user_id])
36 36 if user==nil or user.login != 'root'
37 37 redirect_to :controller => 'main', :action => 'login'
38 38 return false
39 39 end
40 40 end
41 41
42 42 return true
43 43 end
44 44
45 45 def authorization
46 46 return false unless authenticate
47 47 user = User.find(session[:user_id])
48 48 unless user.roles.detect { |role|
49 49 role.rights.detect{ |right|
50 50 right.controller == self.class.controller_name and
51 51 (right.action == 'all' or right.action == action_name)
52 52 }
53 53 }
54 54 flash[:notice] = 'You are not authorized to view the page you requested'
55 55 #request.env['HTTP_REFERER'] ? (redirect_to :back) : (redirect_to :controller => 'login')
56 56 redirect_to :controller => 'main', :action => 'login'
57 57 return false
58 58 end
59 59 end
60 60
61 61 def verify_time_limit
62 62 return true if session[:user_id]==nil
63 63 user = User.find(session[:user_id], :include => :site)
64 64 return true if user==nil or user.site == nil
65 - if user.site.finished?
66 - flash[:notice] = 'Error: the contest on your site is over.'
65 + if user.contest_finished?
66 + flash[:notice] = 'Error: the contest you are participating is over.'
67 67 redirect_to :back
68 68 return false
69 69 end
70 70 return true
71 71 end
72 72
73 73 end
74 74
@@ -1,43 +1,40
1 1 class LoginController < ApplicationController
2 2
3 3 def index
4 4 # show login screen
5 5 reset_session
6 6 redirect_to :controller => 'main', :action => 'login'
7 7 end
8 8
9 9 def login
10 10 if user = User.authenticate(params[:login], params[:password])
11 11 session[:user_id] = user.id
12 + session[:admin] = user.admin?
13 + UserContestStat.update_user_start_time(user)
12 14 redirect_to :controller => 'main', :action => 'list'
13 - if user.admin?
14 - session[:admin] = true
15 - else
16 - session[:admin] = false
17 - end
18 15 else
19 16 flash[:notice] = 'Wrong password'
20 17 redirect_to :controller => 'main', :action => 'login'
21 18 end
22 19 end
23 20
24 21 def site_login
25 22 begin
26 23 site = Site.find(params[:login][:site_id])
27 24 rescue ActiveRecord::RecordNotFound
28 25 site = nil
29 26 end
30 27 if site==nil
31 28 flash[:notice] = 'Wrong site'
32 29 redirect_to :controller => 'main', :action => 'login' and return
33 30 end
34 31 if (site.password) and (site.password == params[:login][:password])
35 32 session[:site_id] = site.id
36 33 redirect_to :controller => 'site', :action => 'index'
37 34 else
38 35 flash[:notice] = 'Wrong site password'
39 36 redirect_to :controller => 'site', :action => 'login'
40 37 end
41 38 end
42 39
43 40 end
@@ -1,111 +1,108
1 1 class MainController < ApplicationController
2 2
3 - SYSTEM_MODE_CONF_KEY = 'system.mode'
4 -
5 3 before_filter :authenticate, :except => [:index, :login]
6 4 before_filter :check_viewability, :except => [:index, :login]
7 5
8 6 # COMMENTED OUT: filter in each action instead
9 7 # before_filter :verify_time_limit, :only => [:submit]
10 8
11 9 verify :method => :post, :only => [:submit, :download_input, :submit_solution],
12 10 :redirect_to => { :action => :index }
13 11
14 12 # COMMENT OUT: only need when having high load
15 13 # caches_action :index, :login
16 14
17 15 # NOTE: This method is not actually needed, 'config/routes.rb' has
18 16 # assigned action login as a default action.
19 17 def index
20 18 redirect_to :action => 'login'
21 19 end
22 20
23 21 def login
24 22 saved_notice = flash[:notice]
25 23 reset_session
26 24 flash[:notice] = saved_notice
27 25
28 26 # EXPERIMENT:
29 27 # Hide login if in single user mode and the url does not
30 28 # explicitly specify /login
31 29 #
32 30 # logger.info "PATH: #{request.path}"
33 31 # if Configuration['system.single_user_mode'] and
34 32 # request.path!='/main/login'
35 33 # @hidelogin = true
36 34 # end
37 35
38 36 @announcements = Announcement.find_for_frontpage
39 37 render :action => 'login', :layout => 'empty'
40 38 end
41 39
42 40 def list
43 41 prepare_list_information
44 42 end
45 43
46 44 def help
47 45 @user = User.find(session[:user_id])
48 46 end
49 47
50 48 def submit
51 49 user = User.find(session[:user_id])
52 50
53 51 @submission = Submission.new(params[:submission])
54 52 @submission.user = user
55 53 @submission.language_id = 0
56 54 if (params['file']) and (params['file']!='')
57 55 @submission.source = params['file'].read
58 56 @submission.source_filename = params['file'].original_filename
59 57 end
60 58 @submission.submitted_at = Time.new.gmtime
61 59
62 - if Configuration[SYSTEM_MODE_CONF_KEY]=='contest' and
63 - user.site!=nil and user.site.finished?
60 + if Configuration.time_limit_mode? and user.contest_finished?
64 61 @submission.errors.add_to_base "The contest is over."
65 62 prepare_list_information
66 63 render :action => 'list' and return
67 64 end
68 65
69 66 if @submission.valid?
70 67 if @submission.save == false
71 68 flash[:notice] = 'Error saving your submission'
72 69 elsif Task.create(:submission_id => @submission.id,
73 70 :status => Task::STATUS_INQUEUE) == false
74 71 flash[:notice] = 'Error adding your submission to task queue'
75 72 end
76 73 else
77 74 prepare_list_information
78 75 render :action => 'list' and return
79 76 end
80 77 redirect_to :action => 'list'
81 78 end
82 79
83 80 def source
84 81 submission = Submission.find(params[:id])
85 82 if submission.user_id == session[:user_id]
86 83 send_data(submission.source,
87 84 {:filename => submission.download_filename,
88 85 :type => 'text/plain'})
89 86 else
90 87 flash[:notice] = 'Error viewing source'
91 88 redirect_to :action => 'list'
92 89 end
93 90 end
94 91
95 92 def compiler_msg
96 93 @submission = Submission.find(params[:id])
97 94 if @submission.user_id == session[:user_id]
98 95 render :action => 'compiler_msg', :layout => 'empty'
99 96 else
100 97 flash[:notice] = 'Error viewing source'
101 98 redirect_to :action => 'list'
102 99 end
103 100 end
104 101
105 102 def submission
106 103 @user = User.find(session[:user_id])
107 104 @problems = Problem.find_available_problems
108 105 if params[:id]==nil
109 106 @problem = nil
110 107 @submissions = nil
111 108 else
@@ -1,78 +1,76
1 1 class TestController < ApplicationController
2 2
3 - SYSTEM_MODE_CONF_KEY = 'system.mode'
4 -
5 3 before_filter :authenticate, :check_viewability
6 4
7 5 #
8 6 # COMMENT OUT: filter in each action instead
9 7 #
10 8 # before_filter :verify_time_limit, :only => [:submit]
11 9
12 10 verify :method => :post, :only => [:submit],
13 11 :redirect_to => { :action => :index }
14 12
15 13 def index
16 14 prepare_index_information
17 15 end
18 16
19 17 def submit
20 18 @user = User.find(session[:user_id])
21 19
22 20 @submitted_test_request = TestRequest.new_from_form_params(@user,params[:test_request])
23 21
24 22 if @submitted_test_request.errors.length != 0
25 23 prepare_index_information
26 24 render :action => 'index' and return
27 25 end
28 26
29 - if Configuration[SYSTEM_MODE_CONF_KEY]=='contest'
30 - if @user.site!=nil and @user.site.finished?
27 + if Configuration.time_limit_mode?
28 + if @user.contest_finished?
31 29 @submitted_test_request.errors.add_to_base('Contest is over.')
32 30 prepare_index_information
33 31 render :action => 'index' and return
34 32 end
35 33
36 34 if !Configuration.allow_test_request(@user)
37 35 prepare_index_information
38 36 flash[:notice] = 'Test request is not allowed during the last 30 minutes'
39 37 redirect_to :action => 'index' and return
40 38 end
41 39 end
42 40
43 41 if @submitted_test_request.save
44 42 redirect_to :action => 'index'
45 43 else
46 44 prepare_index_information
47 45 render :action => 'index'
48 46 end
49 47 end
50 48
51 49 def read
52 50 user = User.find(session[:user_id])
53 51 begin
54 52 test_request = TestRequest.find(params[:id])
55 53 rescue
56 54 test_request = nil
57 55 end
58 56 if test_request==nil or test_request.user_id != user.id
59 57 flash[:notice] = 'Invalid output'
60 58 redirect_to :action => 'index'
61 59 return
62 60 end
63 61 if test_request.output_file_name!=nil
64 62 data = File.open(test_request.output_file_name).read(2048)
65 63 if data==nil
66 64 data=""
67 65 end
68 66 send_data(data,
69 67 {:filename => 'output.txt',
70 68 :type => 'text/plain'})
71 69 return
72 70 end
73 71 redirect_to :action => 'index'
74 72 end
75 73
76 74 def result
77 75 @user = User.find(session[:user_id])
78 76 begin
@@ -1,124 +1,127
1 1 # Methods added to this helper will be available to all templates in the application.
2 2 module ApplicationHelper
3 3
4 - SYSTEM_MODE_CONF_KEY = 'system.mode'
5 -
6 4 def user_header
7 5 menu_items = ''
8 6 user = User.find(session[:user_id])
9 7
10 8 if (user!=nil) and (session[:admin])
11 9 # admin menu
12 10 menu_items << "<b>Administrative task:</b> "
13 11 append_to menu_items, '[Announcements]', 'announcements', 'index'
14 12 append_to menu_items, '[Msg console]', 'messages', 'console'
15 - append_to menu_items, '[Problem admin]', 'problems', 'index'
16 - append_to menu_items, '[User admin]', 'user_admin', 'index'
13 + append_to menu_items, '[Problems]', 'problems', 'index'
14 + append_to menu_items, '[Users]', 'user_admin', 'index'
17 15 append_to menu_items, '[Results]', 'user_admin', 'user_stat'
18 16 append_to menu_items, '[Graders]', 'graders', 'list'
17 + append_to menu_items, '[Contests]', 'contests', 'index'
19 18 append_to menu_items, '[Sites]', 'sites', 'index'
20 19 append_to menu_items, '[System config]', 'configurations', 'index'
21 20 menu_items << "<br/>"
22 21 end
23 22
24 23 # main page
25 24 append_to menu_items, "[#{I18n.t 'menu.main'}]", 'main', 'list'
26 25 append_to menu_items, "[#{I18n.t 'menu.messages'}]", 'messages', 'list'
27 26
28 27 if (user!=nil) and (Configuration.show_tasks_to?(user))
29 28 append_to menu_items, "[#{I18n.t 'menu.tasks'}]", 'tasks', 'list'
30 29 append_to menu_items, "[#{I18n.t 'menu.submissions'}]", 'main', 'submission'
31 30 append_to menu_items, "[#{I18n.t 'menu.test'}]", 'test', 'index'
32 31 end
33 32 append_to menu_items, "[#{I18n.t 'menu.help'}]", 'main', 'help'
34 33
35 34 if Configuration['system.user_setting_enabled']
36 35 append_to menu_items, "[#{I18n.t 'menu.settings'}]", 'users', 'index'
37 36 end
38 37 append_to menu_items, "[#{I18n.t 'menu.log_out'}]", 'main', 'login'
39 38
40 39 menu_items
41 40 end
42 41
43 42 def append_to(option,label, controller, action)
44 43 option << ' ' if option!=''
45 44 option << link_to_unless_current(label,
46 45 :controller => controller,
47 46 :action => action)
48 47 end
49 48
50 49 def format_short_time(time)
51 50 now = Time.now.gmtime
52 51 st = ''
53 52 if (time.yday != now.yday) or
54 53 (time.year != now.year)
55 54 st = time.strftime("%x ")
56 55 end
57 56 st + time.strftime("%X")
58 57 end
59 58
59 + def format_short_duration(duration)
60 + return '' if duration==nil
61 + d = duration.to_f
62 + return Time.at(d).gmtime.strftime("%X")
63 + end
64 +
60 65 def read_textfile(fname,max_size=2048)
61 66 begin
62 67 File.open(fname).read(max_size)
63 68 rescue
64 69 nil
65 70 end
66 71 end
67 72
68 73 def user_title_bar(user)
69 74 header = ''
70 75 time_left = ''
71 76
72 77 #
73 78 # if the contest is over
74 - if Configuration[SYSTEM_MODE_CONF_KEY]=='contest'
75 - if user.site!=nil and user.site.finished?
79 + if Configuration.time_limit_mode?
80 + if user.contest_finished?
76 81 header = <<CONTEST_OVER
77 82 <tr><td colspan="2" align="center">
78 83 <span class="contest-over-msg">THE CONTEST IS OVER</span>
79 84 </td></tr>
80 85 CONTEST_OVER
81 86 end
82 - if !user.site.started
87 + if !user.contest_started?
83 88 time_left = "&nbsp;&nbsp;" + (t 'title_bar.contest_not_started')
84 89 else
85 - if user.site!=nil
86 - time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
87 - " #{Time.at(user.site.time_left).gmtime.strftime("%X")}"
88 - end
90 + time_left = "&nbsp;&nbsp;" + (t 'title_bar.remaining_time') +
91 + " #{format_short_duration(user.contest_time_left)}"
89 92 end
90 93 end
91 94
92 95 #
93 96 # if the contest is in the anaysis mode
94 - if Configuration[SYSTEM_MODE_CONF_KEY]=='analysis'
97 + if Configuration.analysis_mode?
95 98 header = <<ANALYSISMODE
96 99 <tr><td colspan="2" align="center">
97 100 <span class="contest-over-msg">ANALYSIS MODE</span>
98 101 </td></tr>
99 102 ANALYSISMODE
100 103 end
101 104
102 105 contest_name = Configuration['contest.name']
103 106
104 107 #
105 108 # build real title bar
106 109 <<TITLEBAR
107 110 <div class="title">
108 111 <table>
109 112 #{header}
110 113 <tr>
111 114 <td class="left-col">
112 115 #{user.full_name}<br/>
113 116 #{t 'title_bar.current_time'} #{format_short_time(Time.new)}
114 117 #{time_left}
115 118 <br/>
116 119 </td>
117 120 <td class="right-col">#{contest_name}</td>
118 121 </tr>
119 122 </table>
120 123 </div>
121 124 TITLEBAR
122 125 end
123 126
124 127 end
@@ -14,122 +14,159
14 14 @@configurations = nil
15 15 @@task_grading_info = nil
16 16
17 17 def self.get(key)
18 18 if @@cache
19 19 if @@configurations == nil
20 20 self.read_config
21 21 end
22 22 return @@configurations[key]
23 23 else
24 24 return Configuration.read_one_key(key)
25 25 end
26 26 end
27 27
28 28 def self.[](key)
29 29 self.get(key)
30 30 end
31 31
32 32 def self.reload
33 33 self.read_config
34 34 end
35 35
36 36 def self.clear
37 37 @@configurations = nil
38 38 end
39 39
40 40 def self.cache?
41 41 @@cache
42 42 end
43 43
44 44 def self.enable_caching
45 45 @@cache = true
46 46 end
47 47
48 48 #
49 49 # View decision
50 50 #
51 51 def self.show_submitbox_to?(user)
52 52 mode = get(SYSTEM_MODE_CONF_KEY)
53 53 return false if mode=='analysis'
54 54 if (mode=='contest')
55 55 return false if (user.site!=nil) and
56 56 ((user.site.started!=true) or (user.site.finished?))
57 57 end
58 58 return true
59 59 end
60 60
61 61 def self.show_tasks_to?(user)
62 - mode = get(SYSTEM_MODE_CONF_KEY)
63 - if (mode=='contest')
64 - return false if (user.site!=nil) and (user.site.started!=true)
62 + if time_limit_mode?
63 + return false if not user.contest_started?
65 64 end
66 65 return true
67 66 end
68 67
69 68 def self.show_grading_result
70 69 return (get(SYSTEM_MODE_CONF_KEY)=='analysis')
71 70 end
72 71
73 72 def self.allow_test_request(user)
74 73 mode = get(SYSTEM_MODE_CONF_KEY)
75 74 early_timeout = get(TEST_REQUEST_EARLY_TIMEOUT_KEY)
76 75 if (mode=='contest')
77 76 return false if ((user.site!=nil) and
78 77 ((user.site.started!=true) or
79 78 (early_timeout and (user.site.time_left < 30.minutes))))
80 79 end
81 80 return false if mode=='analysis'
82 81 return true
83 82 end
84 83
85 84 def self.task_grading_info
86 85 if @@task_grading_info==nil
87 86 read_grading_info
88 87 end
89 88 return @@task_grading_info
90 89 end
91 90
92 - def self.contest_mode
91 + def self.standard_mode?
92 + return get(SYSTEM_MODE_CONF_KEY) == 'standard'
93 + end
94 +
95 + def self.contest_mode?
93 96 return get(SYSTEM_MODE_CONF_KEY) == 'contest'
94 97 end
95 98
99 + def self.indv_contest_mode?
100 + return get(SYSTEM_MODE_CONF_KEY) == 'indv-contest'
101 + end
102 +
103 + def self.time_limit_mode?
104 + mode = get(SYSTEM_MODE_CONF_KEY)
105 + return ((mode == 'contest') or (mode == 'indv-contest'))
106 + end
107 +
108 + def self.analysis_mode?
109 + return get(SYSTEM_MODE_CONF_KEY) == 'analysis'
110 + end
111 +
112 + def self.contest_time_limit
113 + contest_time_str = Configuration['contest.time_limit']
114 +
115 + if not defined? @@contest_time_str
116 + @@contest_time_str = nil
117 + end
118 +
119 + if @@contest_time_str != contest_time_str
120 + @@contest_time_str = contest_time_str
121 + if tmatch = /(\d+):(\d+)/.match(contest_time_str)
122 + h = tmatch[1].to_i
123 + m = tmatch[2].to_i
124 +
125 + @@contest_time = h.hour + m.minute
126 + else
127 + @@contest_time = nil
128 + end
129 + end
130 + return @@contest_time
131 + end
132 +
96 133 protected
97 134
98 135 def self.convert_type(val,type)
99 136 case type
100 137 when 'string'
101 138 return val
102 139
103 140 when 'integer'
104 141 return val.to_i
105 142
106 143 when 'boolean'
107 144 return (val=='true')
108 145 end
109 146 end
110 147
111 148 def self.read_config
112 149 @@configurations = {}
113 150 Configuration.find(:all).each do |conf|
114 151 key = conf.key
115 152 val = conf.value
116 153 @@configurations[key] = Configuration.convert_type(val,conf.value_type)
117 154 end
118 155 end
119 156
120 157 def self.read_one_key(key)
121 158 conf = Configuration.find_by_key(key)
122 159 if conf
123 160 return Configuration.convert_type(conf.value,conf.value_type)
124 161 else
125 162 return nil
126 163 end
127 164 end
128 165
129 166 def self.read_grading_info
130 167 f = File.open(TASK_GRADING_INFO_FILENAME)
131 168 @@task_grading_info = YAML.load(f)
132 169 f.close
133 170 end
134 171
135 172 end
@@ -1,54 +1,46
1 1 class Site < ActiveRecord::Base
2 2
3 3 belongs_to :country
4 4 has_many :users
5 5
6 6 def clear_start_time_if_not_started
7 7 if !self.started
8 8 self.start_time = nil
9 9 end
10 10 end
11 11
12 12 def time_left
13 - contest_time = Configuration['contest.time_limit']
14 - if tmatch = /(\d+):(\d+)/.match(contest_time)
15 - h = tmatch[1].to_i
16 - m = tmatch[2].to_i
17 -
18 - contest_time = h.hour + m.minute
13 + contest_time = Configuration.contest_time_limit
19 14
20 - return contest_time if !self.started
15 + return nil if contest_time == nil
16 +
17 + return contest_time if !self.started
21 18
22 - current_time = Time.now.gmtime
23 - if self.start_time!=nil
24 - finish_time = self.start_time + contest_time
25 - else
26 - finish_time = current_time + contest_time
27 - end
19 + current_time = Time.now.gmtime
20 + if self.start_time!=nil
21 + finish_time = self.start_time + contest_time
22 + else
23 + finish_time = current_time + contest_time
24 + end
28 25
29 - if current_time > finish_time
30 - return current_time - current_time
31 - else
32 - finish_time - current_time
33 - end
26 + if current_time > finish_time
27 + return current_time - current_time
34 28 else
35 - nil
29 + return finish_time - current_time
36 30 end
37 31 end
38 32
39 33 def finished?
40 34 if !self.started
41 35 return false
42 36 end
43 37
44 - contest_time = Configuration['contest.time_limit']
45 - if tmatch = /(\d+):(\d+)/.match(contest_time)
46 - h = tmatch[1].to_i
47 - m = tmatch[2].to_i
48 - return Time.now.gmtime > (self.start_time + h.hour + m.minute)
38 + contest_time = Configuration.contest_time_limit
39 + if contest_time!=nil
40 + return Time.now.gmtime > (self.start_time + contest_time)
49 41 else
50 42 false
51 43 end
52 44 end
53 45
54 46 end
@@ -1,69 +1,71
1 1 require 'digest/sha1'
2 2
3 3 class User < ActiveRecord::Base
4 4
5 5 has_and_belongs_to_many :roles
6 6
7 7 has_many :test_requests, :order => "submitted_at DESC"
8 8
9 9 has_many :messages,
10 10 :class_name => "Message",
11 11 :foreign_key => "sender_id",
12 12 :order => 'created_at DESC'
13 13
14 14 has_many :replied_messages,
15 15 :class_name => "Message",
16 16 :foreign_key => "receiver_id",
17 17 :order => 'created_at DESC'
18 18
19 19 has_many :test_pair_assignments, :dependent => :delete_all
20 20 has_many :submission_statuses
21 21
22 + has_one :contest_stat, :class_name => "UserContestStat"
23 +
22 24 belongs_to :site
23 25 belongs_to :country
24 26
25 27 named_scope :activated_users, :conditions => {:activated => true}
26 28
27 29 validates_presence_of :login
28 30 validates_uniqueness_of :login
29 31 validates_format_of :login, :with => /^[\_A-Za-z0-9]+$/
30 32 validates_length_of :login, :within => 3..30
31 33
32 34 validates_presence_of :full_name
33 35 validates_length_of :full_name, :minimum => 1
34 36
35 37 validates_presence_of :password, :if => :password_required?
36 38 validates_length_of :password, :within => 4..20, :if => :password_required?
37 39 validates_confirmation_of :password, :if => :password_required?
38 40
39 41 validates_format_of :email,
40 42 :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i,
41 43 :if => :email_validation?
42 44 validate :uniqueness_of_email_from_activated_users,
43 45 :if => :email_validation?
44 46 validate :enough_time_interval_between_same_email_registrations,
45 47 :if => :email_validation?
46 48
47 49 # these are for ytopc
48 50 # disable for now
49 51 #validates_presence_of :province
50 52
51 53 attr_accessor :password
52 54
53 55 before_save :encrypt_new_password
54 56 before_save :assign_default_site
55 57
56 58 def self.authenticate(login, password)
57 59 user = find_by_login(login)
58 60 return user if user && user.authenticated?(password)
59 61 end
60 62
61 63 def authenticated?(password)
62 64 if self.activated
63 65 hashed_password == User.encrypt(password,self.salt)
64 66 else
65 67 false
66 68 end
67 69 end
68 70
69 71 def admin?
@@ -126,96 +128,144
126 128 elsif self.email==''
127 129 "(blank)"
128 130 else
129 131 self.email
130 132 end
131 133 end
132 134
133 135 def email_for_editing=(e)
134 136 self.email=e
135 137 end
136 138
137 139 def alias_for_editing
138 140 if self.alias==nil
139 141 "(unknown)"
140 142 elsif self.alias==''
141 143 "(blank)"
142 144 else
143 145 self.alias
144 146 end
145 147 end
146 148
147 149 def alias_for_editing=(e)
148 150 self.alias=e
149 151 end
150 152
151 153 def activation_key
152 154 if self.hashed_password==nil
153 155 encrypt_new_password
154 156 end
155 157 Digest::SHA1.hexdigest(self.hashed_password)[0..7]
156 158 end
157 159
158 160 def verify_activation_key(key)
159 161 key == activation_key
160 162 end
161 163
162 164 def self.random_password(length=5)
163 165 chars = 'abcdefghjkmnopqrstuvwxyz'
164 166 password = ''
165 167 length.times { password << chars[rand(chars.length - 1)] }
166 168 password
167 169 end
168 170
169 171 def self.find_non_admin_with_prefix(prefix='')
170 172 users = User.find(:all)
171 173 return users.find_all { |u| !(u.admin?) and u.login.index(prefix)==0 }
172 174 end
173 175
176 + # Contest information
177 +
178 + def contest_time_left
179 + if Configuration.contest_mode?
180 + return nil if site==nil
181 + return site.time_left
182 + elsif Configuration.indv_contest_mode?
183 + time_limit = Configuration.contest_time_limit
184 + if contest_stat==nil
185 + return (Time.now.gmtime + time_limit) - Time.now.gmtime
186 + else
187 + finish_time = contest_stat.started_at + time_limit
188 + current_time = Time.now.gmtime
189 + if current_time > finish_time
190 + return 0
191 + else
192 + return finish_time - current_time
193 + end
194 + end
195 + else
196 + return nil
197 + end
198 + end
199 +
200 + def contest_finished?
201 + if Configuration.contest_mode?
202 + return false if site==nil
203 + return site.finished?
204 + elsif Configuration.indv_contest_mode?
205 + time_limit = Configuration.contest_time_limit
206 +
207 + return false if contest_stat==nil
208 +
209 + return contest_time_left == 0
210 + else
211 + return false
212 + end
213 + end
214 +
215 + def contest_started?
216 + if Configuration.contest_mode?
217 + return true if site==nil
218 + return site.started
219 + else
220 + return true
221 + end
222 + end
223 +
174 224 protected
175 225 def encrypt_new_password
176 226 return if password.blank?
177 227 self.salt = (10+rand(90)).to_s
178 228 self.hashed_password = User.encrypt(self.password,self.salt)
179 229 end
180 230
181 231 def assign_default_site
182 232 # have to catch error when migrating (because self.site is not available).
183 233 begin
184 234 if self.site==nil
185 235 self.site = Site.find_by_name('default')
186 236 if self.site==nil
187 237 self.site = Site.find(1) # when 'default has be renamed'
188 238 end
189 239 end
190 240 rescue
191 241 end
192 242 end
193 243
194 244 def password_required?
195 245 self.hashed_password.blank? || !self.password.blank?
196 246 end
197 247
198 248 def self.encrypt(string,salt)
199 249 Digest::SHA1.hexdigest(salt + string)
200 250 end
201 251
202 252 def uniqueness_of_email_from_activated_users
203 253 user = User.activated_users.find_by_email(self.email)
204 254 if user and (user.login != self.login)
205 255 self.errors.add_to_base("Email has already been taken")
206 256 end
207 257 end
208 258
209 259 def enough_time_interval_between_same_email_registrations
210 260 return if !self.new_record?
211 261 return if self.activated
212 262 open_user = User.find_by_email(self.email,
213 263 :order => 'created_at DESC')
214 264 if open_user and open_user.created_at and
215 265 (open_user.created_at > Time.now.gmtime - 5.minutes)
216 266 self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)")
217 267 end
218 268 end
219 269
220 270 def email_validation?
221 271 begin
@@ -1,35 +1,34
1 1 - content_for :head do
2 2 = javascript_include_tag :defaults
3 3 %script{:type => 'text/javascript', :src => '/javascripts/announcement_refresh.js'}
4 4
5 5 = user_title_bar(@user)
6 6
7 7 - if @announcements.length!=0
8 8 .announcementbox
9 9 %span{:class => 'title'}
10 10 Announcements
11 11 #announcementbox-body
12 12 = render :partial => 'announcement', :collection => @announcements
13 13
14 14 %hr/
15 15
16 - - if (Configuration.contest_mode) and (@user.site!=nil) |
17 - and (@user.site.started!=true)
16 + - if (Configuration.contest_mode?) and (@user.site!=nil) and (@user.site.started!=true)
18 17 %p=t 'main.start_soon'
19 18
20 19 - if Configuration.show_tasks_to?(@user)
21 20 .problem-list
22 21 = render :partial => 'problem_title', :collection => @problems, :as => :problem
23 22 .problem-content
24 23 %span{:id => "problem-panel-filler"}
25 24 %b Welcome to Code Jom
26 25 %br/
27 26 Choose problems from the list on the right.
28 27 = render :partial => 'problem', :collection => @problems
29 28
30 29 %br{:clear=>'both'}/
31 30 %hr/
32 31
33 32 :javascript
34 33 Announcement.registerRefreshEventTimer();
35 34
@@ -1,78 +1,79
1 1 # This file is auto-generated from the current state of the database. Instead of editing this file,
2 2 # please use the migrations feature of Active Record to incrementally modify your database, and
3 3 # then regenerate this schema definition.
4 4 #
5 5 # Note that this schema.rb definition is the authoritative source for your database schema. If you need
6 6 # to create the application database on another system, you should be using db:schema:load, not running
7 7 # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations
8 8 # you'll amass, the slower it'll run and the greater likelihood for issues).
9 9 #
10 10 # It's strongly recommended to check this file into your version control system.
11 11
12 - ActiveRecord::Schema.define(:version => 20100123154326) do
12 + ActiveRecord::Schema.define(:version => 20100124054458) do
13 13
14 14 create_table "announcements", :force => true do |t|
15 15 t.string "author"
16 16 t.text "body"
17 17 t.boolean "published"
18 18 t.datetime "created_at"
19 19 t.datetime "updated_at"
20 20 t.boolean "frontpage", :default => false
21 21 t.boolean "contest_only", :default => false
22 22 t.string "title"
23 23 end
24 24
25 25 create_table "configurations", :force => true do |t|
26 26 t.string "key"
27 27 t.string "value_type"
28 28 t.string "value"
29 29 t.datetime "created_at"
30 30 t.datetime "updated_at"
31 + t.text "description"
31 32 end
32 33
33 34 create_table "countries", :force => true do |t|
34 35 t.string "name"
35 36 t.datetime "created_at"
36 37 t.datetime "updated_at"
37 38 end
38 39
39 40 create_table "descriptions", :force => true do |t|
40 41 t.text "body"
41 42 t.boolean "markdowned"
42 43 t.datetime "created_at"
43 44 t.datetime "updated_at"
44 45 end
45 46
46 47 create_table "grader_processes", :force => true do |t|
47 48 t.string "host", :limit => 20
48 49 t.integer "pid"
49 50 t.string "mode"
50 51 t.boolean "active"
51 52 t.datetime "created_at"
52 53 t.datetime "updated_at"
53 54 t.integer "task_id"
54 55 t.string "task_type"
55 56 t.boolean "terminated"
56 57 end
57 58
58 59 add_index "grader_processes", ["host", "pid"], :name => "index_grader_processes_on_ip_and_pid"
59 60
60 61 create_table "languages", :force => true do |t|
61 62 t.string "name", :limit => 10
62 63 t.string "pretty_name"
63 64 t.string "ext", :limit => 10
64 65 t.string "common_ext"
65 66 end
66 67
67 68 create_table "messages", :force => true do |t|
68 69 t.integer "sender_id"
69 70 t.integer "receiver_id"
70 71 t.integer "replying_message_id"
71 72 t.text "body"
72 73 t.boolean "replied"
73 74 t.datetime "created_at"
74 75 t.datetime "updated_at"
75 76 end
76 77
77 78 create_table "problems", :force => true do |t|
78 79 t.string "name", :limit => 30
@@ -161,65 +162,72
161 162 t.integer "submission_id"
162 163 t.datetime "created_at"
163 164 t.integer "status"
164 165 t.datetime "updated_at"
165 166 end
166 167
167 168 create_table "test_pair_assignments", :force => true do |t|
168 169 t.integer "user_id"
169 170 t.integer "problem_id"
170 171 t.integer "test_pair_id"
171 172 t.integer "test_pair_number"
172 173 t.integer "request_number"
173 174 t.datetime "created_at"
174 175 t.datetime "updated_at"
175 176 t.boolean "submitted"
176 177 end
177 178
178 179 create_table "test_pairs", :force => true do |t|
179 180 t.integer "problem_id"
180 181 t.text "input"
181 182 t.text "solution"
182 183 t.datetime "created_at"
183 184 t.datetime "updated_at"
184 185 t.integer "number"
185 186 end
186 187
187 188 create_table "test_requests", :force => true do |t|
188 189 t.integer "user_id"
189 190 t.integer "problem_id"
190 191 t.integer "submission_id"
191 192 t.string "input_file_name"
192 193 t.string "output_file_name"
193 194 t.string "running_stat"
194 195 t.integer "status"
195 196 t.datetime "updated_at"
196 197 t.datetime "submitted_at"
197 198 t.datetime "compiled_at"
198 199 t.text "compiler_message"
199 200 t.datetime "graded_at"
200 201 t.string "grader_comment"
201 202 t.datetime "created_at"
202 203 t.float "running_time"
203 204 t.string "exit_status"
204 205 t.integer "memory_usage"
205 206 end
206 207
207 208 add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id"
208 209
210 + create_table "user_contest_stats", :force => true do |t|
211 + t.integer "user_id"
212 + t.datetime "started_at"
213 + t.datetime "created_at"
214 + t.datetime "updated_at"
215 + end
216 +
209 217 create_table "users", :force => true do |t|
210 218 t.string "login", :limit => 50
211 219 t.string "full_name"
212 220 t.string "hashed_password"
213 221 t.string "salt", :limit => 5
214 222 t.string "alias"
215 223 t.string "email"
216 224 t.integer "site_id"
217 225 t.integer "country_id"
218 226 t.boolean "activated", :default => false
219 227 t.datetime "created_at"
220 228 t.datetime "updated_at"
221 229 end
222 230
223 231 add_index "users", ["login"], :name => "index_users_on_login", :unique => true
224 232
225 233 end
You need to be logged in to leave comments. Login now