Skip to content

Conversation

@milos-dukic
Copy link
Contributor

@milos-dukic milos-dukic commented Oct 23, 2025

PR for issue #72
Files changed:

  • app/assets/stylesheets/messages.css - some UI styling for error message
  • app/controllers/sessions/password_resets_controller.rb - new controller for handling the reset password flow
  • app/helpers/application_helper.rb - new helper method for checking is smtp is configured
  • app/javascript/controllers/password_reset_controller.js - new Stimulus controller for checking the new password and for displaying errors
  • app/mailers/application_mailer.rb - new application mailer
  • app/mailers/password_reset_mailer.rb - password reset mailer
  • app/models/user.rb - updated User model to be resettable
  • app/models/user/resettable.rb - new concern for password reset
  • app/views/password_reset_mailer/password_reset_email.html.erb - password reset HTML view
  • app/views/password_reset_mailer/password_reset_email.text.erb - password reset text view
  • app/views/sessions/new.html.erb - Added button for forgot password
  • app/views/sessions/password_resets/index.html.erb - HTML to input user email
  • app/views/sessions/password_resets/new.html.erb - HTML that email with reset link has been sent
  • app/views/sessions/password_resets/show.html.erb - HTML to enter new passwrod
  • config/environments/development.rb - SMTP development setup
  • config/environments/production.rb - SMPT production setup
  • config/routes.rb - new routes for password reset flow
  • test/mailers/fixture_templates/password_reset_html_fixture.txt - new fixture for html reset email
  • test/mailers/fixture_templates/password_reset_text_fixture.txt - new fixture for text reset email
  • test/mailers/password_reset_mailer_test.rb - new test
  • test/mailers/previews/password_reset_mailer_preview.rb - new test
  • config/environments/* - updated with new ENVs

ENV setup:

  • SMTP_ENABLED - defaults to false
  • SMTP_ADDRESS - obtained from mailing service
  • SMTP_PORT - obtained from mailing service
  • SMTP_DOMAIN - obtained from mailing service
  • SMTP_USER_NAME - obtained from mailing service
  • SMTP_PASSWORD - obtained from mailing service
  • SMTP_INFO_EMAIL_FROM - defaults to [email protected]
  • SMTP_PASSWORD_RESET_EMAIL_FROM - defaults to [email protected]

For SMTP feature to be enable i.e. supported following ENVs MUST be set:

  • SMTP_ENABLED
  • SMTP_ADDRESS
  • SMTP_PORT
  • SMTP_DOMAIN
  • SMTP_USER_NAME
  • SMTP_PASSWORD

SMTP config development:

  config.feature_enable_smtp = ENV.fetch("SMTP_ENABLED", false)
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:         ENV["SMTP_ADDRESS"],
    port:            ENV["SMTP_PORT"],
    domain:          ENV["SMTP_DOMAIN"],
    user_name:       ENV["SMTP_USER_NAME"],
    password:        ENV["SMTP_PASSWORD"],
    authentication:  "plain",
    open_timeout:    5,
    read_timeout:    5,
    openssl_verify_mode:  "none"
  }

Note openssl_verify_mode: "none" is set since I had issues with certificates in sandbox env.

SMTP config production:

  config.feature_enable_smtp = ENV.fetch("SMTP_ENABLED", false)
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address:         ENV["SMTP_ADDRESS"],
    port:            ENV["SMTP_PORT"],
    domain:          ENV["SMTP_DOMAIN"],
    user_name:       ENV["SMTP_USER_NAME"],
    password:        ENV["SMTP_PASSWORD"],
    authentication:  "plain",
    enable_starttls: true,
    open_timeout:    5,
    read_timeout:    5
  }

Screenshots:
1

2 3 4 5

@user = User.find_by_password_reset_id(password_reset_params[:password_reset_id])

redirect_to root_url unless @user
redirect_to root_url unless password_reset_params[:new_password] == password_reset_params[:confirm_new_password]

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe you could create another method called passwords_match? to make it a bit cleaner?

     def update
     ...
       redirect_to root_url unless passwords_match?
     ...
     end

    def passwords_match?
      password_reset_params[:new_password] == password_reset_params[:confirm_new_password]
    end

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah sure why not :)

extend ActiveSupport::Concern

# RESET_PASSWORD_LINK_EXPIRY_DURATION = 5.minutes
RESET_PASSWORD_LINK_EXPIRY_DURATION = 5.hours

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe you forgot to delete the comment in line 4?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep thx

Comment on lines 62 to 74
config.feature_enable_smtp = ENV.fetch("SMTP_ENABLED", false)
config.action_mailer.delivery_method = :test
config.action_mailer.smtp_settings = {
address: ENV.fetch("SMTP_ADDRESS", nil),
port: ENV.fetch("SMTP_PORT", nil),
domain: ENV.fetch("SMTP_DOMAIN", nil),
user_name: ENV.fetch("SMTP_USER_NAME", nil),
password: ENV.fetch("SMTP_PASSWORD", nil),
authentication: "plain",
open_timeout: 5,
read_timeout: 5,
openssl_verify_mode: "none"
}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We shouldn't use SMTP in the test environment because it makes tests slow, flaky and dependent on external services. The :test delivery method combined with perform_deliveries = true allows us to manipulate the ActionMailer::Base.deliveries array during tests.

Docs: https://guides.rubyonrails.org/testing.html#testing-mailers

Suggested change
config.feature_enable_smtp = ENV.fetch("SMTP_ENABLED", false)
config.action_mailer.delivery_method = :test
config.action_mailer.smtp_settings = {
address: ENV.fetch("SMTP_ADDRESS", nil),
port: ENV.fetch("SMTP_PORT", nil),
domain: ENV.fetch("SMTP_DOMAIN", nil),
user_name: ENV.fetch("SMTP_USER_NAME", nil),
password: ENV.fetch("SMTP_PASSWORD", nil),
authentication: "plain",
open_timeout: 5,
read_timeout: 5,
openssl_verify_mode: "none"
}
config.action_mailer.delivery_method = :test
config.action_mailer.perform_deliveries = true

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah about that...it all comes down to the method in application helper that checks whether the smtp is enabled or not, and that comes down to checking all above envs...I don't like it either :)... ok so I will try to find workaround for the testing purposes. Thx.

Copy link

@p-schlickmann p-schlickmann Oct 23, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Considering my previous comment, smtp usages should be removed in testing.

Test logic might need to be rewritten to leverage ActionMailer::Base.deliveries.

Copy link
Contributor Author

@milos-dukic milos-dukic Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ok will see about that :)
EDIT: This is not for smpt per se, this mimics the reset password process, it has nothing to do with the smpt, apart from that the password reset feature is not available if the smpt is not set up. So the call to

  def update
    @user = User.find_by_password_reset_id(password_reset_params[:password_reset_id])

    redirect_to root_url unless @user
    redirect_to root_url unless password_match?

    @user.update(password: password_reset_params[:new_password])

    redirect_to new_session_path
  end

will either reset password or won't be executed at all depending on the smpt set up i.e. if the config is set up.
So I would leave this, since it tests the controller and not the sending of the email :)

Copy link

@p-schlickmann p-schlickmann Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, totally understand your point, but smtp_enabled? will always be false while running the test suite, so the if statement in line 22 could be removed

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

will do I misunderstood...my bad. thx

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remove smtp usages here as well

Copy link
Contributor Author

@milos-dukic milos-dukic Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yep thx
EDIT: Not sure why to remove this, as this tests the body of the email, from, to etc. And when I replaced the envs with config.action_mailer.perform_deliveries = true config/test.rb test passes. So again not sure why to remove this? basically it is this: https://guides.rubyonrails.org/testing.html#unit-testing :)

Copy link

@p-schlickmann p-schlickmann Oct 24, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it should pass, but SMTP_PASSWORD_RESET_EMAIL_FROM in line 11 is irrelevant since SMTP is not configured in the test environment

Copy link
Contributor Author

@milos-dukic milos-dukic Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

aha yeah sure sure...I misunderstood...my bad. thx

Copy link
Contributor Author

@milos-dukic milos-dukic Oct 27, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@p-schlickmann sorry :) for the test env it isn't set, but for me locally, or for anyone else who configures it locally (I mean smtp), this will fail if we leave out ENV fetch, because in the code it checks whether the env is set or not. So, for the test to pass locally as well if the SMTP is configured i.e. if SMTP_PASSWORD_RESET_EMAIL_FROM env is set this needs to stay, or we can completely remove line 11 assert_equal [ ENV.fetch("SMTP_PASSWORD_RESET_EMAIL_FROM", ApplicationMailer::DEFAULT_BASE_FROM) ], email.from and don't test the from at all...I would leave this as it is, rather then remove the test case...
The part of the code that sets the FROM in app/mailers/password_reset_mailer.rb:

class PasswordResetMailer < ApplicationMailer
  default from: ENV.fetch("SMTP_PASSWORD_RESET_EMAIL_FROM", DEFAULT_BASE_FROM)

  def password_reset_email
    @email = params[:email]
    @url  = params[:url]
    mail(to: @email, subject: "Campfire Reset Password")
  end
end

@milos-dukic milos-dukic force-pushed the feature-reset-passwrod-flow branch from d2ce64f to 5d1fae8 Compare October 24, 2025 14:34
@milos-dukic
Copy link
Contributor Author

milos-dukic commented Oct 24, 2025

@p-schlickmann updated the PR :) thx for the review btw

@milos-dukic milos-dukic force-pushed the feature-reset-passwrod-flow branch from 5d1fae8 to b13696f Compare October 27, 2025 14:40
@milos-dukic
Copy link
Contributor Author

@p-schlickmann updated PR :) with one comment on test/mailers/password_reset_mailer_test.rb thx

@p-schlickmann
Copy link

Thanks @milos-dukic, I'll wait for a mantainer's opinion now.

…s and stimulus controllers and mailer. New tests and fixtures added.
@milos-dukic milos-dukic force-pushed the feature-reset-passwrod-flow branch from b13696f to 78cb507 Compare December 22, 2025 15:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants