diff --git a/Gemfile b/Gemfile index 30849bd40..fcf1f4764 100644 --- a/Gemfile +++ b/Gemfile @@ -13,7 +13,7 @@ gem 'json', '1.8.1' # Authentication -gem 'devise', '3.0.2' +gem 'devise', '3.2.2' # Captcha diff --git a/Gemfile.lock b/Gemfile.lock index 16e8c4245..edd21c73b 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -41,6 +41,7 @@ GEM asset_sync (1.0.0) activemodel fog (>= 1.8.0) + atomic (1.1.14) bcrypt-ruby (3.1.2) bootstrap-sass (2.2.2.0) sass (~> 3.2) @@ -91,10 +92,11 @@ GEM nokogiri (>= 1.5.0) rails (>= 3.0.0) database_cleaner (1.2.0) - devise (3.0.2) + devise (3.2.2) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) railties (>= 3.2.6, < 5) + thread_safe (~> 0.1) warden (~> 1.2.3) diff-lcs (1.2.5) entypo-rails (2.0.2) @@ -221,6 +223,7 @@ GEM multi_json (1.8.4) multi_test (0.0.3) multipart-post (1.2.0) + mysql2 (0.3.14) nested_form (0.3.2) net-scp (1.1.2) net-ssh (>= 2.6.5) @@ -256,7 +259,6 @@ GEM addressable nokogiri orm_adapter (0.5.0) - pg (0.16.0) polyglot (0.3.3) pry (0.9.12.4) coderay (~> 1.0) @@ -321,7 +323,6 @@ GEM rake (10.1.1) rb-fsevent (0.9.4) rb-inotify (0.9.3) - ffi (>= 0.5.0) rdoc (3.12.2) json (~> 1.4) redcarpet (3.0.0) @@ -392,6 +393,8 @@ GEM subexec (0.2.3) test_after_commit (0.2.2) thor (0.18.1) + thread_safe (0.1.3) + atomic tilt (1.4.1) timecop (0.7.1) timers (1.1.0) @@ -441,7 +444,7 @@ DEPENDENCIES configurate (= 0.0.8) cucumber-rails (= 1.4.0) database_cleaner (= 1.2.0) - devise (= 3.0.2) + devise (= 3.2.2) entypo-rails factory_girl_rails (= 4.3.0) faraday (= 0.8.9) @@ -467,6 +470,7 @@ DEPENDENCIES messagebus_ruby_api (= 1.0.3) mini_magick (= 3.7.0) mobile-fu (= 1.2.2) + mysql2 (= 0.3.14) nokogiri (= 1.6.1) omniauth (= 1.1.4) omniauth-facebook (= 1.6.0) @@ -474,7 +478,6 @@ DEPENDENCIES omniauth-twitter (= 1.0.1) omniauth-wordpress (= 0.2.0) opengraph_parser (= 0.2.3) - pg (= 0.16.0) rack-cors (= 0.2.8) rack-google-analytics (= 0.14.0) rack-piwik (= 0.2.2) diff --git a/app/models/user.rb b/app/models/user.rb index 6ee1b23aa..8d0becddc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -151,8 +151,11 @@ class User < ActiveRecord::Base self.hidden_shareables[share_type].present? end + # Copy the method provided by Devise to be able to call it later + # from a Sidekiq job + alias_method :send_reset_password_instructions!, :send_reset_password_instructions + def send_reset_password_instructions - generate_reset_password_token! if should_generate_reset_token? Workers::ResetPassword.perform_async(self.id) end diff --git a/app/views/devise/mailer/confirmation_instructions.markerb b/app/views/devise/mailer/confirmation_instructions.markerb index 987654218..80b5f86a4 100644 --- a/app/views/devise/mailer/confirmation_instructions.markerb +++ b/app/views/devise/mailer/confirmation_instructions.markerb @@ -4,4 +4,4 @@ [<%= t('.confirm') %>][1] -[1]: <%= confirmation_url(@resource, :confirmation_token => @resource.confirmation_token) %> +[1]: <%= confirmation_url(@resource, :confirmation_token => @token) %> diff --git a/app/views/devise/mailer/reset_password_instructions.markerb b/app/views/devise/mailer/reset_password_instructions.markerb index 840bf053e..1fe10a09a 100644 --- a/app/views/devise/mailer/reset_password_instructions.markerb +++ b/app/views/devise/mailer/reset_password_instructions.markerb @@ -4,7 +4,7 @@ [<%= t('.change') %>][1] -[1]: <%= edit_password_url(@resource, :reset_password_token => @resource.reset_password_token) %> +[1]: <%= edit_password_url(@resource, :reset_password_token => @token) %> <%= t('.wont_change') %> diff --git a/app/views/devise/mailer/unlock_instructions.markerb b/app/views/devise/mailer/unlock_instructions.markerb index 15ea9c91c..c70ce7abb 100644 --- a/app/views/devise/mailer/unlock_instructions.markerb +++ b/app/views/devise/mailer/unlock_instructions.markerb @@ -6,4 +6,4 @@ [<%= t('.unlock') %>][1] -[1]: <%= unlock_url(@resource, :unlock_token => @resource.unlock_token) %> +[1]: <%= unlock_url(@resource, :unlock_token => @token) %> diff --git a/app/workers/reset_password.rb b/app/workers/reset_password.rb index a0b869f59..965876e5e 100644 --- a/app/workers/reset_password.rb +++ b/app/workers/reset_password.rb @@ -3,8 +3,7 @@ module Workers sidekiq_options queue: :mail def perform(user_id) - user = User.find(user_id) - ::Devise.mailer.reset_password_instructions(user).deliver + User.find(user_id).send_reset_password_instructions! end end end diff --git a/config/initializers/check_session_secret.rb b/config/initializers/check_session_secret.rb deleted file mode 100644 index 941915356..000000000 --- a/config/initializers/check_session_secret.rb +++ /dev/null @@ -1,6 +0,0 @@ -if AppConfig.heroku? - Rails.application.config.secret_token = AppConfig.secret_token -elsif !Rails.root.join('config', 'initializers', 'secret_token.rb').exist? - `bundle exec rake generate:secret_token` - require Rails.root.join('config', 'initializers', 'secret_token.rb') -end diff --git a/config/initializers/devise.rb b/config/initializers/devise.rb index 03dbf8e99..42e1cc656 100644 --- a/config/initializers/devise.rb +++ b/config/initializers/devise.rb @@ -2,9 +2,6 @@ # licensed under the Affero General Public License version 3 or later. See # the COPYRIGHT file. -# Use this hook to configure devise mailer, warden hooks and so forth. The first -# four configuration values can also be set straight in your models. - class ActionController::Responder def to_mobile default_render @@ -13,83 +10,165 @@ class ActionController::Responder end end +# Use this hook to configure devise mailer, warden hooks and so forth. +# Many of these configuration options can be set straight in your model. Devise.setup do |config| - # Configure the e-mail address which will be shown in DeviseMailer. - # ==> ORM configuration - # Load and configure the ORM. Supports :active_record (default), :mongoid - # (bson_ext recommended) and :data_mapper (experimental). - require 'devise/orm/active_record' + # The secret key used by Devise. Devise uses this key to generate + # random tokens. Changing this key will render invalid all existing + # confirmation, reset password and unlock tokens in the database. + config.secret_key = AppConfig.secret_token - #mail setup + # ==> Mailer Configuration + # Configure the e-mail address which will be shown in Devise::Mailer, + # note that it will be overwritten if you use your own mailer class + # with default "from" parameter. if AppConfig.mail.sender_address.present? config.mailer_sender = AppConfig.mail.sender_address elsif AppConfig.mail.enable? unless Rails.env == 'test' Rails.logger.warn("No smtp sender address set, mail may fail.") - puts "WARNING: No smtp sender address set, mail may fail." + warn "WARNING: No smtp sender address set, mail may fail." end - config.mailer_sender = "please-change-me@config-initializers-devise.com" + config.mailer_sender = "please-change-me@config-diaspora-yml.com" end # Configure the class responsible to send e-mails. config.mailer = "DiasporaDeviseMailer" + # ==> ORM configuration + # Load and configure the ORM. Supports :active_record (default) and + # :mongoid (bson_ext recommended) by default. Other ORMs may be + # available as additional gems. + require 'devise/orm/active_record' + # ==> Configuration for any authentication mechanism - # Configure which keys are used when authenticating an user. By default is + # Configure which keys are used when authenticating a user. The default is # just :email. You can configure it to use [:username, :subdomain], so for - # authenticating an user, both parameters are required. Remember that those + # authenticating a user, both parameters are required. Remember that those # parameters are used only when authenticating and not when retrieving from # session. If you need permissions, you should implement that in a before filter. - config.authentication_keys = [:username] + # You can also supply a hash where the value is a boolean determining whether + # or not authentication should be aborted when the value is not present. + config.authentication_keys = [ :username ] + + # Configure parameters from the request object used for authentication. Each entry + # given should be a request method and it will automatically be passed to the + # find_for_authentication method and considered in your model lookup. For instance, + # if you set :request_keys to [:subdomain], :subdomain will be used on authentication. + # The same considerations mentioned for authentication_keys also apply to request_keys. + # config.request_keys = [] + + # Configure which authentication keys should be case-insensitive. + # These keys will be downcased upon creating or modifying a user and when used + # to authenticate or find a user. Default is :email. + config.case_insensitive_keys = [ :email, :username ] + + # Configure which authentication keys should have whitespace stripped. + # These keys will have whitespace before and after removed upon creating or + # modifying a user and when used to authenticate or find a user. Default is :email. + config.strip_whitespace_keys = [ :email, :username ] # Tell if authentication through request.params is enabled. True by default. + # It can be set to an array that will enable params authentication only for the + # given strategies, for example, `config.params_authenticatable = [:database]` will + # enable it only for database (email + password) authentication. # config.params_authenticatable = true - # Tell if authentication through HTTP Basic Auth is enabled. True by default. - # config.http_authenticatable = true + # Tell if authentication through HTTP Auth is enabled. False by default. + # It can be set to an array that will enable http authentication only for the + # given strategies, for example, `config.http_authenticatable = [:database]` will + # enable it only for database authentication. The supported strategies are: + # :database = Support basic authentication with authentication key + password + # config.http_authenticatable = false - # The realm used in Http Basic Authentication - # config.http_authentication_realm = "Application" + # If http headers should be returned for AJAX requests. True by default. + # config.http_authenticatable_on_xhr = true + + # The realm used in Http Basic Authentication. 'Application' by default. + # config.http_authentication_realm = 'Application' + + # It will change confirmation, password recovery and other workflows + # to behave the same regardless if the e-mail provided was right or wrong. + # Does not affect registerable. + # config.paranoid = true + + # By default Devise will store the user in session. You can skip storage for + # particular strategies by setting this option. + # Notice that if you are skipping storage for all authentication paths, you + # may want to disable generating routes to Devise's sessions controller by + # passing :skip => :sessions to `devise_for` in your config/routes.rb + config.skip_session_storage = [:http_auth] + + # By default, Devise cleans up the CSRF token on authentication to + # avoid CSRF token fixation attacks. This means that, when using AJAX + # requests for sign in and sign up, you need to get a new CSRF token + # from the server. You can disable this option at your own risk. + # config.clean_up_csrf_token_on_authentication = true # ==> Configuration for :database_authenticatable # For bcrypt, this is the cost for hashing the password and defaults to 10. If # using other encryptors, it sets how many times you want the password re-encrypted. + # + # Limiting the stretches to just one in testing will increase the performance of + # your test suite dramatically. However, it is STRONGLY RECOMMENDED to not use + # a value less than 10 in other environments. config.stretches = Rails.env.test? ? 1 : 10 # Setup a pepper to generate the encrypted password. config.pepper = "065eb8798b181ff0ea2c5c16aee0ff8b70e04e2ee6bd6e08b49da46924223e39127d5335e466207d42bf2a045c12be5f90e92012a4f05f7fc6d9f3c875f4c95b" - config.reset_password_within = 2.days - - # ==> Configuration for :invitable - # Time interval where the invitation token is valid (default: 0). - # If invite_for is 0 or nil, the invitation will never expire. - # config.invite_for = 2.weeks - # ==> Configuration for :confirmable - # The time you want to give your user to confirm his account. During this time - # he will be able to access your application without confirming. Default is nil. - # When confirm_within is zero, the user won't be able to sign in without confirming. - # You can use this to let your user access some features of your application - # without confirming the account, but blocking it after a certain period - # (ie 2 days). + # A period that the user is allowed to access the website even without + # confirming his account. For instance, if set to 2.days, the user will be + # able to access the website for two days without confirming his account, + # access will be blocked just in the third day. Default is 0.days, meaning + # the user cannot access the website without confirming his account. # config.allow_unconfirmed_access_for = 2.days + # A period that the user is allowed to confirm their account before their + # token becomes invalid. For example, if set to 3.days, the user can confirm + # their account within 3 days after the mail was sent, but on the fourth day + # their account can't be confirmed with the token any more. + # Default is nil, meaning there is no restriction on how long a user can take + # before confirming their account. + # config.confirm_within = 3.days + + # If true, requires any email changes to be confirmed (exactly the same way as + # initial account confirmation) to be applied. Requires additional unconfirmed_email + # db field (see migrations). Until confirmed new email is stored in + # unconfirmed email column, and copied to email column on successful confirmation. + config.reconfirmable = true + + # Defines which key will be used when confirming an account + # config.confirmation_keys = [ :email ] + # ==> Configuration for :rememberable # The time the user will be remembered without asking for credentials again. config.remember_for = 2.weeks - # ==> Configuration for :validatable - # Range for password length - # config.password_length = 8..20 + # If true, extends the user's remember period when remembered via cookie. + # config.extend_remember_period = false - # Regex to use to validate the email address - # config.email_regexp = /^([\w\.%\+\-]+)@([\w\-]+\.)+([\w]{2,})$/i + # Options to be passed to the created cookie. For instance, you can set + # :secure => true in order to force SSL only cookies. + # config.rememberable_options = {} + + # ==> Configuration for :validatable + # Range for password length. Default is 8..128. + config.password_length = 6..128 + + # Email regex used to validate email formats. It simply asserts that + # one (and only one) @ exists in the given string. This is mainly + # to give user feedback and not to assert the e-mail validity. + # config.email_regexp = /\A[^@]+@[^@]+\z/ # ==> Configuration for :timeoutable # The time you want to timeout the user session without activity. After this - # time the user will be asked for credentials again. - # config.timeout_in = 1.day + # time the user will be asked for credentials again. Default is 30 minutes. + # config.timeout_in = 30.minutes + + # If true, expires auth token on session timeout. + # config.expire_auth_token_on_timeout = false # ==> Configuration for :lockable # Defines which strategy will be used to lock an account. @@ -97,6 +176,9 @@ Devise.setup do |config| # :none = No lock strategy. You should handle locking by yourself. # config.lock_strategy = :failed_attempts + # Defines which key will be used when locking and unlocking an account + # config.unlock_keys = [ :email ] + # Defines which strategy will be used to unlock an account. # :email = Sends an unlock link to the user email # :time = Re-enables login after a certain amount of time (see :unlock_in below) @@ -111,56 +193,79 @@ Devise.setup do |config| # Time interval to unlock the account if :time is enabled as unlock_strategy. # config.unlock_in = 1.hour - # ==> Configuration for :token_authenticatable - # Defines name of the authentication token params key - config.token_authentication_key = :auth_token - config.skip_session_storage << :token_auth + # ==> Configuration for :recoverable + # + # Defines which key will be used when recovering the password for an account + # config.reset_password_keys = [ :email ] + + # Time interval you can reset your password with a reset password key. + # Don't put a too small interval or your users won't have the time to + # change their passwords. + config.reset_password_within = 2.days + + # ==> Configuration for :encryptable + # Allow you to use another encryption algorithm besides bcrypt (default). You can use + # :sha1, :sha512 or encryptors from others authentication tools as :clearance_sha1, + # :authlogic_sha512 (then you should set stretches above to 20 for default behavior) + # and :restful_authentication_sha1 (then you should set stretches to 10, and copy + # REST_AUTH_SITE_KEY to pepper). + # + # Require the `devise-encryptable` gem when using anything other than bcrypt + # config.encryptor = :sha512 # ==> Scopes configuration # Turn scoped views on. Before rendering "sessions/new", it will first check for - # "sessions/users/new". It's turned off by default because it's slower if you + # "users/sessions/new". It's turned off by default because it's slower if you # are using only default views. - # config.scoped_views = true + # config.scoped_views = false - # By default, devise detects the role accessed based on the url. So whenever - # accessing "/users/sign_in", it knows you are accessing an User. This makes - # routes as "/sign_in" not possible, unless you tell Devise to use the default - # scope, setting true below. - # Note that devise does not generate default routes. You also have to - # specify them in config/routes.rb - - # Configure the default scope used by Devise. By default it's the first devise - # role declared in your routes. + # Configure the default scope given to Warden. By default it's the first + # devise role declared in your routes (usually :user). config.default_scope = :user + # Set this configuration to false if you want /users/sign_out to sign out + # only the current scope. By default, Devise signs out all scopes. + # config.sign_out_all_scopes = true + # ==> Navigation configuration # Lists the formats that should be treated as navigational. Formats like # :html, should redirect to the sign in page when the user does not have # access, but formats like :xml or :json, should return 401. + # # If you have any extra navigational formats, like :iphone or :mobile, you - # should add them to the navigational formats lists. Default is [:html] - # config.navigational_formats = [:html, :iphone] - config.navigational_formats = [:"*/*", "*/*", :html, :mobile] + # should add them to the navigational formats lists. + # + # The "*/*" below is required to match Internet Explorer requests. + config.navigational_formats = ['*/*', :html, :mobile] - # Looks up user emails ignoring case - # for forgot password, sign up, sign in, etc - config.case_insensitive_keys = [:email] + # The default HTTP method used to sign out a resource. Default is :delete. + config.sign_out_via = :delete + + # ==> OmniAuth + # Add a new OmniAuth provider. Check the wiki for more information on setting + # up on your models and hooks. + # config.omniauth :github, 'APP_ID', 'APP_SECRET', :scope => 'user,public_repo' # ==> Warden configuration - # If you want to use other strategies, that are not (yet) supported by Devise, - # you can configure them inside the config.warden block. The example below - # allows you to setup OAuth, using http://github.com/roman/warden_oauth + # If you want to use other strategies, that are not supported by Devise, or + # change the failure app, you can configure them inside the config.warden block. # # config.warden do |manager| - # manager.oauth(:twitter) do |twitter| - # twitter.consumer_secret = - # twitter.consumer_key = - # twitter.options :site => 'http://twitter.com' - # end - # manager.default_strategies(:scope => :user).unshift :twitter_oauth + # manager.intercept_401 = false + # manager.default_strategies(:scope => :user).unshift :some_external_strategy # end - # Sign out via a DELETE request - config.sign_out_via = :delete + # ==> Mountable engine configurations + # When using Devise inside an engine, let's call it `MyEngine`, and this engine + # is mountable, there are some extra configurations to be taken into account. + # The following options are available, assuming the engine is mounted as: + # + # mount MyEngine, at: '/my_engine' + # + # The router that invoked `devise_for`, in the example above, would be: + # config.router_name = :my_engine + # + # When using omniauth, Devise cannot automatically set Omniauth path, + # so you need to do it manually. For the users scope, it would be: + # config.omniauth_path_prefix = '/my_engine/users/auth' end - diff --git a/config/initializers/set_session_secret.rb b/config/initializers/set_session_secret.rb new file mode 100644 index 000000000..1896d44be --- /dev/null +++ b/config/initializers/set_session_secret.rb @@ -0,0 +1 @@ +Rails.application.config.secret_token = AppConfig.secret_token diff --git a/features/desktop/change_password.feature b/features/desktop/change_password.feature index 6a4ee2ca1..113f106ec 100644 --- a/features/desktop/change_password.feature +++ b/features/desktop/change_password.feature @@ -21,4 +21,4 @@ Feature: Change password Then I should see "Change my password" When I fill out reset password form with "supersecret" and "supersecret" And I submit reset password form - Then I should be on the stream page \ No newline at end of file + Then I should be on the stream page diff --git a/lib/configuration_methods.rb b/lib/configuration_methods.rb index 5cf20b907..5fcf4246e 100644 --- a/lib/configuration_methods.rb +++ b/lib/configuration_methods.rb @@ -2,53 +2,65 @@ module Configuration module Methods def pod_uri return @pod_uri unless @pod_uri.nil? - + url = environment.url.get url = "http://#{url}" unless url =~ /^(https?:\/\/)/ url << "/" unless url.end_with?("/") - + begin @pod_url = Addressable::URI.parse(url) rescue puts "WARNING: pod url #{url} is not a legal URI" end - + @pod_url end - + def bare_pod_uri pod_uri.authority.gsub('www.', '') end - + def configured_services return @configured_services unless @configured_services.nil? - + @configured_services = [] [:twitter, :tumblr, :facebook, :wordpress].each do |service| @configured_services << service if services.send(service).enable? end - + @configured_services end attr_writer :configured_services - + def secret_token - return ENV['SECRET_TOKEN'] if ENV['SECRET_TOKEN'] - $stderr.puts "FATAL: Running on Heroku with SECRET_TOKEN unset" - $stderr.puts " Run heroku config:add SECRET_TOKEN=#{SecureRandom.hex(40)}" - Process.exit(1) + if heroku? + return ENV['SECRET_TOKEN'] if ENV['SECRET_TOKEN'] + warn "FATAL: Running on Heroku with SECRET_TOKEN unset" + warn " Run heroku config:add SECRET_TOKEN=#{SecureRandom.hex(40)}" + Process.exit(1) + else + token_file = File.expand_path( + '../config/initializers/secret_token.rb', + File.dirname(__FILE__) + ) + unless File.exist? token_file + `bundle exec rake generate:secret_token` + end + require token_file + Rails.application.config.secret_token + end end - + def version_string return @version_string unless @version_string.nil? @version_string = version.number.to_s @version_string << "-p#{git_revision[0..7]}" if git_available? @version_string end - + def git_available? return @git_available unless @git_available.nil? - + if heroku? @git_available = false else @@ -57,47 +69,47 @@ module Configuration @git_available = $?.success? end end - + def git_revision get_git_info if git_available? @git_revision end attr_writer :git_revision - + def git_update get_git_info if git_available? @git_update end attr_writer :git_update - + def rails_asset_id (git_revision || version)[0..8] end - + def get_redis_options if redistogo_url.present? - $stderr.puts "WARNING: using the REDISTOGO_URL environment variable is deprecated, please use REDIS_URL now." + warn "WARNING: using the REDISTOGO_URL environment variable is deprecated, please use REDIS_URL now." ENV['REDIS_URL'] = redistogo_url end - + redis_options = {} - + redis_url = ENV['REDIS_URL'] || environment.redis.get - + if ENV['RAILS_ENV']== 'integration2' redis_options[:url] = "redis://localhost:6380" elsif redis_url.present? unless redis_url.start_with?("redis://") || redis_url.start_with?("unix:///") - $stderr.puts "WARNING: Your redis url (#{redis_url}) doesn't start with redis:// or unix:///" + warn "WARNING: Your redis url (#{redis_url}) doesn't start with redis:// or unix:///" end redis_options[:url] = redis_url end - + redis_options[:namespace] = AppConfig.environment.sidekiq.namespace.get - + redis_options end - + def sidekiq_log path = Pathname.new environment.sidekiq.log.get path = Rails.root.join(path) unless pathname.absolute? @@ -111,7 +123,7 @@ module Configuration def bitcoin_donation_address if AppConfig.settings.bitcoin_wallet_id.present? - $stderr.puts "WARNING: bitcoin_wallet_id is now bitcoin_address. Change in diaspora.yml." + warn "WARNING: bitcoin_wallet_id is now bitcoin_address. Change in diaspora.yml." return AppConfig.settings.bitcoin_wallet_id end @@ -124,14 +136,14 @@ module Configuration def get_git_info return if git_info_present? || !git_available? - + git_cmd = `git log -1 --pretty="format:%H %ci"` if git_cmd =~ /^(\w+?)\s(.+)$/ @git_revision = $1 @git_update = $2.strip end end - + def git_info_present? @git_revision || @git_update end diff --git a/spec/models/user_spec.rb b/spec/models/user_spec.rb index 6af10f13a..20375f60f 100644 --- a/spec/models/user_spec.rb +++ b/spec/models/user_spec.rb @@ -868,20 +868,6 @@ describe User do end describe "#send_reset_password_instructions" do - it "generates a reset password token if it's supposed to" do - user = User.new - user.stub(:should_generate_reset_token?).and_return(true) - user.should_receive(:generate_reset_password_token) - user.send_reset_password_instructions - end - - it "does not generate a reset password token if it's not supposed to" do - user = User.new - user.stub(:should_generate_reset_token?).and_return(false) - user.should_not_receive(:generate_reset_password_token) - user.send_reset_password_instructions - end - it "queues up a job to send the reset password instructions" do user = FactoryGirl.create :user Workers::ResetPassword.should_receive(:perform_async).with(user.id) diff --git a/spec/workers/reset_password_spec.rb b/spec/workers/reset_password_spec.rb index d1f09347f..eed8697d7 100644 --- a/spec/workers/reset_password_spec.rb +++ b/spec/workers/reset_password_spec.rb @@ -3,12 +3,16 @@ require 'spec_helper' describe Workers::ResetPassword do describe "#perform" do it "given a user id it sends the reset password instructions for that user" do - user = FactoryGirl.create :user expect { - mail = Workers::ResetPassword.new.perform(user.id) - mail.to.should == [user.email] - mail.body.should include("change your password") + Workers::ResetPassword.new.perform(alice.id) }.to change(Devise.mailer.deliveries, :length).by(1) end + + it "correctly sets the message parameters" do + Workers::ResetPassword.new.perform(alice.id) + mail = Devise.mailer.deliveries.last + mail.to.should == [alice.email] + mail.body.should include("change your password") + end end end