Description:
Merged online-registration branch changes r297:303 into the trunk
git-svn-id: http://theory.cpe.ku.ac.th/grader/web/trunk@303 6386c4cd-e34a-4fa8-8920-d93eb39b512e
Commit status:
[Not Reviewed]
References:
Diff options:
Comments:
0 Commit comments
0 Inline Comments
Unresolved TODOs:
There are no unresolved TODOs
r158:13c9210ae5ca - - 16 files changed: 318 inserted, 29 deleted
@@ -0,0 +1,15 | |||||
|
|
1 | + - if @result == :successful | ||
|
|
2 | + %h1 User activated | ||
|
|
3 | + Your account has been activated. | ||
|
|
4 | + %br/ | ||
|
|
5 | + Please go ahead to | ||
|
|
6 | + = link_to 'login.', :controller => 'main', :action => 'login' | ||
|
|
7 | + - else | ||
|
|
8 | + %h1 Activation failed | ||
|
|
9 | + - if @result == :email_used | ||
|
|
10 | + A user with this E-mail exists. | ||
|
|
11 | + - else | ||
|
|
12 | + Your activation code is invalid. Please check again. | ||
|
|
13 | + %br/ | ||
|
|
14 | + Get back to | ||
|
|
15 | + = link_to 'home.', :controller => 'main', :action => 'login' |
@@ -0,0 +1,9 | |||||
|
|
1 | + %h1 Errors in sending registration confirmation | ||
|
|
2 | + | ||
|
|
3 | + .errorExplanation | ||
|
|
4 | + %h2 | ||
|
|
5 | + Your user account has been created, but the system cannot send you the | ||
|
|
6 | + confirmation e-mail. | ||
|
|
7 | + | ||
|
|
8 | + Maybe there's a problem in the configuration. Please report the | ||
|
|
9 | + admin. Thank you! |
@@ -0,0 +1,18 | |||||
|
|
1 | + class AddEmailingInfoOnConfigOption < ActiveRecord::Migration | ||
|
|
2 | + def self.up | ||
|
|
3 | + # If Configuration['system.online_registration'] is true, the | ||
|
|
4 | + # system allows online registration, and will use these | ||
|
|
5 | + # information for sending confirmation emails. | ||
|
|
6 | + Configuration.create(:key => 'system.online_registration.smtp', | ||
|
|
7 | + :value_type => 'string', | ||
|
|
8 | + :value => 'smtp.somehost.com') | ||
|
|
9 | + Configuration.create(:key => 'system.online_registration.from', | ||
|
|
10 | + :value_type => 'string', | ||
|
|
11 | + :value => 'your.email@address') | ||
|
|
12 | + end | ||
|
|
13 | + | ||
|
|
14 | + def self.down | ||
|
|
15 | + Configuration.find_by_key("system.online_registration.smtp").destroy | ||
|
|
16 | + Configuration.find_by_key("system.online_registration.from").destroy | ||
|
|
17 | + end | ||
|
|
18 | + end |
@@ -0,0 +1,9 | |||||
|
|
1 | + class AddTimestampsToUsers < ActiveRecord::Migration | ||
|
|
2 | + def self.up | ||
|
|
3 | + add_timestamps :users | ||
|
|
4 | + end | ||
|
|
5 | + | ||
|
|
6 | + def self.down | ||
|
|
7 | + remove_timestamps :users | ||
|
|
8 | + end | ||
|
|
9 | + end |
@@ -0,0 +1,95 | |||||
|
|
1 | + | ||
|
|
2 | + require File.dirname(__FILE__) + '/../spec_helper' | ||
|
|
3 | + | ||
|
|
4 | + describe UsersController, "when a new user registers" do | ||
|
|
5 | + | ||
|
|
6 | + before(:each) do | ||
|
|
7 | + # create john | ||
|
|
8 | + | ||
|
|
9 | + @john_info = {:login => 'john', | ||
|
|
10 | + :full_name => 'John John', | ||
|
|
11 | + :email => 'john@space.com'} | ||
|
|
12 | + @john = User.new(@john_info) | ||
|
|
13 | + | ||
|
|
14 | + @john_activation_key = "123456" | ||
|
|
15 | + | ||
|
|
16 | + @john.should_receive(:activation_key). | ||
|
|
17 | + any_number_of_times. | ||
|
|
18 | + and_return(@john_activation_key) | ||
|
|
19 | + | ||
|
|
20 | + get :new | ||
|
|
21 | + response.should render_template('users/new') | ||
|
|
22 | + end | ||
|
|
23 | + | ||
|
|
24 | + it "should show the new form again when user information is invalid" do | ||
|
|
25 | + User.should_receive(:new).with(any_args()).and_return(@john) | ||
|
|
26 | + @john.should_receive(:activated=).with(false) | ||
|
|
27 | + @john.should_receive(:valid?).and_return(false) | ||
|
|
28 | + @john.should_not_receive(:save) | ||
|
|
29 | + | ||
|
|
30 | + post :register, :login => @john_info[:login], | ||
|
|
31 | + :full_name => @john_info[:full_name], | ||
|
|
32 | + :email => @john_info[:email] | ||
|
|
33 | + | ||
|
|
34 | + response.should render_template('users/new') | ||
|
|
35 | + end | ||
|
|
36 | + | ||
|
|
37 | + it "should create unactivated user and send e-mail with activation key" do | ||
|
|
38 | + User.should_receive(:new).with(any_args()).and_return(@john) | ||
|
|
39 | + @john.should_receive(:activated=).with(false) | ||
|
|
40 | + @john.should_receive(:valid?).and_return(true) | ||
|
|
41 | + @john.should_receive(:save).and_return(true) | ||
|
|
42 | + | ||
|
|
43 | + smtp_mock = mock("smtp") | ||
|
|
44 | + smtp_mock.should_receive(:send_message) do |msg,fr,to| | ||
|
|
45 | + to.should == [@john_info[:email]] | ||
|
|
46 | + msg.index(@john_activation_key).should_not be_nil | ||
|
|
47 | + end | ||
|
|
48 | + | ||
|
|
49 | + Net::SMTP.should_receive(:start). | ||
|
|
50 | + with(any_args()). | ||
|
|
51 | + and_yield(smtp_mock) | ||
|
|
52 | + | ||
|
|
53 | + post :register, :login => @john_info[:login], | ||
|
|
54 | + :full_name => @john_info[:full_name], | ||
|
|
55 | + :email => @john_info[:email] | ||
|
|
56 | + | ||
|
|
57 | + response.should render_template('users/new_splash') | ||
|
|
58 | + end | ||
|
|
59 | + | ||
|
|
60 | + it "should create unactivated user and return error page when e-mail sending error" do | ||
|
|
61 | + User.should_receive(:new).with(any_args()).and_return(@john) | ||
|
|
62 | + @john.should_receive(:activated=).with(false) | ||
|
|
63 | + @john.should_receive(:valid?).and_return(true) | ||
|
|
64 | + @john.should_receive(:save).and_return(true) | ||
|
|
65 | + | ||
|
|
66 | + smtp_mock = mock("smtp") | ||
|
|
67 | + smtp_mock.should_receive(:send_message). | ||
|
|
68 | + and_throw(:error) | ||
|
|
69 | + | ||
|
|
70 | + Net::SMTP.should_receive(:start). | ||
|
|
71 | + with(any_args()). | ||
|
|
72 | + and_yield(smtp_mock) | ||
|
|
73 | + | ||
|
|
74 | + post :register, :login => @john_info[:login], | ||
|
|
75 | + :full_name => @john_info[:full_name], | ||
|
|
76 | + :email => @john_info[:email] | ||
|
|
77 | + | ||
|
|
78 | + response.should render_template('users/email_error') | ||
|
|
79 | + end | ||
|
|
80 | + | ||
|
|
81 | + it "should activate user with valid activation key" do | ||
|
|
82 | + login = @john_info[:login] | ||
|
|
83 | + User.should_receive(:find_by_login). | ||
|
|
84 | + with(login). | ||
|
|
85 | + and_return(@john) | ||
|
|
86 | + @john.should_receive(:valid?).and_return(true) | ||
|
|
87 | + @john.should_receive(:activated=).with(true) | ||
|
|
88 | + @john.should_receive(:save).and_return(true) | ||
|
|
89 | + | ||
|
|
90 | + get :confirm, :login => login, :activation => @john_activation_key | ||
|
|
91 | + | ||
|
|
92 | + response.should render_template('users/confirm') | ||
|
|
93 | + end | ||
|
|
94 | + | ||
|
|
95 | + end |
@@ -1,56 +1,116 | |||||
|
1 |
- require ' |
|
1 | + require 'tmail' |
|
|
2 | + require 'net/smtp' | ||
|
2 |
|
3 | ||
|
3 | class UsersController < ApplicationController |
|
4 | class UsersController < ApplicationController |
|
4 |
|
5 | ||
|
5 | - before_filter :authenticate, :except => [:new, :register] |
|
6 | + before_filter :authenticate, :except => [:new, :register, :confirm] |
|
6 |
|
7 | ||
|
7 | verify :method => :post, :only => [:chg_passwd], |
|
8 | verify :method => :post, :only => [:chg_passwd], |
|
8 | :redirect_to => { :action => :index } |
|
9 | :redirect_to => { :action => :index } |
|
9 |
|
10 | ||
|
10 | in_place_edit_for :user, :alias_for_editing |
|
11 | in_place_edit_for :user, :alias_for_editing |
|
11 | in_place_edit_for :user, :email_for_editing |
|
12 | in_place_edit_for :user, :email_for_editing |
|
12 |
|
13 | ||
|
13 | def index |
|
14 | def index |
|
14 | if !Configuration['system.user_setting_enabled'] |
|
15 | if !Configuration['system.user_setting_enabled'] |
|
15 | redirect_to :controller => 'main', :action => 'list' |
|
16 | redirect_to :controller => 'main', :action => 'list' |
|
16 | else |
|
17 | else |
|
17 | @user = User.find(session[:user_id]) |
|
18 | @user = User.find(session[:user_id]) |
|
18 | end |
|
19 | end |
|
19 | end |
|
20 | end |
|
20 |
|
21 | ||
|
21 | def chg_passwd |
|
22 | def chg_passwd |
|
22 | user = User.find(session[:user_id]) |
|
23 | user = User.find(session[:user_id]) |
|
23 | user.password = params[:passwd] |
|
24 | user.password = params[:passwd] |
|
24 | user.password_confirmation = params[:passwd_verify] |
|
25 | user.password_confirmation = params[:passwd_verify] |
|
25 | if user.save |
|
26 | if user.save |
|
26 | flash[:notice] = 'password changed' |
|
27 | flash[:notice] = 'password changed' |
|
27 | else |
|
28 | else |
|
28 | flash[:notice] = 'Error: password changing failed' |
|
29 | flash[:notice] = 'Error: password changing failed' |
|
29 | end |
|
30 | end |
|
30 | redirect_to :action => 'index' |
|
31 | redirect_to :action => 'index' |
|
31 | end |
|
32 | end |
|
32 |
|
33 | ||
|
33 | def new |
|
34 | def new |
|
34 | @user = User.new |
|
35 | @user = User.new |
|
35 | render :action => 'new', :layout => 'empty' |
|
36 | render :action => 'new', :layout => 'empty' |
|
36 | end |
|
37 | end |
|
37 |
|
38 | ||
|
38 | def register |
|
39 | def register |
|
39 | @user = User.new(params[:user]) |
|
40 | @user = User.new(params[:user]) |
|
40 | @user.password_confirmation = @user.password = User.random_password |
|
41 | @user.password_confirmation = @user.password = User.random_password |
|
41 | @user.activated = false |
|
42 | @user.activated = false |
|
42 | if (@user.valid?) and (@user.save) |
|
43 | if (@user.valid?) and (@user.save) |
|
43 | - send_confirmation_email(@user) |
|
44 | + if send_confirmation_email(@user) |
|
44 | - render :action => 'new_splash', :layout => 'empty' |
|
45 | + render :action => 'new_splash', :layout => 'empty' |
|
|
46 | + else | ||
|
|
47 | + render :action => 'email_error', :layout => 'empty' | ||
|
|
48 | + end | ||
|
45 | else |
|
49 | else |
|
46 | @user.errors.add_to_base("Email cannot be blank") if @user.email=='' |
|
50 | @user.errors.add_to_base("Email cannot be blank") if @user.email=='' |
|
47 | render :action => 'new', :layout => 'empty' |
|
51 | render :action => 'new', :layout => 'empty' |
|
48 | end |
|
52 | end |
|
49 | end |
|
53 | end |
|
50 |
|
54 | ||
|
|
55 | + def confirm | ||
|
|
56 | + login = params[:login] | ||
|
|
57 | + key = params[:activation] | ||
|
|
58 | + user = User.find_by_login(login) | ||
|
|
59 | + if (user) and (user.verify_activation_key(key)) | ||
|
|
60 | + if user.valid? # check uniquenss of email | ||
|
|
61 | + user.activated = true | ||
|
|
62 | + user.save | ||
|
|
63 | + @result = :successful | ||
|
|
64 | + else | ||
|
|
65 | + @result = :email_used | ||
|
|
66 | + end | ||
|
|
67 | + else | ||
|
|
68 | + @result = :failed | ||
|
|
69 | + end | ||
|
|
70 | + render :action => 'confirm', :layout => 'empty' | ||
|
|
71 | + end | ||
|
|
72 | + | ||
|
51 | protected |
|
73 | protected |
|
52 |
|
74 | ||
|
53 | def send_confirmation_email(user) |
|
75 | def send_confirmation_email(user) |
|
|
76 | + contest_name = Configuration['contest.name'] | ||
|
|
77 | + activation_url = url_for(:action => 'confirm', | ||
|
|
78 | + :login => user.login, | ||
|
|
79 | + :activation => user.activation_key) | ||
|
|
80 | + home_url = url_for(:controller => 'main', :action => 'index') | ||
|
|
81 | + mail = TMail::Mail.new | ||
|
|
82 | + mail.to = user.email | ||
|
|
83 | + mail.from = Configuration['system.online_registration.from'] | ||
|
|
84 | + mail.subject = "[#{contest_name}] Confirmation" | ||
|
|
85 | + mail.body = <<-EOF | ||
|
|
86 | + Hello #{user.full_name}, | ||
|
|
87 | + | ||
|
|
88 | + You have registered for #{contest_name} (#{home_url}). | ||
|
|
89 | + | ||
|
|
90 | + Your login is: #{user.login} | ||
|
|
91 | + Your password is: #{user.password} | ||
|
|
92 | + | ||
|
|
93 | + Please follow the link: | ||
|
|
94 | + #{activation_url} | ||
|
|
95 | + to activate your user account. | ||
|
|
96 | + | ||
|
|
97 | + If you did not register, please ignore this e-mail. | ||
|
|
98 | + | ||
|
|
99 | + Thanks! | ||
|
|
100 | + EOF | ||
|
|
101 | + | ||
|
|
102 | + smtp_server = Configuration['system.online_registration.smtp'] | ||
|
|
103 | + | ||
|
|
104 | + begin | ||
|
|
105 | + Net::SMTP.start(smtp_server) do |smtp| | ||
|
|
106 | + smtp.send_message(mail.to_s, mail.from, mail.to) | ||
|
|
107 | + end | ||
|
|
108 | + result = true | ||
|
|
109 | + rescue | ||
|
|
110 | + result = false | ||
|
|
111 | + end | ||
|
|
112 | + | ||
|
|
113 | + return result | ||
|
54 | end |
|
114 | end |
|
55 |
|
115 | ||
|
56 | end |
|
116 | end |
@@ -15,48 +15,52 | |||||
|
15 |
|
15 | ||
|
16 | def self.get(key) |
|
16 | def self.get(key) |
|
17 | if @@cache |
|
17 | if @@cache |
|
18 | if @@configurations == nil |
|
18 | if @@configurations == nil |
|
19 | self.read_config |
|
19 | self.read_config |
|
20 | end |
|
20 | end |
|
21 | return @@configurations[key] |
|
21 | return @@configurations[key] |
|
22 | else |
|
22 | else |
|
23 | return Configuration.read_one_key(key) |
|
23 | return Configuration.read_one_key(key) |
|
24 | end |
|
24 | end |
|
25 | end |
|
25 | end |
|
26 |
|
26 | ||
|
27 | def self.[](key) |
|
27 | def self.[](key) |
|
28 | self.get(key) |
|
28 | self.get(key) |
|
29 | end |
|
29 | end |
|
30 |
|
30 | ||
|
31 | def self.reload |
|
31 | def self.reload |
|
32 | self.read_config |
|
32 | self.read_config |
|
33 | end |
|
33 | end |
|
34 |
|
34 | ||
|
35 | def self.clear |
|
35 | def self.clear |
|
36 | @@configurations = nil |
|
36 | @@configurations = nil |
|
37 | end |
|
37 | end |
|
38 |
|
38 | ||
|
|
39 | + def self.enable_caching | ||
|
|
40 | + @@cache = true | ||
|
|
41 | + end | ||
|
|
42 | + | ||
|
39 | # |
|
43 | # |
|
40 | # View decision |
|
44 | # View decision |
|
41 | # |
|
45 | # |
|
42 | def self.show_submitbox_to?(user) |
|
46 | def self.show_submitbox_to?(user) |
|
43 | mode = get(SYSTEM_MODE_CONF_KEY) |
|
47 | mode = get(SYSTEM_MODE_CONF_KEY) |
|
44 | return false if mode=='analysis' |
|
48 | return false if mode=='analysis' |
|
45 | if (mode=='contest') |
|
49 | if (mode=='contest') |
|
46 | return false if (user.site!=nil) and |
|
50 | return false if (user.site!=nil) and |
|
47 | ((user.site.started!=true) or (user.site.finished?)) |
|
51 | ((user.site.started!=true) or (user.site.finished?)) |
|
48 | end |
|
52 | end |
|
49 | return true |
|
53 | return true |
|
50 | end |
|
54 | end |
|
51 |
|
55 | ||
|
52 | def self.show_tasks_to?(user) |
|
56 | def self.show_tasks_to?(user) |
|
53 | mode = get(SYSTEM_MODE_CONF_KEY) |
|
57 | mode = get(SYSTEM_MODE_CONF_KEY) |
|
54 | if (mode=='contest') |
|
58 | if (mode=='contest') |
|
55 | return false if (user.site!=nil) and (user.site.started!=true) |
|
59 | return false if (user.site!=nil) and (user.site.started!=true) |
|
56 | end |
|
60 | end |
|
57 | return true |
|
61 | return true |
|
58 | end |
|
62 | end |
|
59 |
|
63 | ||
|
60 | def self.show_grading_result |
|
64 | def self.show_grading_result |
|
61 | return (get(SYSTEM_MODE_CONF_KEY)=='analysis') |
|
65 | return (get(SYSTEM_MODE_CONF_KEY)=='analysis') |
|
62 | end |
|
66 | end |
@@ -1,62 +1,63 | |||||
|
1 | require 'digest/sha1' |
|
1 | require 'digest/sha1' |
|
2 |
|
2 | ||
|
3 | class User < ActiveRecord::Base |
|
3 | class User < ActiveRecord::Base |
|
4 |
|
4 | ||
|
5 | has_and_belongs_to_many :roles |
|
5 | has_and_belongs_to_many :roles |
|
6 |
|
6 | ||
|
7 | has_many :test_requests, :order => "submitted_at DESC" |
|
7 | has_many :test_requests, :order => "submitted_at DESC" |
|
8 |
|
8 | ||
|
9 | has_many :messages, |
|
9 | has_many :messages, |
|
10 | :class_name => "Message", |
|
10 | :class_name => "Message", |
|
11 | :foreign_key => "sender_id", |
|
11 | :foreign_key => "sender_id", |
|
12 | :order => 'created_at DESC' |
|
12 | :order => 'created_at DESC' |
|
13 |
|
13 | ||
|
14 | has_many :replied_messages, |
|
14 | has_many :replied_messages, |
|
15 | :class_name => "Message", |
|
15 | :class_name => "Message", |
|
16 | :foreign_key => "receiver_id", |
|
16 | :foreign_key => "receiver_id", |
|
17 | :order => 'created_at DESC' |
|
17 | :order => 'created_at DESC' |
|
18 |
|
18 | ||
|
19 | belongs_to :site |
|
19 | belongs_to :site |
|
20 | belongs_to :country |
|
20 | belongs_to :country |
|
21 |
|
21 | ||
|
22 | - named_scope :activated, :conditions => {:activated => true} |
|
22 | + named_scope :activated_users, :conditions => {:activated => true} |
|
23 |
|
23 | ||
|
24 | validates_presence_of :login |
|
24 | validates_presence_of :login |
|
25 | validates_uniqueness_of :login |
|
25 | validates_uniqueness_of :login |
|
26 | validates_format_of :login, :with => /^[\_a-z0-9]+$/ |
|
26 | validates_format_of :login, :with => /^[\_a-z0-9]+$/ |
|
27 | validates_length_of :login, :within => 3..10 |
|
27 | validates_length_of :login, :within => 3..10 |
|
28 |
|
28 | ||
|
29 | validates_presence_of :full_name |
|
29 | validates_presence_of :full_name |
|
30 | validates_length_of :full_name, :minimum => 1 |
|
30 | validates_length_of :full_name, :minimum => 1 |
|
31 |
|
31 | ||
|
32 | validates_presence_of :password, :if => :password_required? |
|
32 | validates_presence_of :password, :if => :password_required? |
|
33 | validates_length_of :password, :within => 4..20, :if => :password_required? |
|
33 | validates_length_of :password, :within => 4..20, :if => :password_required? |
|
34 | validates_confirmation_of :password, :if => :password_required? |
|
34 | validates_confirmation_of :password, :if => :password_required? |
|
35 |
|
35 | ||
|
36 | validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :allow_blank => true |
|
36 | validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :allow_blank => true |
|
37 |
|
37 | ||
|
38 | validate :uniqueness_of_email_from_activated_users |
|
38 | validate :uniqueness_of_email_from_activated_users |
|
|
39 | + validate :enough_time_interval_between_same_email_registrations | ||
|
39 |
|
40 | ||
|
40 | attr_accessor :password |
|
41 | attr_accessor :password |
|
41 |
|
42 | ||
|
42 | before_save :encrypt_new_password |
|
43 | before_save :encrypt_new_password |
|
43 |
|
44 | ||
|
44 | def self.authenticate(login, password) |
|
45 | def self.authenticate(login, password) |
|
45 | user = find_by_login(login) |
|
46 | user = find_by_login(login) |
|
46 | return user if user && user.authenticated?(password) |
|
47 | return user if user && user.authenticated?(password) |
|
47 | end |
|
48 | end |
|
48 |
|
49 | ||
|
49 | def authenticated?(password) |
|
50 | def authenticated?(password) |
|
50 | if self.activated |
|
51 | if self.activated |
|
51 | hashed_password == User.encrypt(password,self.salt) |
|
52 | hashed_password == User.encrypt(password,self.salt) |
|
52 | else |
|
53 | else |
|
53 | false |
|
54 | false |
|
54 | end |
|
55 | end |
|
55 | end |
|
56 | end |
|
56 |
|
57 | ||
|
57 | def admin? |
|
58 | def admin? |
|
58 | self.roles.detect {|r| r.name == 'admin' } |
|
59 | self.roles.detect {|r| r.name == 'admin' } |
|
59 | end |
|
60 | end |
|
60 |
|
61 | ||
|
61 | def email_for_editing |
|
62 | def email_for_editing |
|
62 | if self.email==nil |
|
63 | if self.email==nil |
@@ -66,59 +67,72 | |||||
|
66 | else |
|
67 | else |
|
67 | self.email |
|
68 | self.email |
|
68 | end |
|
69 | end |
|
69 | end |
|
70 | end |
|
70 |
|
71 | ||
|
71 | def email_for_editing=(e) |
|
72 | def email_for_editing=(e) |
|
72 | self.email=e |
|
73 | self.email=e |
|
73 | end |
|
74 | end |
|
74 |
|
75 | ||
|
75 | def alias_for_editing |
|
76 | def alias_for_editing |
|
76 | if self.alias==nil |
|
77 | if self.alias==nil |
|
77 | "(unknown)" |
|
78 | "(unknown)" |
|
78 | elsif self.alias=='' |
|
79 | elsif self.alias=='' |
|
79 | "(blank)" |
|
80 | "(blank)" |
|
80 | else |
|
81 | else |
|
81 | self.alias |
|
82 | self.alias |
|
82 | end |
|
83 | end |
|
83 | end |
|
84 | end |
|
84 |
|
85 | ||
|
85 | def alias_for_editing=(e) |
|
86 | def alias_for_editing=(e) |
|
86 | self.alias=e |
|
87 | self.alias=e |
|
87 | end |
|
88 | end |
|
88 |
|
89 | ||
|
89 | def activation_key |
|
90 | def activation_key |
|
|
91 | + if self.hashed_password==nil | ||
|
|
92 | + encrypt_new_password | ||
|
|
93 | + end | ||
|
90 | Digest::SHA1.hexdigest(self.hashed_password)[0..7] |
|
94 | Digest::SHA1.hexdigest(self.hashed_password)[0..7] |
|
91 | end |
|
95 | end |
|
92 |
|
96 | ||
|
93 | def verify_activation_key(key) |
|
97 | def verify_activation_key(key) |
|
94 | key == activation_key |
|
98 | key == activation_key |
|
95 | end |
|
99 | end |
|
96 |
|
100 | ||
|
97 | def self.random_password(length=5) |
|
101 | def self.random_password(length=5) |
|
98 | chars = 'abcdefghjkmnopqrstuvwxyz' |
|
102 | chars = 'abcdefghjkmnopqrstuvwxyz' |
|
99 | password = '' |
|
103 | password = '' |
|
100 | length.times { password << chars[rand(chars.length - 1)] } |
|
104 | length.times { password << chars[rand(chars.length - 1)] } |
|
101 | password |
|
105 | password |
|
102 | end |
|
106 | end |
|
103 |
|
107 | ||
|
104 | protected |
|
108 | protected |
|
105 | def encrypt_new_password |
|
109 | def encrypt_new_password |
|
106 | return if password.blank? |
|
110 | return if password.blank? |
|
107 | self.salt = (10+rand(90)).to_s |
|
111 | self.salt = (10+rand(90)).to_s |
|
108 | self.hashed_password = User.encrypt(self.password,self.salt) |
|
112 | self.hashed_password = User.encrypt(self.password,self.salt) |
|
109 | end |
|
113 | end |
|
110 |
|
114 | ||
|
111 | def password_required? |
|
115 | def password_required? |
|
112 | self.hashed_password.blank? || !self.password.blank? |
|
116 | self.hashed_password.blank? || !self.password.blank? |
|
113 | end |
|
117 | end |
|
114 |
|
118 | ||
|
115 | def self.encrypt(string,salt) |
|
119 | def self.encrypt(string,salt) |
|
116 | Digest::SHA1.hexdigest(salt + string) |
|
120 | Digest::SHA1.hexdigest(salt + string) |
|
117 | end |
|
121 | end |
|
118 |
|
122 | ||
|
119 | def uniqueness_of_email_from_activated_users |
|
123 | def uniqueness_of_email_from_activated_users |
|
120 |
- |
|
124 | + user = User.activated_users.find_by_email(self.email) |
|
|
125 | + if user and (user.login != self.login) | ||
|
121 | self.errors.add_to_base("Email has already been taken") |
|
126 | self.errors.add_to_base("Email has already been taken") |
|
122 | end |
|
127 | end |
|
123 | end |
|
128 | end |
|
|
129 | + | ||
|
|
130 | + def enough_time_interval_between_same_email_registrations | ||
|
|
131 | + open_user = User.find_by_email(self.email, | ||
|
|
132 | + :order => 'created_at DESC') | ||
|
|
133 | + if open_user and open_user.created_at and | ||
|
|
134 | + (open_user.created_at > Time.now.gmtime - 5.minutes) | ||
|
|
135 | + self.errors.add_to_base("There are already unactivated registrations with this e-mail address (please wait for 5 minutes)") | ||
|
|
136 | + end | ||
|
|
137 | + end | ||
|
124 | end |
|
138 | end |
@@ -29,46 +29,49 | |||||
|
29 | # Use the database for sessions instead of the file system |
|
29 | # Use the database for sessions instead of the file system |
|
30 | # (create the session table with 'rake db:sessions:create') |
|
30 | # (create the session table with 'rake db:sessions:create') |
|
31 | config.action_controller.session_store = :active_record_store |
|
31 | config.action_controller.session_store = :active_record_store |
|
32 |
|
32 | ||
|
33 | # Use SQL instead of Active Record's schema dumper when creating the test database. |
|
33 | # Use SQL instead of Active Record's schema dumper when creating the test database. |
|
34 | # This is necessary if your schema can't be completely dumped by the schema dumper, |
|
34 | # This is necessary if your schema can't be completely dumped by the schema dumper, |
|
35 | # like if you have constraints or database-specific column types |
|
35 | # like if you have constraints or database-specific column types |
|
36 | # config.active_record.schema_format = :sql |
|
36 | # config.active_record.schema_format = :sql |
|
37 |
|
37 | ||
|
38 | # Activate observers that should always be running |
|
38 | # Activate observers that should always be running |
|
39 | # config.active_record.observers = :cacher, :garbage_collector |
|
39 | # config.active_record.observers = :cacher, :garbage_collector |
|
40 |
|
40 | ||
|
41 | # Make Active Record use UTC-base instead of local time |
|
41 | # Make Active Record use UTC-base instead of local time |
|
42 | config.active_record.default_timezone = :utc |
|
42 | config.active_record.default_timezone = :utc |
|
43 |
|
43 | ||
|
44 | # See Rails::Configuration for more options |
|
44 | # See Rails::Configuration for more options |
|
45 |
|
45 | ||
|
46 | # ------------- |
|
46 | # ------------- |
|
47 | # Required gems |
|
47 | # Required gems |
|
48 | # ------------- |
|
48 | # ------------- |
|
49 |
|
49 | ||
|
50 | # This is for rspec |
|
50 | # This is for rspec |
|
51 | config.gem "rspec-rails", :lib => "spec" |
|
51 | config.gem "rspec-rails", :lib => "spec" |
|
52 | config.gem "haml" |
|
52 | config.gem "haml" |
|
53 |
- config.gem " |
|
53 | + config.gem "tmail" |
|
54 | #config.gem "BlueCloth", :lig => "bluecloth" |
|
54 | #config.gem "BlueCloth", :lig => "bluecloth" |
|
55 | end |
|
55 | end |
|
56 |
|
56 | ||
|
57 | # Add new inflection rules using the following format |
|
57 | # Add new inflection rules using the following format |
|
58 | # (all these examples are active by default): |
|
58 | # (all these examples are active by default): |
|
59 | # Inflector.inflections do |inflect| |
|
59 | # Inflector.inflections do |inflect| |
|
60 | # inflect.plural /^(ox)$/i, '\1en' |
|
60 | # inflect.plural /^(ox)$/i, '\1en' |
|
61 | # inflect.singular /^(ox)en/i, '\1' |
|
61 | # inflect.singular /^(ox)en/i, '\1' |
|
62 | # inflect.irregular 'person', 'people' |
|
62 | # inflect.irregular 'person', 'people' |
|
63 | # inflect.uncountable %w( fish sheep ) |
|
63 | # inflect.uncountable %w( fish sheep ) |
|
64 | # end |
|
64 | # end |
|
65 |
|
65 | ||
|
66 | # Add new mime types for use in respond_to blocks: |
|
66 | # Add new mime types for use in respond_to blocks: |
|
67 | # Mime::Type.register "text/richtext", :rtf |
|
67 | # Mime::Type.register "text/richtext", :rtf |
|
68 | # Mime::Type.register "application/x-mobile", :mobile |
|
68 | # Mime::Type.register "application/x-mobile", :mobile |
|
69 |
|
69 | ||
|
70 | # Include your application configuration below |
|
70 | # Include your application configuration below |
|
71 |
|
71 | ||
|
72 | # These are where inputs and outputs of test requests are stored |
|
72 | # These are where inputs and outputs of test requests are stored |
|
73 | TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input' |
|
73 | TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input' |
|
74 | TEST_REQUEST_OUTPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/output' |
|
74 | TEST_REQUEST_OUTPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/output' |
|
|
75 | + | ||
|
|
76 | + # Uncomment so that configuration is read only once when the server is loaded | ||
|
|
77 | + # Configuration.enable_caching |
@@ -1,36 +1,36 | |||||
|
1 | # This file is auto-generated from the current state of the database. Instead of editing this file, |
|
1 | # This file is auto-generated from the current state of the database. Instead of editing this file, |
|
2 | # please use the migrations feature of Active Record to incrementally modify your database, and |
|
2 | # please use the migrations feature of Active Record to incrementally modify your database, and |
|
3 | # then regenerate this schema definition. |
|
3 | # then regenerate this schema definition. |
|
4 | # |
|
4 | # |
|
5 | # Note that this schema.rb definition is the authoritative source for your database schema. If you need |
|
5 | # Note that this schema.rb definition is the authoritative source for your database schema. If you need |
|
6 | # to create the application database on another system, you should be using db:schema:load, not running |
|
6 | # to create the application database on another system, you should be using db:schema:load, not running |
|
7 | # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations |
|
7 | # all the migrations from scratch. The latter is a flawed and unsustainable approach (the more migrations |
|
8 | # you'll amass, the slower it'll run and the greater likelihood for issues). |
|
8 | # you'll amass, the slower it'll run and the greater likelihood for issues). |
|
9 | # |
|
9 | # |
|
10 | # It's strongly recommended to check this file into your version control system. |
|
10 | # It's strongly recommended to check this file into your version control system. |
|
11 |
|
11 | ||
|
12 |
- ActiveRecord::Schema.define(:version => 2008120 |
|
12 | + ActiveRecord::Schema.define(:version => 20081210021333) do |
|
13 |
|
13 | ||
|
14 | create_table "announcements", :force => true do |t| |
|
14 | create_table "announcements", :force => true do |t| |
|
15 | t.string "author" |
|
15 | t.string "author" |
|
16 | t.text "body" |
|
16 | t.text "body" |
|
17 | t.boolean "published" |
|
17 | t.boolean "published" |
|
18 | t.datetime "created_at" |
|
18 | t.datetime "created_at" |
|
19 | t.datetime "updated_at" |
|
19 | t.datetime "updated_at" |
|
20 | t.boolean "frontpage", :default => false |
|
20 | t.boolean "frontpage", :default => false |
|
21 | end |
|
21 | end |
|
22 |
|
22 | ||
|
23 | create_table "configurations", :force => true do |t| |
|
23 | create_table "configurations", :force => true do |t| |
|
24 | t.string "key" |
|
24 | t.string "key" |
|
25 | t.string "value_type" |
|
25 | t.string "value_type" |
|
26 | t.string "value" |
|
26 | t.string "value" |
|
27 | t.datetime "created_at" |
|
27 | t.datetime "created_at" |
|
28 | t.datetime "updated_at" |
|
28 | t.datetime "updated_at" |
|
29 | end |
|
29 | end |
|
30 |
|
30 | ||
|
31 | create_table "countries", :force => true do |t| |
|
31 | create_table "countries", :force => true do |t| |
|
32 | t.string "name" |
|
32 | t.string "name" |
|
33 | t.datetime "created_at" |
|
33 | t.datetime "created_at" |
|
34 | t.datetime "updated_at" |
|
34 | t.datetime "updated_at" |
|
35 | end |
|
35 | end |
|
36 |
|
36 | ||
@@ -153,38 +153,40 | |||||
|
153 |
|
153 | ||
|
154 | create_table "test_requests", :force => true do |t| |
|
154 | create_table "test_requests", :force => true do |t| |
|
155 | t.integer "user_id" |
|
155 | t.integer "user_id" |
|
156 | t.integer "problem_id" |
|
156 | t.integer "problem_id" |
|
157 | t.integer "submission_id" |
|
157 | t.integer "submission_id" |
|
158 | t.string "input_file_name" |
|
158 | t.string "input_file_name" |
|
159 | t.string "output_file_name" |
|
159 | t.string "output_file_name" |
|
160 | t.string "running_stat" |
|
160 | t.string "running_stat" |
|
161 | t.integer "status" |
|
161 | t.integer "status" |
|
162 | t.datetime "updated_at" |
|
162 | t.datetime "updated_at" |
|
163 | t.datetime "submitted_at" |
|
163 | t.datetime "submitted_at" |
|
164 | t.datetime "compiled_at" |
|
164 | t.datetime "compiled_at" |
|
165 | t.text "compiler_message" |
|
165 | t.text "compiler_message" |
|
166 | t.datetime "graded_at" |
|
166 | t.datetime "graded_at" |
|
167 | t.string "grader_comment" |
|
167 | t.string "grader_comment" |
|
168 | t.datetime "created_at" |
|
168 | t.datetime "created_at" |
|
169 | t.float "running_time" |
|
169 | t.float "running_time" |
|
170 | t.string "exit_status" |
|
170 | t.string "exit_status" |
|
171 | t.integer "memory_usage" |
|
171 | t.integer "memory_usage" |
|
172 | end |
|
172 | end |
|
173 |
|
173 | ||
|
174 | add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id" |
|
174 | add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id" |
|
175 |
|
175 | ||
|
176 | create_table "users", :force => true do |t| |
|
176 | create_table "users", :force => true do |t| |
|
177 | - t.string "login", :limit => 10 |
|
177 | + t.string "login", :limit => 10 |
|
178 | - t.string "full_name" |
|
178 | + t.string "full_name" |
|
179 | - t.string "hashed_password" |
|
179 | + t.string "hashed_password" |
|
180 | - t.string "salt", :limit => 5 |
|
180 | + t.string "salt", :limit => 5 |
|
181 | - t.string "alias" |
|
181 | + t.string "alias" |
|
182 | - t.string "email" |
|
182 | + t.string "email" |
|
183 | - t.integer "site_id" |
|
183 | + t.integer "site_id" |
|
184 | - t.integer "country_id" |
|
184 | + t.integer "country_id" |
|
185 | - t.boolean "activated", :default => false |
|
185 | + t.boolean "activated", :default => false |
|
|
186 | + t.datetime "created_at" | ||
|
|
187 | + t.datetime "updated_at" | ||
|
186 | end |
|
188 | end |
|
187 |
|
189 | ||
|
188 | add_index "users", ["login"], :name => "index_users_on_login", :unique => true |
|
190 | add_index "users", ["login"], :name => "index_users_on_login", :unique => true |
|
189 |
|
191 | ||
|
190 | end |
|
192 | end |
@@ -61,48 +61,56 | |||||
|
61 | background: #777777; |
|
61 | background: #777777; |
|
62 | color: white; |
|
62 | color: white; |
|
63 | } |
|
63 | } |
|
64 |
|
64 | ||
|
65 | tr.info-odd { |
|
65 | tr.info-odd { |
|
66 | background: #dddddd; |
|
66 | background: #dddddd; |
|
67 | } |
|
67 | } |
|
68 |
|
68 | ||
|
69 | tr.info-even { |
|
69 | tr.info-even { |
|
70 | background: #f0f0f0; |
|
70 | background: #f0f0f0; |
|
71 | } |
|
71 | } |
|
72 |
|
72 | ||
|
73 | /******************************* |
|
73 | /******************************* |
|
74 | [Main] |
|
74 | [Main] |
|
75 | ********************************/ |
|
75 | ********************************/ |
|
76 | div.submitbox { |
|
76 | div.submitbox { |
|
77 | border: thin solid black; |
|
77 | border: thin solid black; |
|
78 | padding: 5px; |
|
78 | padding: 5px; |
|
79 | color: white; |
|
79 | color: white; |
|
80 | background-color: #777777; |
|
80 | background-color: #777777; |
|
81 | font-weight: bold; |
|
81 | font-weight: bold; |
|
82 | font-size: 13px; |
|
82 | font-size: 13px; |
|
83 | } |
|
83 | } |
|
84 |
|
84 | ||
|
|
85 | + div.errorExplanation { | ||
|
|
86 | + border: 1px dashed black; | ||
|
|
87 | + color: black; | ||
|
|
88 | + padding: 5px; | ||
|
|
89 | + margin-bottom: 5px; | ||
|
|
90 | + background-color: white; | ||
|
|
91 | + } | ||
|
|
92 | + | ||
|
85 | /******************************* |
|
93 | /******************************* |
|
86 | [Settings] |
|
94 | [Settings] |
|
87 | ********************************/ |
|
95 | ********************************/ |
|
88 | table.uinfo { |
|
96 | table.uinfo { |
|
89 | border-collapse: collapse; |
|
97 | border-collapse: collapse; |
|
90 | border: 1px solid black; |
|
98 | border: 1px solid black; |
|
91 | font-size: 13px; |
|
99 | font-size: 13px; |
|
92 | } |
|
100 | } |
|
93 |
|
101 | ||
|
94 | td.uinfo { |
|
102 | td.uinfo { |
|
95 | vertical-align: top; |
|
103 | vertical-align: top; |
|
96 | border: 1px solid black; |
|
104 | border: 1px solid black; |
|
97 | padding: 5px; |
|
105 | padding: 5px; |
|
98 | } |
|
106 | } |
|
99 |
|
107 | ||
|
100 | th.uinfo { |
|
108 | th.uinfo { |
|
101 | background: lightgreen; |
|
109 | background: lightgreen; |
|
102 | vertical-align: top; |
|
110 | vertical-align: top; |
|
103 | text-align: right; |
|
111 | text-align: right; |
|
104 | border: 1px solid black; |
|
112 | border: 1px solid black; |
|
105 | padding: 5px; |
|
113 | padding: 5px; |
|
106 | } |
|
114 | } |
|
107 |
|
115 | ||
|
108 | /******************************* |
|
116 | /******************************* |
@@ -1,4 +1,5 | |||||
|
1 | #!/usr/bin/env ruby |
|
1 | #!/usr/bin/env ruby |
|
2 | $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib")) |
|
2 | $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib")) |
|
|
3 | + require 'rubygems' | ||
|
3 | require 'spec' |
|
4 | require 'spec' |
|
4 | exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT)) |
|
5 | exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT)) |
@@ -1,50 +1,55 | |||||
|
1 |
|
1 | ||
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 |
|
3 | ||
|
4 | describe MainController do |
|
4 | describe MainController do |
|
5 |
|
5 | ||
|
6 | before(:each) do |
|
6 | before(:each) do |
|
7 | - @problem = mock(Problem, :name => 'test') |
|
7 | + @problem = mock(Problem, :name => 'test', :output_only => false) |
|
8 | @language = mock(Language, :name => 'cpp', :ext => 'cpp') |
|
8 | @language = mock(Language, :name => 'cpp', :ext => 'cpp') |
|
9 | @submission = mock(Submission, |
|
9 | @submission = mock(Submission, |
|
10 | :id => 1, |
|
10 | :id => 1, |
|
11 | :user_id => 1, |
|
11 | :user_id => 1, |
|
12 | :problem => @problem, |
|
12 | :problem => @problem, |
|
13 | :language => @language, |
|
13 | :language => @language, |
|
14 | :source => 'sample source', |
|
14 | :source => 'sample source', |
|
15 | :compiler_message => 'none') |
|
15 | :compiler_message => 'none') |
|
16 | @user = mock(User, :id => 1, :login => 'john') |
|
16 | @user = mock(User, :id => 1, :login => 'john') |
|
|
17 | + @another_user = mock(User, :id => 2, :login => 'mary') | ||
|
17 | end |
|
18 | end |
|
18 |
|
19 | ||
|
19 | it "should redirect user to login page when unlogged-in user try to access main/list" do |
|
20 | it "should redirect user to login page when unlogged-in user try to access main/list" do |
|
20 | get 'list' |
|
21 | get 'list' |
|
21 | response.should redirect_to(:action => 'login') |
|
22 | response.should redirect_to(:action => 'login') |
|
22 | end |
|
23 | end |
|
23 |
|
24 | ||
|
24 | it "should let user sees her own source" do |
|
25 | it "should let user sees her own source" do |
|
25 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
26 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
|
27 | + User.should_receive(:find).with(1).and_return(@user) | ||
|
26 | get 'source', {:id => @submission.id}, {:user_id => 1} |
|
28 | get 'source', {:id => @submission.id}, {:user_id => 1} |
|
27 | response.should be_success |
|
29 | response.should be_success |
|
28 | end |
|
30 | end |
|
29 |
|
31 | ||
|
30 | it "should let user sees her own compiler message" do |
|
32 | it "should let user sees her own compiler message" do |
|
31 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
33 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
|
34 | + User.should_receive(:find).with(1).and_return(@user) | ||
|
32 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 1} |
|
35 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 1} |
|
33 | response.should be_success |
|
36 | response.should be_success |
|
34 | end |
|
37 | end |
|
35 |
|
38 | ||
|
36 | it "should not let user sees other user's source" do |
|
39 | it "should not let user sees other user's source" do |
|
37 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
40 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
|
41 | + User.should_receive(:find).with(2).and_return(@another_user) | ||
|
38 | get 'source', {:id => @submission.id}, {:user_id => 2} |
|
42 | get 'source', {:id => @submission.id}, {:user_id => 2} |
|
39 | flash[:notice].should =~ /[Ee]rror/ |
|
43 | flash[:notice].should =~ /[Ee]rror/ |
|
40 | response.should redirect_to(:action => 'list') |
|
44 | response.should redirect_to(:action => 'list') |
|
41 | end |
|
45 | end |
|
42 |
|
46 | ||
|
43 | it "should not let user sees other user's compiler message" do |
|
47 | it "should not let user sees other user's compiler message" do |
|
44 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
48 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
|
49 | + User.should_receive(:find).with(2).and_return(@another_user) | ||
|
45 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 2} |
|
50 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 2} |
|
46 | flash[:notice].should =~ /[Ee]rror/ |
|
51 | flash[:notice].should =~ /[Ee]rror/ |
|
47 | response.should redirect_to(:action => 'list') |
|
52 | response.should redirect_to(:action => 'list') |
|
48 | end |
|
53 | end |
|
49 |
|
54 | ||
|
50 | end |
|
55 | end |
@@ -1,28 +1,28 | |||||
|
1 |
|
1 | ||
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 |
|
3 | ||
|
4 | describe TestController do |
|
4 | describe TestController do |
|
5 |
|
5 | ||
|
6 | before(:each) do |
|
6 | before(:each) do |
|
7 | @john = mock(User, :id => "1", :login => 'john') |
|
7 | @john = mock(User, :id => "1", :login => 'john') |
|
8 | @john_result = mock(TestRequest, :id => "1", :user_id => @john.id) |
|
8 | @john_result = mock(TestRequest, :id => "1", :user_id => @john.id) |
|
9 | @mary_result = mock(TestRequest, :id => "2", :user_id => @john.id + '1') |
|
9 | @mary_result = mock(TestRequest, :id => "2", :user_id => @john.id + '1') |
|
10 | - User.should_receive(:find).with(@john.id).and_return(@john) |
|
10 | + User.should_receive(:find).at_least(:once).with(@john.id).and_return(@john) |
|
11 | end |
|
11 | end |
|
12 |
|
12 | ||
|
13 | it "should let user see her testing result" do |
|
13 | it "should let user see her testing result" do |
|
14 | TestRequest.should_receive(:find).with(@john_result.id). |
|
14 | TestRequest.should_receive(:find).with(@john_result.id). |
|
15 | and_return(@john_result) |
|
15 | and_return(@john_result) |
|
16 | get 'result', {:id => @john_result.id}, {:user_id => @john.id} |
|
16 | get 'result', {:id => @john_result.id}, {:user_id => @john.id} |
|
17 | response.should be_success |
|
17 | response.should be_success |
|
18 | end |
|
18 | end |
|
19 |
|
19 | ||
|
20 | it "should not let user see other's testing result" do |
|
20 | it "should not let user see other's testing result" do |
|
21 | TestRequest.should_receive(:find).with(@mary_result.id). |
|
21 | TestRequest.should_receive(:find).with(@mary_result.id). |
|
22 | and_return(@mary_result) |
|
22 | and_return(@mary_result) |
|
23 | get 'result', {:id => @mary_result.id}, {:user_id => @john.id} |
|
23 | get 'result', {:id => @mary_result.id}, {:user_id => @john.id} |
|
24 | response.should redirect_to(:action => 'index') |
|
24 | response.should redirect_to(:action => 'index') |
|
25 | end |
|
25 | end |
|
26 |
|
26 | ||
|
27 | end |
|
27 | end |
|
28 |
|
28 |
@@ -1,43 +1,48 | |||||
|
1 |
|
1 | ||
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 |
|
3 | ||
|
4 | describe Site do |
|
4 | describe Site do |
|
5 |
|
5 | ||
|
6 | before(:each) do |
|
6 | before(:each) do |
|
7 | - start_time = Time.local(2008,5,10,9,00) |
|
7 | + start_time = Time.local(2008,5,10,9,00).gmtime |
|
8 | @site = Site.new({:name => 'Test site', |
|
8 | @site = Site.new({:name => 'Test site', |
|
9 | :started => true, |
|
9 | :started => true, |
|
10 | :start_time => start_time }) |
|
10 | :start_time => start_time }) |
|
|
11 | + @site.stub!(:start_time). | ||
|
|
12 | + any_number_of_times. | ||
|
|
13 | + and_return(start_time) | ||
|
|
14 | + @site.stub!(:started).any_number_of_times.and_return(true) | ||
|
11 | end |
|
15 | end |
|
12 |
|
16 | ||
|
13 | it "should report that the contest is not finished when the contest time limit is not set" do |
|
17 | it "should report that the contest is not finished when the contest time limit is not set" do |
|
14 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
18 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
15 | and_return('unlimit') |
|
19 | and_return('unlimit') |
|
16 | - Time.should_not_receive(:now) |
|
||
|
17 | @site.finished?.should == false |
|
20 | @site.finished?.should == false |
|
18 | end |
|
21 | end |
|
19 |
|
22 | ||
|
20 | it "should report that the contest is finished when the contest is over" do |
|
23 | it "should report that the contest is finished when the contest is over" do |
|
21 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
24 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
22 |
- |
|
25 | + and_return('5:00') |
|
23 | - Time.should_receive(:now).and_return(Time.local(2008,5,10,14,01)) |
|
26 | + Time.stub!(:now). |
|
24 | - @site.finished?.should == true |
|
27 | + and_return(Time.local(2008,5,10,14,01).gmtime) |
|
25 | - end |
|
28 | + @site.finished?.should == true end |
|
26 |
|
29 | ||
|
27 | it "should report if the contest is finished correctly, when the contest is over, and the contest time contains some minutes" do |
|
30 | it "should report if the contest is finished correctly, when the contest is over, and the contest time contains some minutes" do |
|
28 | Configuration.should_receive(:[]).twice.with('contest.time_limit'). |
|
31 | Configuration.should_receive(:[]).twice.with('contest.time_limit'). |
|
29 | and_return('5:15') |
|
32 | and_return('5:15') |
|
30 |
- Time.s |
|
33 | + Time.stub!(:now). |
|
31 |
- and_return(Time.local(2008,5,10,14,14) |
|
34 | + and_return(Time.local(2008,5,10,14,14)) |
|
32 | @site.finished?.should == false |
|
35 | @site.finished?.should == false |
|
|
36 | + Time.stub!(:now). | ||
|
|
37 | + and_return(Time.local(2008,5,10,14,16)) | ||
|
33 | @site.finished?.should == true |
|
38 | @site.finished?.should == true |
|
34 | end |
|
39 | end |
|
35 |
|
40 | ||
|
36 | it "should report that the contest is not finished, when the time is exactly at the finish time" do |
|
41 | it "should report that the contest is not finished, when the time is exactly at the finish time" do |
|
37 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
42 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
38 | and_return('5:00') |
|
43 | and_return('5:00') |
|
39 |
- Time.s |
|
44 | + Time.stub!(:now).and_return(Time.local(2008,5,10,14,00)) |
|
40 | @site.finished?.should == false |
|
45 | @site.finished?.should == false |
|
41 | end |
|
46 | end |
|
42 |
|
47 | ||
|
43 | end |
|
48 | end |
@@ -27,37 +27,78 | |||||
|
27 | end |
|
27 | end |
|
28 |
|
28 | ||
|
29 | end |
|
29 | end |
|
30 |
|
30 | ||
|
31 | describe User, "during registration" do |
|
31 | describe User, "during registration" do |
|
32 |
|
32 | ||
|
33 | class User |
|
33 | class User |
|
34 | public :encrypt_new_password |
|
34 | public :encrypt_new_password |
|
35 | end |
|
35 | end |
|
36 |
|
36 | ||
|
37 | before(:each) do |
|
37 | before(:each) do |
|
38 | @john = User.new(:login => 'john', :password => 'hello') |
|
38 | @john = User.new(:login => 'john', :password => 'hello') |
|
39 | @john.encrypt_new_password |
|
39 | @john.encrypt_new_password |
|
40 | end |
|
40 | end |
|
41 |
|
41 | ||
|
42 | it "should produce and accept activation key" do |
|
42 | it "should produce and accept activation key" do |
|
43 | activation_key = @john.activation_key |
|
43 | activation_key = @john.activation_key |
|
44 |
|
44 | ||
|
45 | @john.verify_activation_key(activation_key).should == true |
|
45 | @john.verify_activation_key(activation_key).should == true |
|
46 | end |
|
46 | end |
|
47 |
|
47 | ||
|
48 | it "should not accept invalid activation key" do |
|
48 | it "should not accept invalid activation key" do |
|
49 | @john.verify_activation_key("12345").should == false |
|
49 | @john.verify_activation_key("12345").should == false |
|
50 | end |
|
50 | end |
|
51 | - |
|
51 | + end |
|
|
52 | + | ||
|
|
53 | + describe User, "when re-register with the same e-mail" do | ||
|
|
54 | + | ||
|
|
55 | + before(:each) do | ||
|
|
56 | + @mary_email = 'mary@in.th' | ||
|
|
57 | + | ||
|
|
58 | + @time_first_register = Time.local(2008,5,10,9,00).gmtime | ||
|
|
59 | + | ||
|
|
60 | + @mary_first = mock_model(User, | ||
|
|
61 | + :login => 'mary1', | ||
|
|
62 | + :password => 'hello', | ||
|
|
63 | + :email => @mary_email, | ||
|
|
64 | + :created_at => @time_first_register) | ||
|
|
65 | + @mary_second = User.new(:login => 'mary2', | ||
|
|
66 | + :password => 'hello', | ||
|
|
67 | + :email => @mary_email) | ||
|
|
68 | + User.stub!(:find_by_email). | ||
|
|
69 | + with(@mary_email, {:order => "created_at DESC"}). | ||
|
|
70 | + and_return(@mary_first) | ||
|
|
71 | + end | ||
|
|
72 | + | ||
|
|
73 | + class User | ||
|
|
74 | + public :enough_time_interval_between_same_email_registrations | ||
|
|
75 | + end | ||
|
|
76 | + | ||
|
|
77 | + it "should not be allowed if the time interval is less than 5 mins" do | ||
|
|
78 | + time_now = @time_first_register + 4.minutes | ||
|
|
79 | + Time.stub!(:now).and_return(time_now) | ||
|
|
80 | + | ||
|
|
81 | + @mary_second.enough_time_interval_between_same_email_registrations | ||
|
|
82 | + @mary_second.errors.length.should_not be_zero | ||
|
|
83 | + end | ||
|
|
84 | + | ||
|
|
85 | + it "should be allowed if the time interval is more than 5 mins" do | ||
|
|
86 | + time_now = @time_first_register + 6.minutes | ||
|
|
87 | + Time.stub!(:now).and_return(time_now) | ||
|
|
88 | + | ||
|
|
89 | + @mary_second.enough_time_interval_between_same_email_registrations | ||
|
|
90 | + @mary_second.errors.length.should be_zero | ||
|
|
91 | + end | ||
|
|
92 | + | ||
|
52 | end |
|
93 | end |
|
53 |
|
94 | ||
|
54 | describe User, "as a class" do |
|
95 | describe User, "as a class" do |
|
55 |
|
96 | ||
|
56 | it "should be able to generate random password" do |
|
97 | it "should be able to generate random password" do |
|
57 | password1 = User.random_password |
|
98 | password1 = User.random_password |
|
58 | password2 = User.random_password |
|
99 | password2 = User.random_password |
|
59 |
|
100 | ||
|
60 | password1.should_not == password2 |
|
101 | password1.should_not == password2 |
|
61 | end |
|
102 | end |
|
62 |
|
103 | ||
|
63 | end |
|
104 | end |
You need to be logged in to leave comments.
Login now