Skip to content

Commit

Permalink
Merge pull request #196 from Sun-Mountain/91-feature-confirmation-on-…
Browse files Browse the repository at this point in the history
…registration

91 - User confirmation
  • Loading branch information
Sun-Mountain authored Jul 27, 2023
2 parents 134227e + 1241328 commit e767f10
Show file tree
Hide file tree
Showing 43 changed files with 426 additions and 71 deletions.
7 changes: 6 additions & 1 deletion api/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@ ruby '3.1.2'

gem 'puma', '~> 5.0'
gem 'rails', '~> 7.0.4'

gem 'dotenv-rails'
gem 'pg', '~> 1.4'
gem "activejob", "~> 7.0"
gem "actionmailer", "~> 7.0"
gem "activerecord", "~> 7.0"

gem 'active_model_serializers', '~> 0.10'
gem 'bootsnap', require: false
Expand Down Expand Up @@ -43,9 +45,12 @@ end
group :development do
# Speed up commands on slow machines / big apps [https://github.com/rails/spring]
# gem "spring"
gem "letter_opener", "~> 1.8"
gem "letter_opener_web", "~> 2.0"
end

group :test do
gem 'capybara'
gem "webmock"
gem 'fakeredis'
end
17 changes: 17 additions & 0 deletions api/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ GEM
factory_bot_rails (6.2.0)
factory_bot (~> 6.2.0)
railties (>= 5.0.0)
fakeredis (0.9.2)
redis (~> 4.8)
fast_jsonapi (1.5)
activesupport (>= 4.2)
globalid (1.1.0)
Expand All @@ -150,6 +152,15 @@ GEM
json (2.6.3)
jsonapi-renderer (0.2.2)
jwt (2.7.0)
launchy (2.5.2)
addressable (~> 2.8)
letter_opener (1.8.1)
launchy (>= 2.2, < 3)
letter_opener_web (2.0.0)
actionmailer (>= 5.2)
letter_opener (~> 1.7)
railties (>= 5.2)
rexml
loofah (2.20.0)
crass (~> 1.0.2)
nokogiri (>= 1.5.9)
Expand Down Expand Up @@ -297,7 +308,10 @@ PLATFORMS
ruby

DEPENDENCIES
actionmailer (~> 7.0)
active_model_serializers (~> 0.10)
activejob (~> 7.0)
activerecord (~> 7.0)
bcrypt (~> 3.1.7)
bootsnap
bundler-audit
Expand All @@ -308,8 +322,11 @@ DEPENDENCIES
devise-jwt
dotenv-rails
factory_bot_rails
fakeredis
fast_jsonapi
jwt
letter_opener (~> 1.8)
letter_opener_web (~> 2.0)
nokogiri
pg (~> 1.4)
pry
Expand Down
4 changes: 2 additions & 2 deletions api/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,14 @@ class ApplicationController < ActionController::API
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:account_update) do |user|
user.permit(
:first_name, :last_name, :preferred_username,
:first_name, :last_name, :username,
:email, :password, :password_confirmation, :current_password, :admin
)
end

devise_parameter_sanitizer.permit(:sign_up) do |user|
user.permit(
:first_name, :last_name, :preferred_username,
:first_name, :last_name, :username,
:email, :password, :password_confirmation
)
end
Expand Down
47 changes: 47 additions & 0 deletions api/app/controllers/confirmations_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
# frozen_string_literal: true

# require './lib/redis_store/mail_throttle_store'

class ConfirmationsController < Devise::ConfirmationsController
skip_before_action :authenticate_user
before_action :token
respond_to :json

def create
if token
return render json: { status: 403, message: 'There was an issue.' }, status: :forbidden unless find_user_by_token
if @user.confirm
render json: { status: 201 }, status: :ok
else
render json: { err: @event.errors.full_messages }, status: 503
end
elsif find_user_by_email
return render json: { status: 403, message: 'There was an issue.' }, status: :forbidden if @user.confirmed?
@user.send_confirmation_instructions
else
render json: { err: @event.errors.full_messages }, status: 503
end
end

private

def after_confirmation_path_for(resource_name, resource)
sign_in(resource)
end

def confirmation_params
params.require(:confirmation).permit(:token, :email)
end

def token
@token = confirmation_params[:token]
end

def find_user_by_email
@user = User.find_by_email(confirmation_params[:email])
end

def find_user_by_token
@user = User.find_by_confirmation_token(@token)
end
end
16 changes: 15 additions & 1 deletion api/app/controllers/users/sessions_controller.rb
Original file line number Diff line number Diff line change
@@ -1,11 +1,21 @@
# frozen_string_literal: true

class Users::SessionsController < Devise::SessionsController
skip_before_action :authenticate_user, only: %i[new create]
before_action :find_user
before_action :confirm_user
skip_before_action :authenticate_user
respond_to :json

private

def confirm_user
return render json: { status: 403, message: 'You have to confirm your email address before continuing.' }, status: :forbidden unless @user.confirmed?
end

def find_user
@user = User.find_by_email(session_params[:email])
end

def respond_with(resource, _opts = {})
render json: {
status: {code: 200, message: 'Logged in sucessfully.'},
Expand All @@ -26,4 +36,8 @@ def respond_to_on_destroy
}, status: :unauthorized
end
end

def session_params
params.require(:user).permit(:email, :password)
end
end
2 changes: 1 addition & 1 deletion api/app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,6 @@ def find_user
end

def user_params
params.require(:user).permit(:id, :email, :first_name, :last_name, :preferred_username, :current_password, :password, :password_confirmation)
params.require(:user).permit(:id, :email, :first_name, :last_name, :username, :current_password, :password, :password_confirmation)
end
end
7 changes: 7 additions & 0 deletions api/app/helpers/mailer_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# frozen_string_literal: true

module MailerHelper
def last_email
ActionMailer::Base.deliveries.last
end
end
2 changes: 1 addition & 1 deletion api/app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# frozen_string_literal: true

class ApplicationMailer < ActionMailer::Base
default from: '[email protected]'
default from: '[email protected]'
layout 'mailer'
end
1 change: 1 addition & 0 deletions api/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ class User < ApplicationRecord
include Devise::JWT::RevocationStrategies::JTIMatcher

devise :database_authenticatable, :registerable, :validatable,
:trackable, :confirmable, :recoverable,
:jwt_authenticatable, jwt_revocation_strategy: self
# has_secure_password
has_many :events
Expand Down
2 changes: 1 addition & 1 deletion api/app/serializers/user_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
class UserSerializer
include FastJsonapi::ObjectSerializer
attributes :id, :email, :created_at, :first_name, :last_name, :preferred_username, :admin
attributes :id, :email, :confirmed_at, :created_at, :first_name, :last_name, :username, :admin
attribute :created_date do |user|
user.created_at && user.created_at.strftime('%m/%d/%Y')
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<p>Welcome <%= @email %>!</p>

<p>You can confirm your account email through the link below:</p>

<p><%= link_to 'Confirm my account', confirmation_url(@resource, confirmation_token: @token) %></p>
7 changes: 7 additions & 0 deletions api/app/views/devise/mailer/email_changed.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>Hello <%= @email %>!</p>

<% if @resource.try(:unconfirmed_email?) %>
<p>We're contacting you to notify you that your email is being changed to <%= @resource.unconfirmed_email %>.</p>
<% else %>
<p>We're contacting you to notify you that your email has been changed to <%= @resource.email %>.</p>
<% end %>
3 changes: 3 additions & 0 deletions api/app/views/devise/mailer/password_change.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<p>Hello <%= @resource.email %>!</p>

<p>We're contacting you to notify you that your password has been changed.</p>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<p>Hello <%= @resource.email %>!</p>

<p>Someone has requested a link to change your password. You can do this through the link below.</p>

<p><%= link_to 'Change my password', edit_password_url(@resource, reset_password_token: @token) %></p>

<p>If you didn't request this, please ignore this email.</p>
<p>Your password won't change until you access the link above and create a new one.</p>
7 changes: 7 additions & 0 deletions api/app/views/devise/mailer/unlock_instructions.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<p>Hello <%= @resource.email %>!</p>

<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>

<p>Click the link below to unlock your account:</p>

<p><%= link_to 'Unlock my account', unlock_url(@resource, unlock_token: @token) %></p>
15 changes: 15 additions & 0 deletions api/config/application.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,21 @@ class Application < Rails::Application
config.api_only = true
config.hosts.clear

# Don't generate system test files.
config.generators.system_tests = nil

# field_with_errors support, avoid that nasty line break on errors
config.action_view.field_error_proc = Proc.new { |html_tag, instance|
html_tag
}

config.active_job.queue_adapter = :sidekiq

# Sending mail with`DeliveryJob` has been deprecated. Work has been moved to `MailDeliveryJob`
config.action_mailer.delivery_job = "ActionMailer::MailDeliveryJob"

config.to_prepare { Devise::Mailer.layout "mailer" }

# Configuration for the application, engines, and railties goes here.
#
# These settings can be overridden in specific environments using the files
Expand Down
10 changes: 8 additions & 2 deletions api/config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
}
else
config.action_controller.perform_caching = false

config.cache_store = :null_store
end

Expand All @@ -40,6 +39,12 @@

config.action_mailer.perform_caching = false

config.action_mailer.perform_deliveries = true

# By default we use letter_opener to render the email in a browser
# rather than send them:
config.action_mailer.delivery_method = :letter_opener_web

# Print deprecation notices to the Rails logger.
config.active_support.deprecation = :log

Expand All @@ -63,5 +68,6 @@

# Uncomment if you wish to allow Action Cable access from any origin.
# config.action_cable.disable_request_forgery_protection = true
config.action_mailer.default_url_options = { host: 'localhost', port: 4000 }
config.action_mailer.default_url_options = { host: 'localhost', port: 5173 }
config.action_mailer.asset_host = "http://localhost:5173/account"
end
10 changes: 9 additions & 1 deletion api/config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
# Eager loading loads your whole application. When running a single test locally,
# this probably isn't necessary. It's a good idea to do in a continuous integration
# system, or in some way before deploying your code.
config.eager_load = ENV['CI'].present?
config.eager_load = false

# Configure public file server for tests with Cache-Control for performance.
config.public_file_server.enabled = true
Expand Down Expand Up @@ -54,6 +54,14 @@
# Tell Active Support which deprecation messages to disallow.
config.active_support.disallowed_deprecation_warnings = []

# Tell Action Mailer not to deliver emails to the real world.
# The :test delivery method accumulates sent emails in the
# ActionMailer::Base.deliveries array.
config.action_mailer.delivery_method = :test

# Devise requires mailer
config.action_mailer.default_url_options = { host: 'localhost', port: 3500 }

# Raises error for missing translations.
# config.i18n.raise_on_missing_translations = true

Expand Down
10 changes: 5 additions & 5 deletions api/config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
# confirmation, reset password and unlock tokens in the database.
# Devise will use the `secret_key_base` as its `secret_key`
# by default. You can change it below and use your own secret key.
config.secret_key = '4cecc8861ba24d331afadba33aa48de813c7821fb5cee779fb8fe0b70698467e49148d31df264f1d300f1a9ccb667e928c493e7932ab18fcf267735296f5592b'
# config.secret_key = '4cecc8861ba24d331afadba33aa48de813c7821fb5cee779fb8fe0b70698467e49148d31df264f1d300f1a9ccb667e928c493e7932ab18fcf267735296f5592b'

# ==> Controller configuration
# Configure the parent class to the devise controllers.
Expand All @@ -24,7 +24,7 @@
# 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.
config.mailer_sender = '[email protected]'
config.mailer_sender = '[email protected]'

# Configure the class responsible to send e-mails.
# config.mailer = 'Devise::Mailer'
Expand Down Expand Up @@ -143,7 +143,7 @@
# without confirming their account.
# Default is 0.days, meaning the user cannot access the website without
# confirming their account.
# config.allow_unconfirmed_access_for = 2.days
config.allow_unconfirmed_access_for = nil

# 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
Expand All @@ -157,7 +157,7 @@
# 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
config.reconfirmable = false

# Defines which key will be used when confirming an account
# config.confirmation_keys = [:email]
Expand All @@ -167,7 +167,7 @@
# config.remember_for = 2.weeks

# Invalidates all the remember me tokens when the user signs out.
config.expire_all_remember_me_on_sign_out = true
# config.expire_all_remember_me_on_sign_out = true

# If true, extends the user's remember period when remembered via cookie.
# config.extend_remember_period = false
Expand Down
9 changes: 8 additions & 1 deletion api/config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@

Rails.application.routes.draw do
devise_for :users, path: '', path_names: {
confirmations: "confirmations",
sign_in: 'login',
sign_out: 'logout',
registration: 'signup'
},
controllers: {
confirmations: "confirmations",
sessions: 'users/sessions',
registrations: 'users/registrations'
}
Expand All @@ -18,6 +20,11 @@
get 'owned', action: :user_owned, controller: 'events'
end


resources :admin

if Rails.env.development?
require 'sidekiq/web'
mount Sidekiq::Web, at: '/sidekiq'
mount LetterOpenerWeb::Engine, at: "/letter_opener"
end
end
Loading

0 comments on commit e767f10

Please sign in to comment.