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,17 +1,18 | |||
|
1 |
- require ' |
|
|
1 | + require 'tmail' | |
|
2 | + require 'net/smtp' | |
|
2 | 3 | |
|
3 | 4 | class UsersController < ApplicationController |
|
4 | 5 | |
|
5 | - before_filter :authenticate, :except => [:new, :register] | |
|
6 | + before_filter :authenticate, :except => [:new, :register, :confirm] | |
|
6 | 7 | |
|
7 | 8 | verify :method => :post, :only => [:chg_passwd], |
|
8 | 9 | :redirect_to => { :action => :index } |
|
9 | 10 | |
|
10 | 11 | in_place_edit_for :user, :alias_for_editing |
|
11 | 12 | in_place_edit_for :user, :email_for_editing |
|
12 | 13 | |
|
13 | 14 | def index |
|
14 | 15 | if !Configuration['system.user_setting_enabled'] |
|
15 | 16 | redirect_to :controller => 'main', :action => 'list' |
|
16 | 17 | else |
|
17 | 18 | @user = User.find(session[:user_id]) |
@@ -31,26 +32,85 | |||
|
31 | 32 | end |
|
32 | 33 | |
|
33 | 34 | def new |
|
34 | 35 | @user = User.new |
|
35 | 36 | render :action => 'new', :layout => 'empty' |
|
36 | 37 | end |
|
37 | 38 | |
|
38 | 39 | def register |
|
39 | 40 | @user = User.new(params[:user]) |
|
40 | 41 | @user.password_confirmation = @user.password = User.random_password |
|
41 | 42 | @user.activated = false |
|
42 | 43 | if (@user.valid?) and (@user.save) |
|
43 | - send_confirmation_email(@user) | |
|
44 | + if send_confirmation_email(@user) | |
|
44 | 45 | render :action => 'new_splash', :layout => 'empty' |
|
45 | 46 | else |
|
47 | + render :action => 'email_error', :layout => 'empty' | |
|
48 | + end | |
|
49 | + else | |
|
46 | 50 | @user.errors.add_to_base("Email cannot be blank") if @user.email=='' |
|
47 | 51 | render :action => 'new', :layout => 'empty' |
|
48 | 52 | end |
|
49 | 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 | 73 | protected |
|
52 | 74 | |
|
53 | 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 | 114 | end |
|
55 | 115 | |
|
56 | 116 | end |
@@ -27,24 +27,28 | |||
|
27 | 27 | def self.[](key) |
|
28 | 28 | self.get(key) |
|
29 | 29 | end |
|
30 | 30 | |
|
31 | 31 | def self.reload |
|
32 | 32 | self.read_config |
|
33 | 33 | end |
|
34 | 34 | |
|
35 | 35 | def self.clear |
|
36 | 36 | @@configurations = nil |
|
37 | 37 | end |
|
38 | 38 | |
|
39 | + def self.enable_caching | |
|
40 | + @@cache = true | |
|
41 | + end | |
|
42 | + | |
|
39 | 43 | # |
|
40 | 44 | # View decision |
|
41 | 45 | # |
|
42 | 46 | def self.show_submitbox_to?(user) |
|
43 | 47 | mode = get(SYSTEM_MODE_CONF_KEY) |
|
44 | 48 | return false if mode=='analysis' |
|
45 | 49 | if (mode=='contest') |
|
46 | 50 | return false if (user.site!=nil) and |
|
47 | 51 | ((user.site.started!=true) or (user.site.finished?)) |
|
48 | 52 | end |
|
49 | 53 | return true |
|
50 | 54 | end |
@@ -10,41 +10,42 | |||
|
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 | belongs_to :site |
|
20 | 20 | belongs_to :country |
|
21 | 21 | |
|
22 | - named_scope :activated, :conditions => {:activated => true} | |
|
22 | + named_scope :activated_users, :conditions => {:activated => true} | |
|
23 | 23 | |
|
24 | 24 | validates_presence_of :login |
|
25 | 25 | validates_uniqueness_of :login |
|
26 | 26 | validates_format_of :login, :with => /^[\_a-z0-9]+$/ |
|
27 | 27 | validates_length_of :login, :within => 3..10 |
|
28 | 28 | |
|
29 | 29 | validates_presence_of :full_name |
|
30 | 30 | validates_length_of :full_name, :minimum => 1 |
|
31 | 31 | |
|
32 | 32 | validates_presence_of :password, :if => :password_required? |
|
33 | 33 | validates_length_of :password, :within => 4..20, :if => :password_required? |
|
34 | 34 | validates_confirmation_of :password, :if => :password_required? |
|
35 | 35 | |
|
36 | 36 | validates_format_of :email, :with => /\A([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})\Z/i, :allow_blank => true |
|
37 | 37 | |
|
38 | 38 | validate :uniqueness_of_email_from_activated_users |
|
39 | + validate :enough_time_interval_between_same_email_registrations | |
|
39 | 40 | |
|
40 | 41 | attr_accessor :password |
|
41 | 42 | |
|
42 | 43 | before_save :encrypt_new_password |
|
43 | 44 | |
|
44 | 45 | def self.authenticate(login, password) |
|
45 | 46 | user = find_by_login(login) |
|
46 | 47 | return user if user && user.authenticated?(password) |
|
47 | 48 | end |
|
48 | 49 | |
|
49 | 50 | def authenticated?(password) |
|
50 | 51 | if self.activated |
@@ -78,24 +79,27 | |||
|
78 | 79 | elsif self.alias=='' |
|
79 | 80 | "(blank)" |
|
80 | 81 | else |
|
81 | 82 | self.alias |
|
82 | 83 | end |
|
83 | 84 | end |
|
84 | 85 | |
|
85 | 86 | def alias_for_editing=(e) |
|
86 | 87 | self.alias=e |
|
87 | 88 | end |
|
88 | 89 | |
|
89 | 90 | def activation_key |
|
91 | + if self.hashed_password==nil | |
|
92 | + encrypt_new_password | |
|
93 | + end | |
|
90 | 94 | Digest::SHA1.hexdigest(self.hashed_password)[0..7] |
|
91 | 95 | end |
|
92 | 96 | |
|
93 | 97 | def verify_activation_key(key) |
|
94 | 98 | key == activation_key |
|
95 | 99 | end |
|
96 | 100 | |
|
97 | 101 | def self.random_password(length=5) |
|
98 | 102 | chars = 'abcdefghjkmnopqrstuvwxyz' |
|
99 | 103 | password = '' |
|
100 | 104 | length.times { password << chars[rand(chars.length - 1)] } |
|
101 | 105 | password |
@@ -108,17 +112,27 | |||
|
108 | 112 | self.hashed_password = User.encrypt(self.password,self.salt) |
|
109 | 113 | end |
|
110 | 114 | |
|
111 | 115 | def password_required? |
|
112 | 116 | self.hashed_password.blank? || !self.password.blank? |
|
113 | 117 | end |
|
114 | 118 | |
|
115 | 119 | def self.encrypt(string,salt) |
|
116 | 120 | Digest::SHA1.hexdigest(salt + string) |
|
117 | 121 | end |
|
118 | 122 | |
|
119 | 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 | 126 | self.errors.add_to_base("Email has already been taken") |
|
122 | 127 | end |
|
123 | 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 | 136 | end |
|
137 | + end | |
|
138 | + end |
@@ -41,34 +41,37 | |||
|
41 | 41 | # Make Active Record use UTC-base instead of local time |
|
42 | 42 | config.active_record.default_timezone = :utc |
|
43 | 43 | |
|
44 | 44 | # See Rails::Configuration for more options |
|
45 | 45 | |
|
46 | 46 | # ------------- |
|
47 | 47 | # Required gems |
|
48 | 48 | # ------------- |
|
49 | 49 | |
|
50 | 50 | # This is for rspec |
|
51 | 51 | config.gem "rspec-rails", :lib => "spec" |
|
52 | 52 | config.gem "haml" |
|
53 |
- config.gem " |
|
|
53 | + config.gem "tmail" | |
|
54 | 54 | #config.gem "BlueCloth", :lig => "bluecloth" |
|
55 | 55 | end |
|
56 | 56 | |
|
57 | 57 | # Add new inflection rules using the following format |
|
58 | 58 | # (all these examples are active by default): |
|
59 | 59 | # Inflector.inflections do |inflect| |
|
60 | 60 | # inflect.plural /^(ox)$/i, '\1en' |
|
61 | 61 | # inflect.singular /^(ox)en/i, '\1' |
|
62 | 62 | # inflect.irregular 'person', 'people' |
|
63 | 63 | # inflect.uncountable %w( fish sheep ) |
|
64 | 64 | # end |
|
65 | 65 | |
|
66 | 66 | # Add new mime types for use in respond_to blocks: |
|
67 | 67 | # Mime::Type.register "text/richtext", :rtf |
|
68 | 68 | # Mime::Type.register "application/x-mobile", :mobile |
|
69 | 69 | |
|
70 | 70 | # Include your application configuration below |
|
71 | 71 | |
|
72 | 72 | # These are where inputs and outputs of test requests are stored |
|
73 | 73 | TEST_REQUEST_INPUT_FILE_DIR = RAILS_ROOT + '/data/test_request/input' |
|
74 | 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,24 +1,24 | |||
|
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 => 2008120 |
|
|
12 | + ActiveRecord::Schema.define(:version => 20081210021333) 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 | end |
|
22 | 22 | |
|
23 | 23 | create_table "configurations", :force => true do |t| |
|
24 | 24 | t.string "key" |
@@ -174,17 +174,19 | |||
|
174 | 174 | add_index "test_requests", ["user_id", "problem_id"], :name => "index_test_requests_on_user_id_and_problem_id" |
|
175 | 175 | |
|
176 | 176 | create_table "users", :force => true do |t| |
|
177 | 177 | t.string "login", :limit => 10 |
|
178 | 178 | t.string "full_name" |
|
179 | 179 | t.string "hashed_password" |
|
180 | 180 | t.string "salt", :limit => 5 |
|
181 | 181 | t.string "alias" |
|
182 | 182 | t.string "email" |
|
183 | 183 | t.integer "site_id" |
|
184 | 184 | t.integer "country_id" |
|
185 | 185 | t.boolean "activated", :default => false |
|
186 | + t.datetime "created_at" | |
|
187 | + t.datetime "updated_at" | |
|
186 | 188 | end |
|
187 | 189 | |
|
188 | 190 | add_index "users", ["login"], :name => "index_users_on_login", :unique => true |
|
189 | 191 | |
|
190 | 192 | end |
@@ -73,24 +73,32 | |||
|
73 | 73 | /******************************* |
|
74 | 74 | [Main] |
|
75 | 75 | ********************************/ |
|
76 | 76 | div.submitbox { |
|
77 | 77 | border: thin solid black; |
|
78 | 78 | padding: 5px; |
|
79 | 79 | color: white; |
|
80 | 80 | background-color: #777777; |
|
81 | 81 | font-weight: bold; |
|
82 | 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 | 94 | [Settings] |
|
87 | 95 | ********************************/ |
|
88 | 96 | table.uinfo { |
|
89 | 97 | border-collapse: collapse; |
|
90 | 98 | border: 1px solid black; |
|
91 | 99 | font-size: 13px; |
|
92 | 100 | } |
|
93 | 101 | |
|
94 | 102 | td.uinfo { |
|
95 | 103 | vertical-align: top; |
|
96 | 104 | border: 1px solid black; |
@@ -1,4 +1,5 | |||
|
1 | 1 | #!/usr/bin/env ruby |
|
2 | 2 | $LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__) + "/../vendor/plugins/rspec/lib")) |
|
3 | + require 'rubygems' | |
|
3 | 4 | require 'spec' |
|
4 | 5 | exit ::Spec::Runner::CommandLine.run(::Spec::Runner::OptionParser.parse(ARGV, STDERR, STDOUT)) |
@@ -1,50 +1,55 | |||
|
1 | 1 | |
|
2 | 2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 | 3 | |
|
4 | 4 | describe MainController do |
|
5 | 5 | |
|
6 | 6 | before(:each) do |
|
7 | - @problem = mock(Problem, :name => 'test') | |
|
7 | + @problem = mock(Problem, :name => 'test', :output_only => false) | |
|
8 | 8 | @language = mock(Language, :name => 'cpp', :ext => 'cpp') |
|
9 | 9 | @submission = mock(Submission, |
|
10 | 10 | :id => 1, |
|
11 | 11 | :user_id => 1, |
|
12 | 12 | :problem => @problem, |
|
13 | 13 | :language => @language, |
|
14 | 14 | :source => 'sample source', |
|
15 | 15 | :compiler_message => 'none') |
|
16 | 16 | @user = mock(User, :id => 1, :login => 'john') |
|
17 | + @another_user = mock(User, :id => 2, :login => 'mary') | |
|
17 | 18 | end |
|
18 | 19 | |
|
19 | 20 | it "should redirect user to login page when unlogged-in user try to access main/list" do |
|
20 | 21 | get 'list' |
|
21 | 22 | response.should redirect_to(:action => 'login') |
|
22 | 23 | end |
|
23 | 24 | |
|
24 | 25 | it "should let user sees her own source" do |
|
25 | 26 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
27 | + User.should_receive(:find).with(1).and_return(@user) | |
|
26 | 28 | get 'source', {:id => @submission.id}, {:user_id => 1} |
|
27 | 29 | response.should be_success |
|
28 | 30 | end |
|
29 | 31 | |
|
30 | 32 | it "should let user sees her own compiler message" do |
|
31 | 33 | Submission.should_receive(:find).with(@submission.id.to_s).and_return(@submission) |
|
34 | + User.should_receive(:find).with(1).and_return(@user) | |
|
32 | 35 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 1} |
|
33 | 36 | response.should be_success |
|
34 | 37 | end |
|
35 | 38 | |
|
36 | 39 | it "should not let user sees other user's source" do |
|
37 | 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 | 42 | get 'source', {:id => @submission.id}, {:user_id => 2} |
|
39 | 43 | flash[:notice].should =~ /[Ee]rror/ |
|
40 | 44 | response.should redirect_to(:action => 'list') |
|
41 | 45 | end |
|
42 | 46 | |
|
43 | 47 | it "should not let user sees other user's compiler message" do |
|
44 | 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 | 50 | get 'compiler_msg', {:id => @submission.id}, {:user_id => 2} |
|
46 | 51 | flash[:notice].should =~ /[Ee]rror/ |
|
47 | 52 | response.should redirect_to(:action => 'list') |
|
48 | 53 | end |
|
49 | 54 | |
|
50 | 55 | end |
@@ -1,22 +1,22 | |||
|
1 | 1 | |
|
2 | 2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 | 3 | |
|
4 | 4 | describe TestController do |
|
5 | 5 | |
|
6 | 6 | before(:each) do |
|
7 | 7 | @john = mock(User, :id => "1", :login => 'john') |
|
8 | 8 | @john_result = mock(TestRequest, :id => "1", :user_id => @john.id) |
|
9 | 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 | 11 | end |
|
12 | 12 | |
|
13 | 13 | it "should let user see her testing result" do |
|
14 | 14 | TestRequest.should_receive(:find).with(@john_result.id). |
|
15 | 15 | and_return(@john_result) |
|
16 | 16 | get 'result', {:id => @john_result.id}, {:user_id => @john.id} |
|
17 | 17 | response.should be_success |
|
18 | 18 | end |
|
19 | 19 | |
|
20 | 20 | it "should not let user see other's testing result" do |
|
21 | 21 | TestRequest.should_receive(:find).with(@mary_result.id). |
|
22 | 22 | and_return(@mary_result) |
@@ -1,43 +1,48 | |||
|
1 | 1 | |
|
2 | 2 | require File.dirname(__FILE__) + '/../spec_helper' |
|
3 | 3 | |
|
4 | 4 | describe Site do |
|
5 | 5 | |
|
6 | 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 | 8 | @site = Site.new({:name => 'Test site', |
|
9 | 9 | :started => true, |
|
10 | 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 | 15 | end |
|
12 | 16 | |
|
13 | 17 | it "should report that the contest is not finished when the contest time limit is not set" do |
|
14 | 18 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
15 | 19 | and_return('unlimit') |
|
16 | - Time.should_not_receive(:now) | |
|
17 | 20 | @site.finished?.should == false |
|
18 | 21 | end |
|
19 | 22 | |
|
20 | 23 | it "should report that the contest is finished when the contest is over" do |
|
21 | 24 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
22 | 25 |
|
|
23 | - Time.should_receive(:now).and_return(Time.local(2008,5,10,14,01)) | |
|
24 | - @site.finished?.should == true | |
|
25 | - end | |
|
26 | + Time.stub!(:now). | |
|
27 | + and_return(Time.local(2008,5,10,14,01).gmtime) | |
|
28 | + @site.finished?.should == true end | |
|
26 | 29 | |
|
27 | 30 | it "should report if the contest is finished correctly, when the contest is over, and the contest time contains some minutes" do |
|
28 | 31 | Configuration.should_receive(:[]).twice.with('contest.time_limit'). |
|
29 | 32 | and_return('5:15') |
|
30 |
- Time.s |
|
|
31 |
- and_return(Time.local(2008,5,10,14,14) |
|
|
33 | + Time.stub!(:now). | |
|
34 | + and_return(Time.local(2008,5,10,14,14)) | |
|
32 | 35 | @site.finished?.should == false |
|
36 | + Time.stub!(:now). | |
|
37 | + and_return(Time.local(2008,5,10,14,16)) | |
|
33 | 38 | @site.finished?.should == true |
|
34 | 39 | end |
|
35 | 40 | |
|
36 | 41 | it "should report that the contest is not finished, when the time is exactly at the finish time" do |
|
37 | 42 | Configuration.should_receive(:[]).with('contest.time_limit'). |
|
38 | 43 | and_return('5:00') |
|
39 |
- Time.s |
|
|
44 | + Time.stub!(:now).and_return(Time.local(2008,5,10,14,00)) | |
|
40 | 45 | @site.finished?.should == false |
|
41 | 46 | end |
|
42 | 47 | |
|
43 | 48 | end |
@@ -39,24 +39,65 | |||
|
39 | 39 | @john.encrypt_new_password |
|
40 | 40 | end |
|
41 | 41 | |
|
42 | 42 | it "should produce and accept activation key" do |
|
43 | 43 | activation_key = @john.activation_key |
|
44 | 44 | |
|
45 | 45 | @john.verify_activation_key(activation_key).should == true |
|
46 | 46 | end |
|
47 | 47 | |
|
48 | 48 | it "should not accept invalid activation key" do |
|
49 | 49 | @john.verify_activation_key("12345").should == false |
|
50 | 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 | 93 | end |
|
53 | 94 | |
|
54 | 95 | describe User, "as a class" do |
|
55 | 96 | |
|
56 | 97 | it "should be able to generate random password" do |
|
57 | 98 | password1 = User.random_password |
|
58 | 99 | password2 = User.random_password |
|
59 | 100 | |
|
60 | 101 | password1.should_not == password2 |
|
61 | 102 | end |
|
62 | 103 |
You need to be logged in to leave comments.
Login now