diff --git a/app/models/user.rb b/app/models/user.rb index 82534c1e4..d56ab6001 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -23,6 +23,7 @@ class User < ActiveRecord::Base validates_format_of :username, :with => /\A[A-Za-z0-9_]+\z/ validates_length_of :username, :maximum => 32 validates_inclusion_of :language, :in => AVAILABLE_LANGUAGE_CODES + validates_format_of :unconfirmed_email, :with => Devise.email_regexp, :allow_blank => true validates_presence_of :person, :unless => proc {|user| user.invitation_token.present?} validates_associated :person @@ -43,6 +44,7 @@ class User < ActiveRecord::Base before_save do person.save if person && person.changed? end + before_save :guard_unconfirmed_email attr_accessible :getting_started, :password, :password_confirmation, :language, :disable_mail @@ -349,4 +351,12 @@ class User < ActiveRecord::Base mentioned_person.delete end end + + def guard_unconfirmed_email + self.unconfirmed_email = nil if unconfirmed_email.blank? || unconfirmed_email == email + + if unconfirmed_email_changed? + self.confirm_email_token = unconfirmed_email ? ActiveSupport::SecureRandom.hex(15) : nil + end + end end diff --git a/db/migrate/20110601083310_add_unconfirmed_email_to_users.rb b/db/migrate/20110601083310_add_unconfirmed_email_to_users.rb new file mode 100644 index 000000000..9c295e557 --- /dev/null +++ b/db/migrate/20110601083310_add_unconfirmed_email_to_users.rb @@ -0,0 +1,9 @@ +class AddUnconfirmedEmailToUsers < ActiveRecord::Migration + def self.up + add_column :users, :unconfirmed_email, :string, :default => nil, :null => true + end + + def self.down + remove_column :users, :unconfirmed_email + end +end diff --git a/db/migrate/20110601091059_add_confirm_email_token_to_users.rb b/db/migrate/20110601091059_add_confirm_email_token_to_users.rb new file mode 100644 index 000000000..4c71e97b2 --- /dev/null +++ b/db/migrate/20110601091059_add_confirm_email_token_to_users.rb @@ -0,0 +1,9 @@ +class AddConfirmEmailTokenToUsers < ActiveRecord::Migration + def self.up + add_column :users, :confirm_email_token, :string, :limit => 30 + end + + def self.down + remove_column :users, :confirm_email_token + end +end diff --git a/db/schema.rb b/db/schema.rb index 4ccf06d4b..31eae27d8 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20110527135552) do +ActiveRecord::Schema.define(:version => 20110601091059) do create_table "aspect_memberships", :force => true do |t| t.integer "aspect_id", :null => false @@ -369,6 +369,8 @@ ActiveRecord::Schema.define(:version => 20110527135552) do t.integer "invited_by_id" t.string "invited_by_type" t.string "authentication_token", :limit => 30 + t.string "unconfirmed_email" + t.string "confirm_email_token", :limit => 30 end add_index "users", ["authentication_token"], :name => "index_users_on_authentication_token", :unique => true diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index b08ab0378..2b2747fc8 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -34,6 +34,7 @@ describe User do new_user.id.should_not == alice.id end end + describe "validation" do describe "of associated person" do it "fails if person is not valid" do @@ -119,6 +120,26 @@ describe User do alice.should_not be_valid end end + + describe "of unconfirmed_email" do + it "unconfirmed_email address can be nil/blank" do + alice.unconfirmed_email = nil + alice.should be_valid + alice.unconfirmed_email = "" + alice.should be_valid + end + + it "does NOT require a unique unconfirmed_email address" do + eve.update_attribute :unconfirmed_email, "new@email.com" + alice.unconfirmed_email = "new@email.com" + alice.should be_valid + end + + it "requires a vaild unconfirmed_email address" do + alice.unconfirmed_email = "somebody@anywhere" + alice.should_not be_valid + end + end describe "of language" do after do @@ -593,4 +614,64 @@ describe User do end end end + + context 'change email' do + let(:user){ alice } + + describe "#unconfirmed_email" do + it "is nil by default" do + user.unconfirmed_email.should eql(nil) + end + + it "forces blank to nil" do + user.unconfirmed_email = "" + user.save! + user.unconfirmed_email.should eql(nil) + end + + it "is ignored if it equals email" do + user.unconfirmed_email = user.email + user.save! + user.unconfirmed_email.should eql(nil) + end + + it "allows change to valid new email" do + user.unconfirmed_email = "alice@newmail.com" + user.save! + user.unconfirmed_email.should eql("alice@newmail.com") + end + end + + describe "#confirm_email_token" do + it "is nil by default" do + user.confirm_email_token.should eql(nil) + end + + it "is autofilled when unconfirmed_email is set to new email" do + user.unconfirmed_email = "alice@newmail.com" + user.save! + user.confirm_email_token.should_not be_blank + user.confirm_email_token.size.should eql(30) + end + + it "is set back to nil when unconfirmed_email is empty" do + user.unconfirmed_email = "alice@newmail.com" + user.save! + user.confirm_email_token.should_not be_blank + user.unconfirmed_email = nil + user.save! + user.confirm_email_token.should eql(nil) + end + + it "generates new token on every new unconfirmed_email" do + user.unconfirmed_email = "alice@newmail.com" + user.save! + first_token = user.confirm_email_token + user.unconfirmed_email = "alice@andanotherone.com" + user.save! + user.confirm_email_token.should_not eql(first_token) + user.confirm_email_token.size.should eql(30) + end + end + end end