Skip to content
Open
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
2 changes: 2 additions & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -56,3 +56,5 @@ end
group :test do
gem 'simplecov', '~> 0.22.0', require: false
end

gem 'bcrypt'
2 changes: 2 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,7 @@ GEM
descendants_tracker (~> 0.0.4)
ice_nine (~> 0.11.0)
thread_safe (~> 0.3, >= 0.3.1)
bcrypt (3.1.20)
bootsnap (1.16.0)
msgpack (~> 1.2)
builder (3.2.4)
Expand Down Expand Up @@ -228,6 +229,7 @@ PLATFORMS
x86_64-linux

DEPENDENCIES
bcrypt
bootsnap (~> 1.16)
byebug
did_you_mean (~> 1.6, >= 1.6.3)
Expand Down
33 changes: 3 additions & 30 deletions app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,7 @@

class ApplicationController < ActionController::API
include ActionController::HttpAuthentication::Token::ControllerMethods

rescue_from ActionController::ParameterMissing, with: :show_parameter_missing_error

protected

def authenticate_user(&block)
return block&.call if current_user

head :unauthorized
end

def current_user
@current_user ||= authenticate_with_http_token do |token|
User.find_by(token: token)
end
end

def render_json(status, json = {})
render status: status, json: json
end

def show_parameter_missing_error(exception)
render_json(400, error: exception.message)
end

def set_todo_lists
user_todo_lists = current_user.todo_lists

@todo_lists = todo_lists_only_non_default? ? user_todo_lists.non_default : user_todo_lists
end
include Authenticatable
include ErrorHandleable
include Renderable
end
15 changes: 15 additions & 0 deletions app/controllers/concerns/authenticatable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module Authenticatable
protected

def authenticate_user(&block)
return block&.call if current_user

head :unauthorized
end

def current_user
@current_user ||= authenticate_with_http_token do |token|
User.find_by(token: token)
end
end
end
13 changes: 13 additions & 0 deletions app/controllers/concerns/error_handleable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
module ErrorHandleable
extend ActiveSupport::Concern

included do
rescue_from ActionController::ParameterMissing, with: :show_parameter_missing_error
end

protected

def show_parameter_missing_error(exception)
render_json(:bad_request, error: exception.message)
end
end
5 changes: 5 additions & 0 deletions app/controllers/concerns/renderable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
module Renderable
def render_json(status, json = {})
render status: status, json: json
end
end
9 changes: 9 additions & 0 deletions app/controllers/concerns/todo_listable.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module TodoListable
protected

def set_todo_lists
user_todo_lists = current_user.todo_lists

@todo_lists = todo_lists_only_non_default? ? user_todo_lists.non_default : user_todo_lists
end
end
23 changes: 14 additions & 9 deletions app/controllers/todo_lists_controller.rb
Original file line number Diff line number Diff line change
@@ -1,48 +1,49 @@
# frozen_string_literal: true

class TodoListsController < ApplicationController
include TodoListable
before_action :authenticate_user

before_action :set_todo_lists
before_action :set_todo_list, except: [:index, :create]

rescue_from ActiveRecord::RecordNotFound do |not_found|
render_json(404, todo_list: { id: not_found.id, message: 'not found' })
render_json(:not_found, todo_list: { id: not_found.id, message: 'not found' })
end

def index
todo_lists = @todo_lists.order_by(params).map(&:serialize_as_json)
todo_lists = TodoListsOrderQuery.new(@todo_lists, params).call.map(&:serialize_as_json)

render_json(200, todo_lists: todo_lists)
render_json(:ok, todo_lists: todo_lists)
end

def create
todo_list = @todo_lists.create(todo_list_params)

if todo_list.valid?
render_json(201, todo_list: todo_list.serialize_as_json)
render_todo_list_json(:created, todo_list: todo_list)
else
render_json(422, todo_list: todo_list.errors.as_json)
render_todo_list_json(:unprocessable_entity, errors: todo_list)
end
end

def show
render_json(200, todo_list: @todo_list.serialize_as_json)
render_todo_list_json(:ok, todo_list: @todo_list)
end

def destroy
@todo_list.destroy

render_json(200, todo_list: @todo_list.serialize_as_json)
render_todo_list_json(:ok, todo_list: @todo_list)
end

def update
@todo_list.update(todo_list_params)

if @todo_list.valid?
render_json(200, todo_list: @todo_list.serialize_as_json)
render_todo_list_json(:ok, todo_list: @todo_list)
else
render_json(422, todo_list: @todo_list.errors.as_json)
render_todo_list_json(:unprocessable_entity, errors: @todo_list)
end
end

Expand All @@ -57,4 +58,8 @@ def set_todo_list
def todo_list_params
params.require(:todo_list).permit(:title)
end

def render_todo_list_json(status, todo_list: nil, errors: nil)
render_json(status, todo_list: todo_list ? todo_list.serialize_as_json : errors.errors.as_json)
end
end
44 changes: 26 additions & 18 deletions app/controllers/todos_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# frozen_string_literal: true

class TodosController < ApplicationController
include TodoListable
before_action :authenticate_user

before_action :set_todo_lists
Expand All @@ -10,70 +11,69 @@ class TodosController < ApplicationController
rescue_from ActiveRecord::RecordNotFound do |not_found|
key = not_found.model == 'TodoList' ? :todo_list : :todo

render_json(404, key => { id: not_found.id, message: 'not found' })
render_json(:not_found, key => { id: not_found.id, message: 'not found' })
end

def index
todos = @todos.filter_by_status(params).order_by(params).map(&:serialize_as_json)
filter = TodoFilterQuery.new(@todos, params).call
todos = TodoOrderQuery.new(filter, params).call.map(&:serialize_as_json)

render_json(200, todos:)
render_json(:ok, todos:)
end

def create
todo = @todos.create(todo_params.except(:completed))

if todo.valid?
render_json(201, todo: todo.serialize_as_json)
render_todo_json(:created, todo: todo)
else
render_json(422, todo: todo.errors.as_json)
render_json(:unprocessable_entity, todo: todo.errors.as_json)
end
end

def show
render_json(200, todo: @todo.serialize_as_json)
render_todo_json(:ok, todo: @todo)
end

def destroy
@todo.destroy

render_json(200, todo: @todo.serialize_as_json)
render_json(:ok, todo: @todo.serialize_as_json)
end

def update
@todo.update(todo_params)

if @todo.valid?
render_json(200, todo: @todo.serialize_as_json)
render_todo_json(:ok, todo: @todo)
else
render_json(422, todo: @todo.errors.as_json)
render_json(:unprocessable_entity, todo: @todo.errors.as_json)
end
end

def complete
@todo.complete!
TodoCompleter.new(@todo).call

render_json(200, todo: @todo.serialize_as_json)
render_todo_json(:ok, todo: @todo)
end

def incomplete
@todo.incomplete!
TodoIncompleter.new(@todo).call

render_json(200, todo: @todo.serialize_as_json)
render_todo_json(:ok, todo: @todo)
end

private

def todo_lists_only_non_default? = false

def set_todos
scope =
@todos =
if params[:todo_list_id].present?
@todo_lists.find(params[:todo_list_id])
@todo_lists.find(params[:todo_list_id]).todos
else
action_name == 'create' ? @todo_lists.default.first! : current_user
default_or_user_todos
end

@todos = scope.todos
end

def set_todo
Expand All @@ -83,4 +83,12 @@ def set_todo
def todo_params
params.require(:todo).permit(:title, :due_at, :completed)
end

def render_todo_json(status, todo: nil, errors: nil)
render_json(status, todo: todo ? todo.serialize_as_json : { errors: errors })
end

def default_or_user_todos
action_name == 'create' ? @todo_lists.default.first!.todos : current_user.todos
end
end
52 changes: 14 additions & 38 deletions app/controllers/users_controller.rb
Original file line number Diff line number Diff line change
@@ -1,57 +1,33 @@
# frozen_string_literal: true

class UsersController < ApplicationController
def create
user_params = params.require(:user).permit(:name, :email, :password, :password_confirmation)

password = user_params[:password].to_s.strip
password_confirmation = user_params[:password_confirmation].to_s.strip
before_action :authenticate_user, only: [:show, :destroy]

errors = {}
errors[:password] = ["can't be blank"] if password.blank?
errors[:password_confirmation] = ["can't be blank"] if password_confirmation.blank?
def create
form = UserForm.new(user_params)

if errors.present?
render_json(422, user: errors)
if form.save
render_json(:created, user: form.user.as_json(only: [:id, :name, :token]))
else
if password != password_confirmation
render_json(422, user: { password_confirmation: ["doesn't match password"] })
else
password_digest = Digest::SHA256.hexdigest(password)

user = User.new(
name: user_params[:name],
email: user_params[:email],
token: SecureRandom.uuid,
password_digest: password_digest
)

if user.save
render_json(201, user: user.as_json(only: [:id, :name, :token]))
else
render_json(422, user: user.errors.as_json)
end
end
render_json(:unprocessable_entity, user: form.errors.as_json)
end
end

def show
perform_if_authenticated
render_json(:ok, user: { email: current_user.email })
end

def destroy
perform_if_authenticated do
current_user.destroy
if current_user.destroy
render_json(:ok, user: { email: current_user.email })
else
render_json(:unprocessable_entity, errors: current_user.errors.as_json)
end
end

private

def perform_if_authenticated(&block)
authenticate_user do
block.call if block

render_json(200, user: { email: current_user.email })
end
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
Loading