From 63f57ce39fc483f17befaa7f981ce50efc3afb16 Mon Sep 17 00:00:00 2001 From: leonardobrito Date: Thu, 8 Jun 2023 17:56:04 -0300 Subject: [PATCH 1/4] Add reset password flow --- backend-rails/.env.sample | 4 ++- backend-rails/Gemfile | 2 ++ backend-rails/Gemfile.lock | 1 + .../app/assets/javascripts/application.js | 2 ++ .../app/assets/javascripts/jquery_init.js | 2 ++ .../app/assets/javascripts/reset_password.js | 31 +++++++++++++++++++ .../app/controllers/auth_controller.rb | 10 ++++++ .../app/views/auth/reset_password.html.erb | 19 ++++++++++++ .../mailer/confirmation_instructions.html.erb | 5 +++ .../reset_password_instructions.html.erb | 8 +++++ .../app/views/layouts/application.html.erb | 16 ++++++++++ .../config/environments/development.rb | 5 ++- backend-rails/config/initializers/assets.rb | 2 +- backend-rails/config/initializers/devise.rb | 2 +- backend-rails/config/routes.rb | 3 ++ backend-rails/spec/requests/auth_spec.rb | 7 +++++ 16 files changed, 115 insertions(+), 4 deletions(-) create mode 100644 backend-rails/app/assets/javascripts/application.js create mode 100644 backend-rails/app/assets/javascripts/jquery_init.js create mode 100644 backend-rails/app/assets/javascripts/reset_password.js create mode 100644 backend-rails/app/controllers/auth_controller.rb create mode 100644 backend-rails/app/views/auth/reset_password.html.erb create mode 100644 backend-rails/app/views/devise/mailer/confirmation_instructions.html.erb create mode 100644 backend-rails/app/views/devise/mailer/reset_password_instructions.html.erb create mode 100644 backend-rails/app/views/layouts/application.html.erb create mode 100644 backend-rails/spec/requests/auth_spec.rb diff --git a/backend-rails/.env.sample b/backend-rails/.env.sample index a3508476..4fec26e4 100644 --- a/backend-rails/.env.sample +++ b/backend-rails/.env.sample @@ -1,7 +1,9 @@ SERVER_HOST=localhost -PASSWORD_RESET_URL=http://127.0.0.1:3000 +PASSWORD_RESET_URL=http://localhost:3000/auth/reset_password SENDGRID_API_KEY= AWS_ACCESS_KEY_ID= AWS_SECRET_ACCESS_KEY= S3_BUCKET_NAME= AWS_BUCKET_REGION= +LAUNCHY_DRY_RUN=true +BROWSER=/dev/null diff --git a/backend-rails/Gemfile b/backend-rails/Gemfile index 5da47f4d..c4907b5e 100644 --- a/backend-rails/Gemfile +++ b/backend-rails/Gemfile @@ -28,6 +28,8 @@ gem 'sass-rails', '~> 6.0.0' gem 'sendgrid', '~> 1.2.4' gem 'sprockets', '~> 3.7.2' gem 'yaaf', '~> 2.2' +gem 'jquery-rails' + # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' # Use Active Model has_secure_password diff --git a/backend-rails/Gemfile.lock b/backend-rails/Gemfile.lock index a001620c..4f4e3475 100644 --- a/backend-rails/Gemfile.lock +++ b/backend-rails/Gemfile.lock @@ -468,6 +468,7 @@ DEPENDENCIES faker (~> 2.13) i18n-tasks (~> 0.9.30) jbuilder (~> 2.10) + jquery-rails letter_opener (~> 1.7) listen (~> 3.2) matrix (~> 0.4.2) diff --git a/backend-rails/app/assets/javascripts/application.js b/backend-rails/app/assets/javascripts/application.js new file mode 100644 index 00000000..b51a50e6 --- /dev/null +++ b/backend-rails/app/assets/javascripts/application.js @@ -0,0 +1,2 @@ +// require_self +// require_tree. diff --git a/backend-rails/app/assets/javascripts/jquery_init.js b/backend-rails/app/assets/javascripts/jquery_init.js new file mode 100644 index 00000000..31a96fd2 --- /dev/null +++ b/backend-rails/app/assets/javascripts/jquery_init.js @@ -0,0 +1,2 @@ +//= require jquery +//= require jquery_ujs diff --git a/backend-rails/app/assets/javascripts/reset_password.js b/backend-rails/app/assets/javascripts/reset_password.js new file mode 100644 index 00000000..58db363b --- /dev/null +++ b/backend-rails/app/assets/javascripts/reset_password.js @@ -0,0 +1,31 @@ +//= require_self + +$(document).ready(function () { + $('#reset_password_form').submit(function (event) { + event.preventDefault(); + + const params = $(this).data('params') + + const headers = { + uid: params.uid, + client: params.client, + 'access-token': params['access-token'] + } + + $.ajax({ + headers, + url: $(this).attr('action'), + type: "PUT", + datatype: "application/js", + data: $(this).serialize(), + success: function (response) { + alert(response.message) + }, + error: function (_XMLHttpRequest, textStatus, errorThrown) { + alert("Status: " + textStatus); alert("Error: " + errorThrown); + } + }) + + return false; + }); +}) diff --git a/backend-rails/app/controllers/auth_controller.rb b/backend-rails/app/controllers/auth_controller.rb new file mode 100644 index 00000000..082a2ea5 --- /dev/null +++ b/backend-rails/app/controllers/auth_controller.rb @@ -0,0 +1,10 @@ +class AuthController < ApplicationController + def reset_password + end + + private + + def auth_params + params.permit('access-token', :client, :client_id, :token, :uid) + end +end diff --git a/backend-rails/app/views/auth/reset_password.html.erb b/backend-rails/app/views/auth/reset_password.html.erb new file mode 100644 index 00000000..4ed64510 --- /dev/null +++ b/backend-rails/app/views/auth/reset_password.html.erb @@ -0,0 +1,19 @@ +<%= javascript_include_tag "jquery_init" %> +<%= javascript_include_tag "reset_password", "data-turbolinks-track" => true %> + +
+

Reset your password

+ + <%= form_with url: user_password_path, + local: false, method: :put, html: { id: "reset_password_form", data: { params: params} } do |form| %> +
+ <%= form.label :password %> + <%= form.password_field :password %> +
+
+ <%= form.label :password_confirmation %> + <%= form.password_field :password_confirmation %> +
+ <%= form.submit 'Reset Password', style: 'margin-top: 24px; padding: 12px;' %> + <% end %> +
diff --git a/backend-rails/app/views/devise/mailer/confirmation_instructions.html.erb b/backend-rails/app/views/devise/mailer/confirmation_instructions.html.erb new file mode 100644 index 00000000..1b19eccb --- /dev/null +++ b/backend-rails/app/views/devise/mailer/confirmation_instructions.html.erb @@ -0,0 +1,5 @@ +

<%= t(:welcome).capitalize + ' ' + @email %>!

+ +

<%= t '.confirm_link_msg' %>

+ +

<%= link_to t('.confirm_account_link'), user_confirmation_url(@resource, {confirmation_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url']}).html_safe %>

diff --git a/backend-rails/app/views/devise/mailer/reset_password_instructions.html.erb b/backend-rails/app/views/devise/mailer/reset_password_instructions.html.erb new file mode 100644 index 00000000..e10d76f7 --- /dev/null +++ b/backend-rails/app/views/devise/mailer/reset_password_instructions.html.erb @@ -0,0 +1,8 @@ +

<%= t(:hello).capitalize %> <%= @resource.email %>!

+ +

<%= t '.request_reset_link_msg' %>

+ +

<%= link_to t('.password_change_link'), edit_user_password_url(@resource, reset_password_token: @token, config: message['client-config'].to_s, redirect_url: message['redirect-url'].to_s).html_safe %>

+ +

<%= t '.ignore_mail_msg' %>

+

<%= t '.no_changes_msg' %>

diff --git a/backend-rails/app/views/layouts/application.html.erb b/backend-rails/app/views/layouts/application.html.erb new file mode 100644 index 00000000..4fec1ae2 --- /dev/null +++ b/backend-rails/app/views/layouts/application.html.erb @@ -0,0 +1,16 @@ + + + + My App + + <%= csrf_meta_tags %> + <%= csp_meta_tag %> + + <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %> + <%= javascript_include_tag "application", "data-turbo-track": "reload", defer: true %> + + + + <%= yield %> + + diff --git a/backend-rails/config/environments/development.rb b/backend-rails/config/environments/development.rb index 1c606efc..c0807310 100644 --- a/backend-rails/config/environments/development.rb +++ b/backend-rails/config/environments/development.rb @@ -42,9 +42,12 @@ # Don't care if the mailer can't send. config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :letter_opener - + config.action_mailer.perform_deliveries = true + config.action_mailer.default_options = { from: 'no-reply@yourapi.com'} config.action_mailer.perform_caching = false + config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } + # Print deprecation notices to the Rails logger. config.active_support.deprecation = :log diff --git a/backend-rails/config/initializers/assets.rb b/backend-rails/config/initializers/assets.rb index 5a98a7e0..3c715ad7 100644 --- a/backend-rails/config/initializers/assets.rb +++ b/backend-rails/config/initializers/assets.rb @@ -11,4 +11,4 @@ # Precompile additional assets. # application.js, application.css, and all non-JS/CSS in the app/assets # folder are already added. -Rails.application.config.assets.precompile += %w[active_admin.js active_admin.css] +Rails.application.config.assets.precompile += %w[active_admin.js active_admin.css reset_password.js jquery_init.js] diff --git a/backend-rails/config/initializers/devise.rb b/backend-rails/config/initializers/devise.rb index 8e82857c..379d06f5 100644 --- a/backend-rails/config/initializers/devise.rb +++ b/backend-rails/config/initializers/devise.rb @@ -188,7 +188,7 @@ # ==> Configuration for :recoverable # # Defines which key will be used when recovering the password for an account - # config.reset_password_keys = [:email] + 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 diff --git a/backend-rails/config/routes.rb b/backend-rails/config/routes.rb index 0895643a..d5081f33 100644 --- a/backend-rails/config/routes.rb +++ b/backend-rails/config/routes.rb @@ -2,12 +2,15 @@ devise_for :admin_users, ActiveAdmin::Devise.config ActiveAdmin.routes(self) ExceptionHunter.routes(self) + mount_devise_token_auth_for 'User', at: '/api/v1/users', controllers: { registrations: 'api/v1/registrations', sessions: 'api/v1/sessions', passwords: 'api/v1/passwords' } + get 'auth/reset_password', to: 'auth#reset_password' + namespace :api do namespace :v1, defaults: { format: :json } do resources :daily_habits, only: %i[index create] diff --git a/backend-rails/spec/requests/auth_spec.rb b/backend-rails/spec/requests/auth_spec.rb new file mode 100644 index 00000000..51c64a5e --- /dev/null +++ b/backend-rails/spec/requests/auth_spec.rb @@ -0,0 +1,7 @@ +require 'rails_helper' + +RSpec.describe "Auths", type: :request do + describe "GET /index" do + pending "add some examples (or delete) #{__FILE__}" + end +end From e089ec64a09d2a21f1337a150f7c393c1e012895 Mon Sep 17 00:00:00 2001 From: leonardobrito Date: Thu, 8 Jun 2023 18:12:11 -0300 Subject: [PATCH 2/4] Fix code:analysis --- backend-rails/Gemfile | 2 +- backend-rails/app/controllers/auth_controller.rb | 3 +-- backend-rails/config/environments/development.rb | 2 +- backend-rails/spec/requests/auth_spec.rb | 4 ++-- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/backend-rails/Gemfile b/backend-rails/Gemfile index c4907b5e..b8e048c8 100644 --- a/backend-rails/Gemfile +++ b/backend-rails/Gemfile @@ -15,6 +15,7 @@ gem 'devise_token_auth', '~> 1.2', git: 'https://github.com/lynndylanhurley/devi gem 'draper', '~> 4.0', '>= 4.0.1' gem 'exception_hunter', '~> 1.0', '>= 1.0.1' gem 'jbuilder', '~> 2.10' +gem 'jquery-rails' gem 'matrix', '~> 0.4.2' gem 'oj', '~> 3.9', '>= 3.9.2' gem 'pagy', '~> 3.7', '>= 3.7.5' @@ -28,7 +29,6 @@ gem 'sass-rails', '~> 6.0.0' gem 'sendgrid', '~> 1.2.4' gem 'sprockets', '~> 3.7.2' gem 'yaaf', '~> 2.2' -gem 'jquery-rails' # Use Redis adapter to run Action Cable in production # gem 'redis', '~> 4.0' diff --git a/backend-rails/app/controllers/auth_controller.rb b/backend-rails/app/controllers/auth_controller.rb index 082a2ea5..20aef53d 100644 --- a/backend-rails/app/controllers/auth_controller.rb +++ b/backend-rails/app/controllers/auth_controller.rb @@ -1,6 +1,5 @@ class AuthController < ApplicationController - def reset_password - end + def reset_password; end private diff --git a/backend-rails/config/environments/development.rb b/backend-rails/config/environments/development.rb index c0807310..084d92fe 100644 --- a/backend-rails/config/environments/development.rb +++ b/backend-rails/config/environments/development.rb @@ -43,7 +43,7 @@ config.action_mailer.raise_delivery_errors = true config.action_mailer.delivery_method = :letter_opener config.action_mailer.perform_deliveries = true - config.action_mailer.default_options = { from: 'no-reply@yourapi.com'} + config.action_mailer.default_options = { from: 'no-reply@yourapi.com' } config.action_mailer.perform_caching = false config.action_mailer.default_url_options = { host: 'localhost', port: 3000 } diff --git a/backend-rails/spec/requests/auth_spec.rb b/backend-rails/spec/requests/auth_spec.rb index 51c64a5e..fac1c18b 100644 --- a/backend-rails/spec/requests/auth_spec.rb +++ b/backend-rails/spec/requests/auth_spec.rb @@ -1,7 +1,7 @@ require 'rails_helper' -RSpec.describe "Auths", type: :request do - describe "GET /index" do +RSpec.describe 'Auths', type: :request do + describe 'GET /index' do pending "add some examples (or delete) #{__FILE__}" end end From 625d3bbc15d8a76b3988ab78270ef2d18cb2f379 Mon Sep 17 00:00:00 2001 From: leonardobrito Date: Thu, 8 Jun 2023 19:12:20 -0300 Subject: [PATCH 3/4] Add resend mailer delivery --- backend-rails/.env.sample | 12 ++++++------ backend-rails/Gemfile | 2 +- backend-rails/Gemfile.lock | 13 ++++++++++--- backend-rails/config/application.rb | 9 --------- backend-rails/config/environments/production.rb | 4 ++++ backend-rails/config/initializers/mailer.rb | 1 + 6 files changed, 22 insertions(+), 19 deletions(-) create mode 100644 backend-rails/config/initializers/mailer.rb diff --git a/backend-rails/.env.sample b/backend-rails/.env.sample index 4fec26e4..7657e63d 100644 --- a/backend-rails/.env.sample +++ b/backend-rails/.env.sample @@ -1,9 +1,9 @@ -SERVER_HOST=localhost -PASSWORD_RESET_URL=http://localhost:3000/auth/reset_password -SENDGRID_API_KEY= AWS_ACCESS_KEY_ID= -AWS_SECRET_ACCESS_KEY= -S3_BUCKET_NAME= AWS_BUCKET_REGION= -LAUNCHY_DRY_RUN=true +AWS_SECRET_ACCESS_KEY= BROWSER=/dev/null +LAUNCHY_DRY_RUN=true +PASSWORD_RESET_URL=http://localhost:3000/auth/reset_password +RESEND_API_KEY= +SERVER_HOST=localhost +S3_BUCKET_NAME= diff --git a/backend-rails/Gemfile b/backend-rails/Gemfile index b8e048c8..f740234e 100644 --- a/backend-rails/Gemfile +++ b/backend-rails/Gemfile @@ -25,8 +25,8 @@ gem 'prawn' gem 'puma', '~> 5.6' gem 'pundit', '~> 2.1' gem 'rack-cors', '~> 1.0', '>= 1.0.6' +gem 'resend' gem 'sass-rails', '~> 6.0.0' -gem 'sendgrid', '~> 1.2.4' gem 'sprockets', '~> 3.7.2' gem 'yaaf', '~> 2.2' diff --git a/backend-rails/Gemfile.lock b/backend-rails/Gemfile.lock index 4f4e3475..ff0a96fc 100644 --- a/backend-rails/Gemfile.lock +++ b/backend-rails/Gemfile.lock @@ -178,6 +178,9 @@ GEM activesupport (>= 5.2) hashdiff (1.0.1) highline (2.1.0) + httparty (0.19.1) + mime-types (~> 3.0) + multi_xml (>= 0.5.2) i18n (1.12.0) concurrent-ruby (~> 1.0) i18n-tasks (0.9.37) @@ -236,10 +239,14 @@ GEM marcel (1.0.2) matrix (0.4.2) method_source (1.0.0) + mime-types (3.4.1) + mime-types-data (~> 3.2015) + mime-types-data (3.2023.0218.1) mini_mime (1.1.2) mini_portile2 (2.8.1) minitest (5.17.0) msgpack (1.6.0) + multi_xml (0.6.0) mustache (1.1.1) net-imap (0.3.4) date @@ -341,6 +348,8 @@ GEM request_store (1.5.1) rack (>= 1.4) require_all (3.0.0) + resend (0.5.0) + httparty (~> 0.19.1) responders (3.1.0) actionpack (>= 5.2) railties (>= 5.2) @@ -400,8 +409,6 @@ GEM sprockets (> 3.0) sprockets-rails tilt - sendgrid (1.2.4) - json sexp_processor (4.16.1) shoulda-matchers (4.5.1) activesupport (>= 4.2.0) @@ -485,12 +492,12 @@ DEPENDENCIES rails (~> 7.0.3) rails_best_practices (~> 1.20) reek (~> 6.1, >= 6.1.1) + resend rspec-rails (~> 4.1) rspec_api_documentation (~> 6.1.0) rubocop-rails (~> 2.16, >= 2.16.1) rubocop-rootstrap (~> 1.2) sass-rails (~> 6.0.0) - sendgrid (~> 1.2.4) shoulda-matchers (~> 4.1, >= 4.1.2) simplecov (~> 0.13.0) spring (~> 4.0) diff --git a/backend-rails/config/application.rb b/backend-rails/config/application.rb index 5730d483..56e7e671 100644 --- a/backend-rails/config/application.rb +++ b/backend-rails/config/application.rb @@ -34,15 +34,6 @@ class Application < Rails::Application config.add_autoload_paths_to_load_path = false - ActionMailer::Base.smtp_settings = { - address: 'smtp.sendgrid.net', - authentication: :plain, - domain: ENV.fetch('SERVER_HOST', nil), - enable_starttls_auto: true, - password: ENV.fetch('SENDGRID_API_KEY', nil), - port: 587, - user_name: 'apikey' - } config.action_mailer.default_url_options = { host: ENV.fetch('SERVER_HOST', nil), port: ENV.fetch('PORT', 3000) } config.action_mailer.default_options = { diff --git a/backend-rails/config/environments/production.rb b/backend-rails/config/environments/production.rb index ce764241..969ffd35 100644 --- a/backend-rails/config/environments/production.rb +++ b/backend-rails/config/environments/production.rb @@ -73,6 +73,10 @@ # Ignore bad email addresses and do not raise email delivery errors. # Set this to true and configure the email server for immediate delivery to raise delivery errors. # config.action_mailer.raise_delivery_errors = false + config.action_mailer.delivery_method = :resend + config.action_mailer.resend_settings = { + api_key: ENV.fetch('RESEND_API_KEY', nil) + } # Enable locale fallbacks for I18n (makes lookups for any locale fall back to # the I18n.default_locale when a translation cannot be found). diff --git a/backend-rails/config/initializers/mailer.rb b/backend-rails/config/initializers/mailer.rb new file mode 100644 index 00000000..9ac75db0 --- /dev/null +++ b/backend-rails/config/initializers/mailer.rb @@ -0,0 +1 @@ +Resend.api_key = ENV.fetch('RESEND_API_KEY', nil) From 208b318fd05f5eb897dd49f380812f22a5ba592e Mon Sep 17 00:00:00 2001 From: leonardobrito Date: Thu, 8 Jun 2023 19:17:30 -0300 Subject: [PATCH 4/4] Remove empty spec --- backend-rails/spec/requests/auth_spec.rb | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 backend-rails/spec/requests/auth_spec.rb diff --git a/backend-rails/spec/requests/auth_spec.rb b/backend-rails/spec/requests/auth_spec.rb deleted file mode 100644 index fac1c18b..00000000 --- a/backend-rails/spec/requests/auth_spec.rb +++ /dev/null @@ -1,7 +0,0 @@ -require 'rails_helper' - -RSpec.describe 'Auths', type: :request do - describe 'GET /index' do - pending "add some examples (or delete) #{__FILE__}" - end -end