Commit de2fad9c1104389cafb262c6f86f03935c377b31

Authored by Caio SBA
1 parent 205a1ade

Done

app/controllers/public/account_controller.rb
... ... @@ -16,6 +16,12 @@ class AccountController < ApplicationController
16 16 end
17 17 end
18 18  
  19 + def activate
  20 + @user = User.find_by_activation_code(params[:activation_code]) if params[:activation_code]
  21 + session[:notice] = (@user and @user.activate) ? _("Your account has been activated, now you can log in!") : _("It looks like you're trying to activate an account. Perhaps have already activated this account?")
  22 + redirect_back_or_default(:controller => 'home')
  23 + end
  24 +
19 25 # action to perform login to the application
20 26 def login
21 27 @user = User.new
... ... @@ -60,7 +66,6 @@ class AccountController < ApplicationController
60 66 @person.environment = @user.environment
61 67 if request.post? && params[self.icaptcha_field].blank?
62 68 @user.signup!
63   - self.current_user = @user
64 69 owner_role = Role.find_by_name('owner')
65 70 @user.person.affiliate(@user.person, [owner_role]) if owner_role
66 71 invitation = Task.find_by_code(@invitation_code)
... ... @@ -68,8 +73,8 @@ class AccountController < ApplicationController
68 73 invitation.update_attributes!({:friend => @user.person})
69 74 invitation.finish
70 75 end
71   - session[:notice] = _("Thanks for signing up!")
72   - go_to_initial_page if redirect?
  76 + session[:notice] = _("Thanks for signing up! Now go to your e-mail and activate your account.")
  77 + redirect_back_or_default(:controller => 'home')
73 78 end
74 79 rescue ActiveRecord::RecordInvalid
75 80 @person.valid?
... ...
app/models/user.rb
... ... @@ -21,6 +21,8 @@ class User < ActiveRecord::Base
21 21 end
22 22 end
23 23  
  24 + before_create :make_activation_code
  25 +
24 26 before_create do |user|
25 27 if user.environment.nil?
26 28 user.environment = Environment.default
... ... @@ -31,8 +33,10 @@ class User < ActiveRecord::Base
31 33 user.person ||= Person.new
32 34 user.person.attributes = user.person_data.merge(:identifier => user.login, :user_id => user.id, :environment_id => user.environment_id)
33 35 user.person.name ||= user.login
  36 + user.person.visible = false unless user.activated?
34 37 user.person.save!
35 38 end
  39 + after_create :deliver_activation_code
36 40  
37 41 attr_writer :person_data
38 42 def person_data
... ... @@ -55,6 +59,17 @@ class User < ActiveRecord::Base
55 59 :environment => user.environment.name,
56 60 :url => url_for(:host => user.environment.default_hostname, :controller => 'home')
57 61 end
  62 +
  63 + def activation_code(user)
  64 + recipients user.email
  65 +
  66 + from "#{user.environment.name} <#{user.environment.contact_email}>"
  67 + subject _("[%s] Activate your account") % [user.environment.name]
  68 + body :recipient => user.name,
  69 + :activation_code => user.activation_code,
  70 + :environment => user.environment.name,
  71 + :url => user.environment.top_url
  72 + end
58 73 end
59 74  
60 75 def signup!
... ... @@ -67,6 +82,8 @@ class User &lt; ActiveRecord::Base
67 82 has_one :person, :dependent => :destroy
68 83 belongs_to :environment
69 84  
  85 + attr_protected :activated_at
  86 +
70 87 # Virtual attribute for the unencrypted password
71 88 attr_accessor :password
72 89  
... ... @@ -87,10 +104,22 @@ class User &lt; ActiveRecord::Base
87 104 # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
88 105 def self.authenticate(login, password, environment = nil)
89 106 environment ||= Environment.default
90   - u = find_by_login_and_environment_id(login, environment.id) # need to get the salt
  107 + u = first :conditions => ['login = ? AND environment_id = ? AND activated_at IS NOT NULL', login, environment.id] # need to get the salt
91 108 u && u.authenticated?(password) ? u : nil
92 109 end
93 110  
  111 + # Activates the user in the database.
  112 + def activate
  113 + self.activated_at = Time.now.utc
  114 + self.activation_code = nil
  115 + self.person.visible = true
  116 + self.person.save && self.save
  117 + end
  118 +
  119 + def activated?
  120 + self.activation_code.nil? && !self.activated_at.nil?
  121 + end
  122 +
94 123 class UnsupportedEncryptionType < Exception; end
95 124  
96 125 def self.system_encryption_method
... ... @@ -253,4 +282,12 @@ class User &lt; ActiveRecord::Base
253 282 def password_required?
254 283 crypted_password.blank? || !password.blank?
255 284 end
  285 +
  286 + def make_activation_code
  287 + self.activation_code = Digest::SHA1.hexdigest(Time.now.to_s.split(//).sort_by{rand}.join)
  288 + end
  289 +
  290 + def deliver_activation_code
  291 + User::Mailer.deliver_activation_code(self) unless self.activation_code.blank?
  292 + end
256 293 end
... ...
app/views/user/mailer/activation_code.rhtml 0 → 100644
... ... @@ -0,0 +1,9 @@
  1 +<%= _('Hi, %{recipient}!') % { :recipient => @recipient } %>
  2 +
  3 +<%= word_wrap(_('Welcome to %{environment}! To activate your account, follow the link: %{activation_url}') % { :environment => @environment, :activation_url => @url + url_for(:controller => :account, :action => :activate, :activation_code => @activation_code) }) %>
  4 +
  5 +<%= _("Greetings,") %>
  6 +
  7 +--
  8 +<%= _('%s team.') % @environment %>
  9 +<%= url_for @url %>
... ...
db/migrate/20110824192153_add_activated_at_to_users.rb 0 → 100644
... ... @@ -0,0 +1,16 @@
  1 +class AddActivatedAtToUsers < ActiveRecord::Migration
  2 + def self.up
  3 + add_column :users, :activation_code, :string, :limit => 40
  4 + add_column :users, :activated_at, :datetime
  5 + if ActiveRecord::Base.connection.adapter_name == 'SQLite'
  6 + execute "update users set activated_at = datetime();"
  7 + else
  8 + execute "update users set activated_at = now();"
  9 + end
  10 + end
  11 +
  12 + def self.down
  13 + remove_column :users, :activation_code
  14 + remove_column :users, :activated_at
  15 + end
  16 +end
... ...
features/my_network_block.feature
... ... @@ -56,9 +56,10 @@ Feature: my_network_block
56 56  
57 57 Scenario: not display how many invisible friends I have
58 58 Given the following users
59   - | login | name | visible |
60   - | mariasilva | Maria Silva | true |
61   - | josesilva | Jose Silva | false |
  59 + | login | name |
  60 + | mariasilva | Maria Silva |
  61 + | josesilva | Jose Silva |
  62 + And "josesilva" is invisible
62 63 And "joaosilva" is friend of "mariasilva"
63 64 And I am logged in as "joaosilva"
64 65 When I go to Joao Silva's homepage
... ...
features/signup.feature
... ... @@ -14,6 +14,18 @@ Feature: signup
14 14 | Password confirmation | secret |
15 15 | Name | José da Silva |
16 16 And I press "Sign up"
  17 + Then I should not be logged in
  18 + And I should receive an e-mail on josesilva@example.com
  19 + When I go to login page
  20 + And I fill in "Username" with "josesilva"
  21 + And I fill in "Password" with "secret"
  22 + And I press "Log in"
  23 + Then I should not be logged in
  24 + When José da Silva's account is activated
  25 + And I go to login page
  26 + And I fill in "Username" with "josesilva"
  27 + And I fill in "Password" with "secret"
  28 + And I press "Log in"
17 29 Then I should be logged in as "josesilva"
18 30  
19 31 Scenario: be redirected if user goes to signup page and is logged
... ...
features/step_definitions/noosfero_steps.rb
... ... @@ -7,10 +7,14 @@ Given /^the following users?$/ do |table|
7 7 table.hashes.each do |item|
8 8 person_data = item.dup
9 9 person_data.delete("login")
10   - User.create!(:login => item[:login], :password => '123456', :password_confirmation => '123456', :email => item[:login] + "@example.com", :person_data => person_data)
  10 + User.create!(:login => item[:login], :password => '123456', :password_confirmation => '123456', :email => item[:login] + "@example.com", :person_data => person_data).activate
11 11 end
12 12 end
13 13  
  14 +Given /^"(.+)" is (invisible|visible)$/ do |user, visibility|
  15 + User.find_by_login(user).person.update_attributes(:visible => (visibility == 'visible'))
  16 +end
  17 +
14 18 Given /^"(.+)" is (online|offline|busy) in chat$/ do |user, status|
15 19 status = {'online' => 'chat', 'offline' => '', 'busy' => 'dnd'}[status]
16 20 User.find_by_login(user).update_attributes(:chat_status => status, :chat_status_at => DateTime.now)
... ... @@ -195,6 +199,7 @@ end
195 199 Given /^I am logged in as admin$/ do
196 200 visit('/account/logout')
197 201 user = User.create!(:login => 'admin_user', :password => '123456', :password_confirmation => '123456', :email => 'admin_user@example.com')
  202 + user.activate
198 203 e = Environment.default
199 204 e.add_admin(user.person)
200 205 visit('/account/login')
... ... @@ -345,6 +350,10 @@ Then /^I should be logged in as &quot;(.+)&quot;$/ do |login|
345 350 User.find(session[:user]).login.should == login
346 351 end
347 352  
  353 +Then /^I should not be logged in$/ do
  354 + session[:user].nil?
  355 +end
  356 +
348 357 Given /^the profile "(.+)" has no blocks$/ do |profile|
349 358 profile = Profile[profile]
350 359 profile.boxes.map do |box|
... ... @@ -416,3 +425,12 @@ end
416 425 Given /^skip comments captcha$/ do
417 426 Comment.any_instance.stubs(:skip_captcha?).returns(true)
418 427 end
  428 +
  429 +When /^([^\']*)'s account is activated$/ do |person|
  430 + Person.find_by_name(person).user.activate
  431 +end
  432 +
  433 +Then /^I should receive an e-mail on (.*)$/ do |address|
  434 + last_mail = ActionMailer::Base.deliveries.last
  435 + last_mail['to'].to_s.should == address
  436 +end
... ...
test/fixtures/users.yml
... ... @@ -6,7 +6,7 @@ johndoe:
6 6 crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
7 7 #crypted_password: "ce2/iFrNtQ8=\n" # johndoe, use only if you're using 2-way encryption
8 8 created_at: <%= 5.days.ago.to_s :db %>
9   - # activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
  9 + activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
10 10 environment_id: 1
11 11 joerandomhacker:
12 12 id: 2
... ... @@ -14,7 +14,7 @@ joerandomhacker:
14 14 email: joerandomhacker@localhost.localdomain
15 15 salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
16 16 crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
17   - # activation_code: aaronscode # only if you're activating new signups
  17 + activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
18 18 created_at: <%= 1.days.ago.to_s :db %>
19 19 environment_id: 1
20 20 ze:
... ... @@ -23,7 +23,7 @@ ze:
23 23 email: ze@localhost.localdomain
24 24 salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
25 25 crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
26   - # activation_code: aaronscode # only if you're activating new signups
  26 + activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
27 27 created_at: <%= 1.days.ago.to_s :db %>
28 28 environment_id: 1
29 29 other_ze:
... ... @@ -32,6 +32,6 @@ other_ze:
32 32 email: ze@localhost.localdomain
33 33 salt: 7e3041ebc2fc05a40c60028e2c4901a81035d3cd
34 34 crypted_password: 00742970dc9e6319f8019fd54864d3ea740f04b1 # test
35   - # activation_code: aaronscode # only if you're activating new signups
  35 + activated_at: <%= 5.days.ago.to_s :db %> # only if you're activating new signups
36 36 created_at: <%= 1.days.ago.to_s :db %>
37 37 environment_id: 2
... ...
test/functional/account_controller_test.rb
... ... @@ -643,7 +643,7 @@ class AccountControllerTest &lt; Test::Unit::TestCase
643 643 Person.any_instance.stubs(:required_fields).returns(['organization'])
644 644 assert_difference User, :count do
645 645 post :signup, :user => { :login => 'testuser', :password => '123456', :password_confirmation => '123456', :email => 'testuser@example.com' }, :profile_data => { :organization => 'example.com' }
646   - assert_redirected_to :controller => 'profile_editor', :profile => 'testuser'
  646 + assert_redirected_to :controller => 'home'
647 647 end
648 648 assert_equal 'example.com', Person['testuser'].organization
649 649 end
... ... @@ -689,6 +689,32 @@ class AccountControllerTest &lt; Test::Unit::TestCase
689 689 assert_equal User.find_by_login('ze').data_hash.merge({ 'foo' => 'bar', 'test' => 5 }), ActiveSupport::JSON.decode(@response.body)
690 690 end
691 691  
  692 + should 'activate user when activation code is present and correct' do
  693 + user = User.create! :login => 'testuser', :password => 'test123', :password_confirmation => 'test123', :email => 'test@test.org'
  694 + get :activate, :activation_code => user.activation_code
  695 + post :login, :user => {:login => 'testuser', :password => 'test123'}
  696 + assert_not_nil session[:user]
  697 + assert_redirected_to :controller => 'profile_editor', :profile => 'testuser'
  698 + end
  699 +
  700 + should 'not activate user when activation code is missing' do
  701 + @request.env["HTTP_REFERER"] = '/bli'
  702 + user = User.create! :login => 'testuser', :password => 'test123', :password_confirmation => 'test123', :email => 'test@test.org'
  703 + get :activate
  704 + post :login, :user => {:login => 'testuser', :password => 'test123'}
  705 + assert_nil session[:user]
  706 + assert_redirected_to '/bli'
  707 + end
  708 +
  709 + should 'not activate user when activation code is incorrect' do
  710 + @request.env["HTTP_REFERER"] = '/bli'
  711 + user = User.create! :login => 'testuser', :password => 'test123', :password_confirmation => 'test123', :email => 'test@test.org'
  712 + get :activate, :activation_code => 'wrongcode'
  713 + post :login, :user => {:login => 'testuser', :password => 'test123'}
  714 + assert_nil session[:user]
  715 + assert_redirected_to '/bli'
  716 + end
  717 +
692 718 protected
693 719 def new_user(options = {}, extra_options ={})
694 720 data = {:profile_data => person_data}
... ...
test/functional/profile_controller_test.rb
... ... @@ -189,8 +189,10 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
189 189 end
190 190  
191 191 should 'display add friend button' do
  192 + @profile.user.activate
192 193 login_as(@profile.identifier)
193 194 friend = create_user_full('friendtestuser').person
  195 + friend.user.activate
194 196 friend.boxes.first.blocks << block = ProfileInfoBlock.create!
195 197 get :profile_info, :profile => friend.identifier, :block_id => block.id
196 198 assert_match /Add friend/, @response.body
... ... @@ -318,6 +320,7 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
318 320  
319 321 should 'display contact button only if friends' do
320 322 friend = create_user_full('friend_user').person
  323 + friend.user.activate
321 324 friend.boxes.first.blocks << block = ProfileInfoBlock.create!
322 325 @profile.add_friend(friend)
323 326 env = Environment.default
... ... @@ -338,6 +341,7 @@ class ProfileControllerTest &lt; Test::Unit::TestCase
338 341  
339 342 should 'display contact button only if friends and its enable in environment' do
340 343 friend = create_user_full('friend_user').person
  344 + friend.user.activate
341 345 friend.boxes.first.blocks << block = ProfileInfoBlock.create!
342 346 env = Environment.default
343 347 env.disable('disable_contact_person')
... ...
test/integration/editing_person_info_test.rb
... ... @@ -8,6 +8,8 @@ class EditingPersonInfoTest &lt; ActionController::IntegrationTest
8 8  
9 9 profile = create_user('user_ze', :password => 'test', :password_confirmation => 'test').person
10 10  
  11 + profile.user.activate
  12 +
11 13 login(profile.identifier, 'test')
12 14  
13 15 get "/myprofile/#{profile.identifier}"
... ...
test/integration/enterprise_registration_test.rb
... ... @@ -50,6 +50,7 @@ class EnterpriseRegistrationTest &lt; ActionController::IntegrationTest
50 50  
51 51 # steps done by the validator
52 52 validator = create_user_with_permission('validator', 'validate_enterprise', org)
  53 + validator.user.activate
53 54 login 'validator', 'validator'
54 55  
55 56 get "/myprofile/myorg/enterprise_validation"
... ...
test/integration/forgot_password_test.rb
... ... @@ -12,7 +12,7 @@ class ForgotPasswordTest &lt; ActionController::IntegrationTest
12 12 Profile.destroy_all
13 13 ChangePassword.destroy_all
14 14  
15   - create_user('forgotten', :password => 'test', :password_confirmation => 'test', :email => 'forgotten@localhost.localdomain')
  15 + create_user('forgotten', :password => 'test', :password_confirmation => 'test', :email => 'forgotten@localhost.localdomain').activate
16 16  
17 17 get '/account/forgot_password'
18 18  
... ...
test/integration/manage_documents_test.rb
... ... @@ -6,6 +6,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
6 6  
7 7 def test_creation_of_a_new_article
8 8 user = create_user('myuser')
  9 + user.activate
9 10  
10 11 login('myuser', 'myuser')
11 12 assert_tag :tag => 'a', :attributes => { :href => "#{user.environment.top_url}/myprofile\/{login}" }
... ... @@ -34,6 +35,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
34 35  
35 36 def test_update_of_an_existing_article
36 37 profile = create_user('myuser').person
  38 + profile.user.activate
37 39 article = create_article(profile, :name => 'my-article')
38 40 article.save!
39 41  
... ... @@ -67,6 +69,7 @@ class ManageDocumentsTest &lt; ActionController::IntegrationTest
67 69  
68 70 def test_removing_an_article
69 71 profile = create_user('myuser').person
  72 + profile.user.activate
70 73 article = create_article(profile, :name => 'my-article')
71 74 article.save!
72 75  
... ...
test/integration/signup_test.rb
... ... @@ -11,6 +11,7 @@ class SignupTest &lt; ActionController::IntegrationTest
11 11 Environment.default.update_attributes(:terms_of_use => 'You agree to not be annoying.')
12 12  
13 13 count = User.count
  14 + mail_count = ActionMailer::Base.deliveries.count
14 15  
15 16 get '/account/signup'
16 17 assert_response :success
... ... @@ -20,13 +21,15 @@ class SignupTest &lt; ActionController::IntegrationTest
20 21 assert_response :success
21 22 assert_template 'signup'
22 23 assert_equal count, User.count
  24 + assert_equal mail_count, ActionMailer::Base.deliveries.count
23 25  
24 26 post '/account/signup', :user => { :login => 'shouldaccepterms', :password => 'test', :password_confirmation => 'test', :email => 'shouldaccepterms@example.com', :terms_accepted => '1' }, :profile_data => person_data
25 27 assert_response :redirect
26 28  
27 29 follow_redirect!
28   - assert_response :success
  30 + assert_response :redirect
29 31 assert_equal count + 1, User.count
  32 + assert_equal mail_count + 1, ActionMailer::Base.deliveries.count
30 33  
31 34 end
32 35  
... ...
test/integration/user_registers_at_the_application_test.rb
... ... @@ -14,12 +14,9 @@ class UserRegistersAtTheApplicationTest &lt; ActionController::IntegrationTest
14 14  
15 15 post '/account/signup', :user => { :login => 'mylogin', :password => 'mypassword', :password_confirmation => 'mypassword', :email => 'mylogin@example.com' }
16 16 assert_response :redirect
17   - assert_redirected_to '/myprofile/mylogin'
18 17  
19   - # user is logged in right after the registration
20 18 follow_redirect!
21   - assert_no_tag :tag => 'a', :attributes => { :href => '/account/login_popup' }
22   - assert_tag :tag => 'a', :attributes => { :href => '/account/logout' }
  19 + assert_tag :tag => 'a', :attributes => { :href => /^\/account\/login/ }
23 20 end
24 21  
25 22 def test_trying_an_existing_login_name
... ...
test/unit/user_test.rb
... ... @@ -346,7 +346,7 @@ class UserTest &lt; Test::Unit::TestCase
346 346 Person.any_instance.stubs(:profile_custom_icon).returns('/custom_icon')
347 347 expected_hash = {
348 348 'coldplayfriend' => {
349   - 'avatar' => '/custom_icon', 'name' => 'coldplayfriend', 'jid' => 'coldplayfriend@colivre.net/coldplayfriend', 'status' => 'chat'
  349 + 'avatar' => '/custom_icon', 'name' => 'coldplayfriend', 'jid' => 'coldplayfriend@' + Environment.default.default_hostname + '/coldplayfriend', 'status' => 'chat'
350 350 }
351 351 }
352 352 assert_equal expected_hash, person.user.data_hash['friends_list']
... ... @@ -409,6 +409,69 @@ class UserTest &lt; Test::Unit::TestCase
409 409 assert_equal 'testuser', user.name
410 410 end
411 411  
  412 + should 'have activation code' do
  413 + user = create_user('testuser')
  414 + assert_respond_to user, :activation_code
  415 + end
  416 +
  417 + should 'have activated at' do
  418 + user = create_user('testuser')
  419 + assert_respond_to user, :activated_at
  420 + end
  421 +
  422 + should 'make activation code before creation' do
  423 + assert_not_nil new_user.activation_code
  424 + end
  425 +
  426 + should 'deliver e-mail with activation code after creation' do
  427 + assert_difference(ActionMailer::Base.deliveries, :size, 1) do
  428 + new_user :email => 'pending@activation.com'
  429 + end
  430 + assert_equal 'pending@activation.com', ActionMailer::Base.deliveries.last['to'].to_s
  431 + end
  432 +
  433 + should 'not mass assign activated at' do
  434 + user = User.new :activated_at => 5.days.ago
  435 + assert_nil user.activated_at
  436 + user.attributes = { :activated_at => 5.days.ago }
  437 + assert_nil user.activated_at
  438 + user.activated_at = 5.days.ago
  439 + assert_not_nil user.activated_at
  440 + end
  441 +
  442 + should 'authenticate an activated user' do
  443 + user = new_user :login => 'testuser', :password => 'test123', :password_confirmation => 'test123'
  444 + user.activate
  445 + assert_equal user, User.authenticate('testuser', 'test123')
  446 + end
  447 +
  448 + should 'not authenticate a not activated user' do
  449 + user = new_user :login => 'testuser', :password => 'test123', :password_confirmation => 'test123'
  450 + assert_nil User.authenticate('testuser', 'test123')
  451 + end
  452 +
  453 + should 'have activation code but no activated at when created' do
  454 + user = new_user
  455 + assert_not_nil user.activation_code
  456 + assert_nil user.activated_at
  457 + assert !user.person.visible
  458 + end
  459 +
  460 + should 'activate an user' do
  461 + user = new_user
  462 + assert user.activate
  463 + assert_nil user.activation_code
  464 + assert_not_nil user.activated_at
  465 + assert user.person.visible
  466 + end
  467 +
  468 + should 'return if the user is activated' do
  469 + user = new_user
  470 + assert !user.activated?
  471 + user.activate
  472 + assert user.activated?
  473 + end
  474 +
412 475 protected
413 476 def new_user(options = {})
414 477 user = User.new({ :login => 'quire', :email => 'quire@example.com', :password => 'quire', :password_confirmation => 'quire' }.merge(options))
... ...