Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
2 changes: 1 addition & 1 deletion app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ def show
render json: @user
end

# POST /users
# POST /users V1
def create
@user = User.new(user_params)
if @user.save
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: "from@example.com"
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: "noreply@falko.com"
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