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

User resource 2 #134

Closed
wants to merge 6 commits into from
Closed
Show file tree
Hide file tree
Changes from all 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
1 change: 1 addition & 0 deletions server/.rspec
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
--require spec_helper
11 changes: 9 additions & 2 deletions server/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ gem 'jbuilder', '~> 2.9'
# Use Redis adapter to run Action Cable in production
# gem 'redis', '~> 4.0'
# Use ActiveModel has_secure_password
# gem 'bcrypt', '~> 3.1.7'

gem 'bcrypt', '~> 3.1.7'
gem 'jwt'
# Use Capistrano for deployment
# gem 'capistrano-rails', group: :development

Expand All @@ -44,6 +44,7 @@ group :development, :test do
# Adds support for Capybara system testing and selenium driver
gem 'capybara', '~> 3.24'
gem 'selenium-webdriver'
gem 'rspec-rails', '~> 3.8'
end

group :development do
Expand All @@ -55,5 +56,11 @@ group :development do
gem 'spring-watcher-listen', '~> 2.0.0'
end

group :test do
gem 'factory_bot_rails', '~> 4.0'
gem 'shoulda-matchers', '~> 3.1'
gem 'faker'
gem 'database_cleaner'
end
# Windows does not include zoneinfo files, so bundle the tzinfo-data gem
gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
61 changes: 61 additions & 0 deletions server/Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ GEM
addressable (2.6.0)
public_suffix (>= 2.0.2, < 4.0)
arel (9.0.0)
bcrypt (3.1.13)
bindex (0.5.0)
bootsnap (1.4.4)
msgpack (~> 1.0)
Expand All @@ -69,15 +70,31 @@ GEM
coffee-script-source (1.12.2)
concurrent-ruby (1.1.5)
crass (1.0.4)
database_cleaner (1.7.0)
diff-lcs (1.3)
equatable (0.6.0)
erubi (1.8.0)
execjs (2.7.0)
factory_bot (4.11.1)
activesupport (>= 3.0.0)
factory_bot_rails (4.11.1)
factory_bot (~> 4.11.1)
railties (>= 3.0.0)
faker (1.9.4)
i18n (>= 0.7)
pastel (~> 0.7.2)
thor (~> 0.20.0)
tty-pager (~> 0.12.0)
tty-screen (~> 0.6.5)
tty-tree (~> 0.3.0)
ffi (1.10.0)
globalid (0.4.2)
activesupport (>= 4.2.0)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
jbuilder (2.9.1)
activesupport (>= 4.2.0)
jwt (2.2.1)
listen (3.1.5)
rb-fsevent (~> 0.9, >= 0.9.4)
rb-inotify (~> 0.9, >= 0.9.7)
Expand All @@ -98,6 +115,9 @@ GEM
nio4r (2.3.1)
nokogiri (1.10.3)
mini_portile2 (~> 2.4.0)
pastel (0.7.3)
equatable (~> 0.6)
tty-color (~> 0.5)
pg (1.1.4)
public_suffix (3.1.0)
puma (3.12.1)
Expand Down Expand Up @@ -133,6 +153,23 @@ GEM
rb-inotify (0.10.0)
ffi (~> 1.0)
regexp_parser (1.5.1)
rspec-core (3.8.1)
rspec-support (~> 3.8.0)
rspec-expectations (3.8.4)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-mocks (3.8.1)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-rails (3.8.2)
actionpack (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
rspec-mocks (~> 3.8.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.2)
ruby_dep (1.5.0)
rubyzip (1.2.2)
sass (3.7.3)
Expand All @@ -149,6 +186,8 @@ GEM
selenium-webdriver (3.142.3)
childprocess (>= 0.5, < 2.0)
rubyzip (~> 1.2, >= 1.2.2)
shoulda-matchers (3.1.3)
activesupport (>= 4.0.0)
spring (2.1.0)
spring-watcher-listen (2.0.1)
listen (>= 2.7, < 4.0)
Expand All @@ -161,16 +200,31 @@ GEM
activesupport (>= 4.0)
sprockets (>= 3.0.0)
sqlite3 (1.4.1)
strings (0.1.5)
strings-ansi (~> 0.1)
unicode-display_width (~> 1.5)
unicode_utils (~> 1.4)
strings-ansi (0.1.0)
thor (0.20.3)
thread_safe (0.3.6)
tilt (2.0.9)
tty-color (0.5.0)
tty-pager (0.12.1)
strings (~> 0.1.4)
tty-screen (~> 0.6)
tty-which (~> 0.4)
tty-screen (0.6.5)
tty-tree (0.3.0)
tty-which (0.4.1)
turbolinks (5.2.0)
turbolinks-source (~> 5.2)
turbolinks-source (5.2.0)
tzinfo (1.2.5)
thread_safe (~> 0.1)
uglifier (4.1.20)
execjs (>= 0.3.0, < 3)
unicode-display_width (1.6.0)
unicode_utils (1.4.0)
web-console (3.7.0)
actionview (>= 5.0)
activemodel (>= 5.0)
Expand All @@ -186,17 +240,24 @@ PLATFORMS
ruby

DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap (>= 1.1.0)
byebug
capybara (~> 3.24)
coffee-rails (~> 5.0)
database_cleaner
factory_bot_rails (~> 4.0)
faker
jbuilder (~> 2.9)
jwt
listen (>= 3.0.5, < 3.2)
pg
puma (~> 3.12)
rails (~> 5.2)
rspec-rails (~> 3.8)
sass-rails (~> 5.0)
selenium-webdriver
shoulda-matchers (~> 3.1)
spring
spring-watcher-listen (~> 2.0.0)
sqlite3 (~> 1.4.1)
Expand Down
3 changes: 3 additions & 0 deletions server/app/assets/javascripts/api_users.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
3 changes: 3 additions & 0 deletions server/app/assets/javascripts/users.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# Place all the behaviors and hooks related to the matching controller here.
# All this logic will automatically be available in application.js.
# You can use CoffeeScript in this file: http://coffeescript.org/
3 changes: 3 additions & 0 deletions server/app/assets/stylesheets/api_users.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the ApiUsers controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
3 changes: 3 additions & 0 deletions server/app/assets/stylesheets/users.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
// Place all the styles related to the Users controller here.
// They will automatically be included in application.css.
// You can use Sass (SCSS) here: http://sass-lang.com/
24 changes: 24 additions & 0 deletions server/app/auth/authenticate_user.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# app/auth/authenticate_user.rb
class AuthenticateUser
def initialize(email, password)
@email = email
@password = password
end

# Service entry point
def call
JsonWebToken.encode(user_id: api_user.id) if api_user
end

private

attr_reader :email, :password

# verify user credentials
def api_user
api_user = ApiUser.find_by(email: email)
return api_user if api_user && api_user.authenticate(password)
# raise Authentication error if credentials are invalid
raise(ExceptionHandler::AuthenticationError, Message.invalid_credentials)
end
end
42 changes: 42 additions & 0 deletions server/app/auth/authorize_api_request.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
class AuthorizeApiRequest
def initialize(headers = {})
@headers = headers
end

# Service entry point - return valid user object
def call
{
api_user: api_user
}
end

private

attr_reader :headers

def api_user
# check if user is in the database
# memoize user object
@api_user ||= ApiUser.find(decoded_auth_token[:api_user_id]) if decoded_auth_token
# handle user not found
rescue ActiveRecord::RecordNotFound => e
# raise custom error
raise(
ExceptionHandler::InvalidToken,
("#{Message.invalid_token} #{e.message}")
)
end

# decode authentication token
def decoded_auth_token
@decoded_auth_token ||= JsonWebToken.decode(http_auth_header)
end

# check for token in `Authorization` header
def http_auth_header
if headers['Authorization'].present?
return headers['Authorization'].split(' ').last
end
raise(ExceptionHandler::MissingToken, Message.missing_token)
end
end
44 changes: 44 additions & 0 deletions server/app/controllers/api/v1/api_users_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
class Api::V1::ApiUsersController < ApplicationController
before_action :set_api_user, only: [:show, :update, :destroy]

#GET /api_users
def index
@api_users = ApiUser.all
json_response(@api_users)
end

# Post /api_users
def create
@api_user = ApiUser.create!(api_user_params)
json_response(@api_user, :created)
end

# GET /api_users/:id
def show
json_response(@api_user)
end

# PUT /api_users/:id
def update
@api_user.update(api_user_params)
head :no_content
end

# DELETE /api_users/:id
def destroy
@api_user.destroy
head :no_content
end

private

def api_user_params
#whitelist params
#params.permit(:email, :password_digest)
params.require(:api_user).permit(:first_name, :last_name, :city, :email, :password_digest, :mentor, :mentee)
end

def set_api_user
@api_user = ApiUser.find(params[:id])
end
end
7 changes: 5 additions & 2 deletions server/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
class ApplicationController < ActionController::Base
protect_from_forgery with: :exception
class ApplicationController < ActionController::API # used to say 'Base'
#protect_from_forgery with: :exception
include Response
include ExceptionHandler
end

34 changes: 34 additions & 0 deletions server/app/controllers/concerns/exception_handler.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
module ExceptionHandler
extend ActiveSupport::Concern

# Define custom error subclasses - rescue catches `StandardErrors`
class AuthenticationError < StandardError; end
class MissingToken < StandardError; end
class InvalidToken < StandardError; end

included do
rescue_from ActiveRecord::RecordInvalid, with: :four_two_two
rescue_from ActiveRecord::RecordNotFound, with: :four_o_four
rescue_from ActionController::ParameterMissing, with: :four_two_two
#Following handlers not required until authentication set up
#rescue_from ExceptionHandler::AuthenticationError, with: :unauthorized_request
#rescue_from ExceptionHandler::MissingToken, with: :four_twenty_two
#rescue_from ExceptionHandler::InvalidToken, with: :four_twenty_two
end

private

def four_o_four(e)
json_response({message: e.message}, :not_found)
end

def four_two_two(e)
json_response({message: e.message}, :unprocessable_entity)
end

# JSON response with message; Status code 401 - Unauthorized
def unauthorized_request(e)
json_response({ message: e.message }, :unauthorized)
end

end
5 changes: 5 additions & 0 deletions server/app/controllers/concerns/response.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Response
def json_response(object, status = :ok)
render json: object, status: status
end
end
4 changes: 0 additions & 4 deletions server/app/controllers/welcome_controller.rb

This file was deleted.

2 changes: 2 additions & 0 deletions server/app/helpers/api_users_helper.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module ApiUsersHelper
end
17 changes: 17 additions & 0 deletions server/app/lib/json_web_token.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
class JsonWebToken
#secret to encode and decode token
HMAC_SECRET = Rails.application.secrets.secret_key_base

def self.encode(payload,exp = 24.hours.from_now)
payload[:exp] = exp.to_i
JWT.encode(payload,HMAC_SECRET)
end

def self.decode(token)
body = JWT.decode(token,HMAC_SECRET)[0]
HashWithIndifferentAccess.new body
rescue JWT::DecodeError => e
raise ExceptionHandler::InvalidToken, e.message
end
end

Loading