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: 306 inserted, 17 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,11 +1,12 | |||||
|
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 |
@@ -37,20 +38,79 | |||||
|
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' |
|
45 | else |
|
46 | else |
|
|
47 | + render :action => 'email_error', :layout => 'empty' | ||
|
|
48 | + end | ||
|
|
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 |
@@ -33,12 +33,16 | |||||
|
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' |
@@ -16,13 +16,13 | |||||
|
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 | ||
@@ -33,12 +33,13 | |||||
|
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) |
@@ -84,12 +85,15 | |||||
|
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 |
@@ -114,11 +118,21 | |||||
|
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)") | ||
|
124 | end |
|
136 | end |
|
|
137 | + end | ||
|
|
138 | + end |
@@ -47,13 +47,13 | |||||
|
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| |
@@ -69,6 +69,9 | |||||
|
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 |
@@ -6,13 +6,13 | |||||
|
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" |
@@ -180,11 +180,13 | |||||
|
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 |
@@ -79,12 +79,20 | |||||
|
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; |
@@ -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 |
@@ -4,13 +4,13 | |||||
|
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} |
@@ -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 |
@@ -45,12 +45,53 | |||||
|
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 | + 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 | ||
|
51 |
|
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 |
You need to be logged in to leave comments.
Login now