Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Send confirmation email for registration #249

Open
wants to merge 11 commits into
base: devel
Choose a base branch
from
2 changes: 1 addition & 1 deletion app/commands/authenticate_user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ def initialize(email, password)
end

def call
JsonWebToken.encode(user_id: user.id) if user
JsonWebToken.encode(payload: { user_id: user.id }, secret_key: Rails.application.secrets.secret_key_base) if user
end

private
Expand Down
2 changes: 1 addition & 1 deletion app/commands/authorize_api_request.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ def user
end

def decoded_auth_token
@decoded_auth_token ||= JsonWebToken.decode(http_auth_header)
@decoded_auth_token ||= JsonWebToken.decode(token: http_auth_header, secret_key: Rails.application.secrets.secret_key_base)
end

def http_auth_header
Expand Down
11 changes: 11 additions & 0 deletions app/commands/generate_verify_token.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
class GenerateVerifyToken
prepend SimpleCommand

def initialize(user_id)
@user_id = user_id
end

def call
JsonWebToken.encode(payload: { user_id: @user_id }, secret_key: Rails.application.secrets.secret_key_email)
end
end
8 changes: 4 additions & 4 deletions app/commands/json_web_token.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
class JsonWebToken
class << self
def encode(payload, exp = 24.hours.from_now)
def encode(payload:, exp: 24.hours.from_now, secret_key:)
payload[:exp] = exp.to_i
JWT.encode(payload, Rails.application.secrets.secret_key_base)
JWT.encode(payload, secret_key)
end

def decode(token)
body = JWT.decode(token, Rails.application.secrets.secret_key_base)[0]
def decode(token:, secret_key:)
body = JWT.decode(token, secret_key)[0]
HashWithIndifferentAccess.new body
rescue
nil
Expand Down
14 changes: 14 additions & 0 deletions app/controllers/authentication_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,4 +10,18 @@ def authenticate
render json: { error: command.errors } , status: :unauthorized
end
end

def confirm_email
begin
token = params[:token]
decoded_token = JWT.decode(token, Rails.application.secrets.secret_key_email)[0]
current_user = User.find(decoded_token["user_id"].to_i)
email = current_user.email
current_user.confirmation_token = true
current_user.save
render json: { status: 200, message: "User confirmed" }.to_json
rescue JWT::DecodeError => e
render json: { status: 401, message: "Invalid token" }.to_json
end
end
end
20 changes: 16 additions & 4 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,17 @@ class UsersController < ApplicationController

# GET /users/1
def show
@user = User.find(params[:id].to_i)
render json: @user
begin
@user = User.find(params[:id].to_i)
render json: @user
rescue ActiveRecord::RecordNotFound => e
render json: {
error: e.to_s
}, status: :not_found
end
end

# POST /users
# POST /users V1
def create
@user = User.new(user_params)
if @user.save
Expand Down Expand Up @@ -86,7 +92,13 @@ def destroy

private
def set_user
@user = User.find(params[:id])
begin
@user = User.find(params[:id])
rescue ActiveRecord::RecordNotFound => e
render json: {
error: e.to_s
}, status: :not_found
end
end

def user_params
Expand Down
33 changes: 33 additions & 0 deletions app/controllers/v1/users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
require "rest-client"
class V1::UsersController < ApplicationController
include ValidationsHelper
include UsersDoc

skip_before_action :authenticate_request, only: [:create, :all]

before_action only: [:show, :update, :destroy] do
set_user
validate_user(:id, 0)
end

# POST /users
def create
@user = User.new(user_params)
if @user.save
@token = GenerateVerifyToken.call(@user.id)
UserMailer.with(user: @user, token: @token).verify_email.deliver_now!
render json: @token, status: :created
else
render json: @user.errors, status: :unprocessable_entity
end
end

private
def set_user
@user = User.find(params[:id])
end

def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
2 changes: 1 addition & 1 deletion app/mailers/application_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
class ApplicationMailer < ActionMailer::Base
default from: "[email protected]"
layout "mailer"
layout "verify_email"
end
9 changes: 9 additions & 0 deletions app/mailers/user_mailer.rb
Original file line number Diff line number Diff line change
@@ -1,9 +1,18 @@
class UserMailer < ApplicationMailer
default from: "[email protected]"
layout "verify_email"

def recover_password_email
@user = params[:user]
@uri = ENV["PASSWORD_RESET_ADDRESS"].gsub(/<token>/, @user.reset_password_token)
mail(to: @user.email, subject: "Falko password recovery")
end

def verify_email
@user = params[:user]
@email = @user[:email]
user_token = params[:token]
@token = user_token.result
mail to: @email, subject: "Email confirmation token"
end
end
11 changes: 11 additions & 0 deletions app/views/layouts/verify_email.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Email Confirmation</h1>

<p>
Hi <%= @email %>,
</p>

<p>
Confirm your email http://localhost:3000/verify_token/?token=<%= @token %>

:)
</p>
11 changes: 11 additions & 0 deletions app/views/layouts/verify_email.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Email Confirmation</h1>

<p>
Hi <%= @email %>,
</p>

<p>
Confirm your email http://localhost:3000/verify_token/?token=<%= @token %>

:)
</p>
11 changes: 11 additions & 0 deletions app/views/user_mailer/verify_email.html.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Email Confirmation</h1>

<p>
Hi <%= @email %>,
</p>

<p>
Confirm your email http://localhost:3000/verify_token/?token=<%= @token %>

:)
</p>
11 changes: 11 additions & 0 deletions app/views/user_mailer/verify_email.text.erb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<h1>Email Confirmation</h1>

<p>
Hi <%= @email %>,
</p>

<p>
Confirm your email http://localhost:3000/verify_token/?token=<%= @token %>

:)
</p>
10 changes: 10 additions & 0 deletions config/environment.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,13 @@

# Initialize the Rails application.
Rails.application.initialize!

ActionMailer::Base.smtp_settings = {
user_name: "apikey",
password: "",
domain: "gmail.com",
address: "smtp.sendgrid.net",
port: 587,
authentication: :plain,
enable_starttls_auto: true
}
1 change: 1 addition & 0 deletions config/environments/development.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

# Show full error reports.
config.consider_all_requests_local = true
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }

# Enable/disable caching. By default caching is disabled.
if Rails.root.join("tmp/caching-dev.txt").exist?
Expand Down
6 changes: 6 additions & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
post "request_github_token", to: "users#request_github_token"
post "remove_github_token", to: "users#remove_github_token"

get "verify_token", to: "authentication#confirm_email"

post "password/forgot", to: "passwords#forgot"
post "password/reset", to: "passwords#reset"
get "password/validate_token", to: "passwords#validate_token"
Expand Down Expand Up @@ -33,6 +35,10 @@
post "projects/:id/reopen_issue", to: "issues#reopen_issue"
post "/projects/:id/issues/graphic", to: "issues#issue_graphic_data"

namespace :v1 do
post "/users", to: "users#create"
end

resources :users, shallow: true do
resources :projects do
resources :grades
Expand Down
2 changes: 1 addition & 1 deletion config/secrets.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@

development:
secret_key_base: fbaf4d96ad5701178ae81fc6158701d7117a0e212845183f90429489101c4e3dadce2a63ef87f228b2dd2aa7109dda79c73a9386bac2bcd85237d9984d68cf5c
secret_key_email: fd701599009e745a0eaf501075679588344bb385e979a77f01223f87918a1fae9fa306d97216422ead69c3767a360f1f12587d44ba9b9ad04b3a28acf71c65bb

test:
secret_key_base: 4b182d9b7c7d4c04e3229e2d0294952305f2c475cd73884316b3bf6230e95f00a53364702860ea59ecb6c88746ef52aa92043f0ab3bac84d4ecab1e1a8e0e0f4

# Do not keep production secrets in the unencrypted secrets file.
# Instead, either read values from the environment.
# Or, use `bin/rails secrets:setup` to configure encrypted secrets
Expand Down
5 changes: 5 additions & 0 deletions db/migrate/20191013155716_add_authenticated_field_to_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class AddAuthenticatedFieldToUser < ActiveRecord::Migration[5.1]
def up
add_column :users, :confirmation_token, :boolean, default: false
end
end
3 changes: 2 additions & 1 deletion db/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.

ActiveRecord::Schema.define(version: 20190418161604) do
ActiveRecord::Schema.define(version: 20191013155716) do

# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
Expand Down Expand Up @@ -105,6 +105,7 @@
t.string "access_token"
t.string "reset_password_token"
t.datetime "reset_password_sent_at"
t.boolean "confirmation_token", default: false
end

add_foreign_key "grades", "projects"
Expand Down