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

BE | Create UserPuzzles#create & Update UserLoans#create Endpoints #52

Merged
merged 18 commits into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
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 Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ group :development, :test do
# See https://guides.rubyonrails.org/debugging_rails_applications.html#debugging-with-the-debug-gem
# gem 'bundler-audit'
gem 'capybara' #used to write tests
gem 'cloudinary'
gem "debug", platforms: %i[ mri mingw x64_mingw ]
gem 'factory_bot_rails' #used to make fake data
gem 'faker' #used to make fake data
Expand Down
22 changes: 22 additions & 0 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ GEM
addressable (2.8.5)
public_suffix (>= 2.0.2, < 6.0)
ast (2.4.2)
aws_cf_signer (0.1.3)
base64 (0.1.1)
bcrypt (3.1.19)
bootsnap (1.16.0)
Expand All @@ -83,6 +84,9 @@ GEM
rack-test (>= 0.6.3)
regexp_parser (>= 1.5, < 3.0)
xpath (~> 3.2)
cloudinary (1.27.0)
aws_cf_signer
rest-client (>= 2.0.0)
coderay (1.1.3)
concurrent-ruby (1.2.2)
crass (1.0.6)
Expand All @@ -92,6 +96,8 @@ GEM
reline (>= 0.3.1)
diff-lcs (1.5.0)
docile (1.4.0)
domain_name (0.5.20190701)
unf (>= 0.0.5, < 1.0.0)
erubi (1.12.0)
factory_bot (6.2.1)
activesupport (>= 5.0.0)
Expand All @@ -102,6 +108,9 @@ GEM
i18n (>= 1.8.11, < 2)
globalid (1.2.1)
activesupport (>= 6.1)
http-accept (1.7.0)
http-cookie (1.0.5)
domain_name (~> 0.5)
i18n (1.14.1)
concurrent-ruby (~> 1.0)
io-console (0.6.0)
Expand All @@ -123,6 +132,9 @@ GEM
marcel (1.0.2)
matrix (0.4.2)
method_source (1.0.0)
mime-types (3.5.1)
mime-types-data (~> 3.2015)
mime-types-data (3.2023.1003)
mini_mime (1.1.5)
minitest (5.20.0)
msgpack (1.7.2)
Expand All @@ -135,6 +147,7 @@ GEM
timeout
net-smtp (0.4.0)
net-protocol
netrc (0.11.0)
nio4r (2.5.9)
nokogiri (1.15.4-x86_64-darwin)
racc (~> 1.4)
Expand Down Expand Up @@ -194,6 +207,11 @@ GEM
regexp_parser (2.8.2)
reline (0.3.9)
io-console (~> 0.5)
rest-client (2.1.0)
http-accept (>= 1.7.0, < 2.0)
http-cookie (>= 1.0.2, < 2.0)
mime-types (>= 1.16, < 4.0)
netrc (~> 0.8)
rexml (3.2.6)
rspec-core (3.12.2)
rspec-support (~> 3.12.0)
Expand Down Expand Up @@ -244,6 +262,9 @@ GEM
timeout (0.4.0)
tzinfo (2.0.6)
concurrent-ruby (~> 1.0)
unf (0.1.4)
unf_ext
unf_ext (0.0.8.2)
unicode-display_width (2.5.0)
websocket-driver (0.7.6)
websocket-extensions (>= 0.1.0)
Expand All @@ -260,6 +281,7 @@ DEPENDENCIES
bcrypt (~> 3.1.7)
bootsnap
capybara
cloudinary
debug
factory_bot_rails
faker
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/api/v1/sessions_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ def destroy
end

private

def authorize
render json: { error: 'Not authorized' }, status: :unauthorized unless session[:user_id]
end
Expand Down
26 changes: 19 additions & 7 deletions app/controllers/api/v1/users/loans_controller.rb
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
class Api::V1::Users::LoansController < ApplicationController
def create
puzzle = Puzzle.find(params[:puzzle_id])
borrower = User.find(params[:borrower_id])

loan = Loan.new(owner: puzzle.user, puzzle:, borrower:)
before_action :find_users_and_puzzle, only: [:create]
before_action :check_puzzle_status, only: [:create]

def create
loan = Loan.new(owner_id: @owner.id, puzzle_id: @puzzle.id, borrower_id: @borrower.id)

if loan.save
render json: LoanSerializer.new(loan), status: 201
render json: LoanSerializer.new(loan), status: :created #201
else
render json: { error: "Unable to create loan" }, status: 422
render json: { error: "Unable to create loan" }, status: :unprocessable_entity #422
end
end

Expand All @@ -28,4 +28,16 @@ def update
render json: { error: "Unable to update loan status" }, status: 422
end
end

private

def find_users_and_puzzle
@owner = User.find(params[:user_id])
@borrower = User.find(params[:borrower_id])
@puzzle = Puzzle.find(params[:puzzle_id])
end

def check_puzzle_status
render json: { error: "Puzzle is not available for loan." }, status: :unprocessable_entity if @puzzle.status != "Available"
end
end
18 changes: 13 additions & 5 deletions app/controllers/api/v1/users/puzzles_controller.rb
Original file line number Diff line number Diff line change
@@ -1,17 +1,21 @@
class Api::V1::Users::PuzzlesController < ApplicationController
before_action :find_user

def index
user = User.find(params[:user_id])
render json: PuzzleSerializer.new(user.puzzles)
render json: PuzzleSerializer.new(@user.puzzles)
end

def show
user = User.find(params[:user_id])
puzzle = user.puzzles.find(params[:puzzle_id])
puzzle = @user.puzzles.find(params[:puzzle_id])
render json: PuzzleSerializer.new(puzzle)
end

def create
puzzle = @user.puzzles.new(puzzle_params)
render json: PuzzleSerializer.new(puzzle), status: 201 if puzzle.save
end

def update
User.find(params[:user_id])
puzzle = Puzzle.find(params[:puzzle_id])

puzzle.update(puzzle_params)
Expand All @@ -23,4 +27,8 @@ def update
def puzzle_params
params.permit(:status, :title, :description, :total_pieces, :notes, :puzzle_image_url) # did not include user_id
end

def find_user
@user = User.find(params[:user_id])
end
end
2 changes: 1 addition & 1 deletion config/credentials.yml.enc
Original file line number Diff line number Diff line change
@@ -1 +1 @@
IL4N8M95vrB/esDvIFD5VSPSd4WeSCFyWl8gIS0raJnDgaPfEf0e9t0mWKB5xeI01GrMczu0RACUHhYJezUimYqdsaKxURxQN+7EnvyLHF5OdAa+j4GFE+B/UoTk5hbozyd1zT4eD/D0zytev1cfzlaeI2ZNSS4uBK8oE4rX+G3c7rMY8Gz0wt3S62C6X1zzJMONP21qDmmdFWi5/75KUbNXwYNp4hxCjuV20Y/T512QkyT/DXA6oe47kKYZb8bxcAfax1kf7MAWFssUbjHfmQ5yyHS9/DgUMTiiQrrvoHK9D4JDoLP5WdBjkYvQ90Ei/kJFLk0mkxSXaGZqI8brZP3gjckgBT758XPPafa/ar9YELzLmFbjK+D058Sejpd+DrHYgq+I58pWuReCn1pgrnjR4kuUXVDbFfHp--1S5k6pYYWALfcPgC--Ks7JFZU4UIoPdcpUkX/BHg==
RsfZcGeY28P15m432K6wNTLzYLVZr3nvtd0zYo+mCW7/fmEFz1IKeQgeTvd9NEmPnIRnrDQJ0IGGC6rSLwSCeKbFUBJMsGsbbXLCUw8pbgL0Pm4dS5NPVAEaAlLkzai+DzYbvKA1qglMMi1wYSJlsN+Wh66uj6bMwbkrOey/sEYuNL0HDOay+uH45IUKPRh69HgBFQiFimXRxKxeygb5oU06m3fkqKNkJfKkYz89XIu6OxeToFO5DY/Qx0qohtn+RH2Sd+uet0XHXHos00EP8FAGH+f0/sDr3K1GxaYF5JH0u/M2faaHZkrvebZNsqR4P3QFz/zZWe79XPdFba9Y5hFsykBF3C0m8tfdhWe9ppyRtGXWoW0FmBgxFF+vG2FBi3WicbqmQyDFnOy+fuvk4l9bD9cv8hK9HjMeKazw3ISJoy7EvcjXOmaKWjFMWz3b9QYj8trekH20Z09LlTmWS7bIgSa45Ql+mGOmYqLW82tMI5fy70tXE6mEqYU=--2nrBAjQmfyodtPiG--I0EEp060JLqs5zabzyvndA==
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@

get '/users/:user_id/puzzles', to: 'users/puzzles#index'
get '/users/:user_id/puzzles/:puzzle_id', to: 'users/puzzles#show'
post '/users/:user_id/puzzles', to: 'users/puzzles#create'
patch '/users/:user_id/puzzles/:puzzle_id', to: 'users/puzzles#update'

post '/users/:user_id/loans', to: 'users/loans#create'
Expand Down
2 changes: 2 additions & 0 deletions spec/rails_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@
RSpec.configure do |config|
config.include FactoryBot::Syntax::Methods

config.fixture_path = "#{::Rails.root}/spec/fixtures"

# Remove this line if you're not using ActiveRecord or ActiveRecord fixtures
config.fixture_path = "#{::Rails.root}/spec/fixtures"

Expand Down
64 changes: 52 additions & 12 deletions spec/requests/api/v1/sessions_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
password: "PuzzleQueen1",
password_confirmation: "PuzzleQueen1",
email: "dpuzzler@myemail.com",
zip_code: 12_345,
phone_number: 5_550_009_999
zip_code: 12345,
phone_number: 5500009999
)

login_data = {
Expand All @@ -22,13 +22,38 @@
post '/api/v1/login', headers:, params: JSON.generate(login_data)

expect(response).to have_http_status(201)

parsed_data = JSON.parse(response.body, symbolize_names: true)
expect(session[:user_id]).to eq(user.id)
end
end

# context 'when NOT successful' do
# end
context 'when NOT successful' do
it 'cannot log in a user with an incorrect password' do
user = User.create(
full_name: "Diana Puzzler",
password: "PuzzleQueen1",
password_confirmation: "PuzzleQueen1",
email: "dpuzzler@myemail.com",
zip_code: 12_345,
phone_number: 5_550_009_999
)

login_data = {
email: "dpuzzler@myemail.com",
password: "Queen_of_Puzzles"
}

headers = { 'CONTENT_TYPE' => 'application/json' }
post '/api/v1/login', headers:, params: JSON.generate(login_data)

expect(response).to have_http_status(401)

parsed_error_data = JSON.parse(response.body, symbolize_names: true)

expect(parsed_error_data).to be_a(Hash)
expect(parsed_error_data.keys).to eq([:error])
expect(parsed_error_data[:error]).to eq("Invalid email or password")
end
end
end

describe '#destroy' do
Expand All @@ -41,18 +66,33 @@
post '/api/v1/login', headers:, params: JSON.generate(login_data)

expect(response).to have_http_status(201)
expect(session[:user_id]).to eq(user.id)

token = JSON.parse(response.body)['token']

delete '/api/v1/logout', headers: { 'Authorization' => "Bearer #{token}" }
delete '/api/v1/logout'

expect(response).to have_http_status(204)

expect(session[:user_id]).to be_nil
end
end

# context 'when NOT successful' do
# end
context 'when NOT successful' do
#Unsure how to test this:

# it 'cannot delete a user session of another user' do
# user = create(:user)
# login_data = { email: user.email, password: user.password }

# headers = { 'CONTENT_TYPE' => 'application/json' }
# post '/api/v1/login', headers:, params: JSON.generate(login_data)

# expect(response).to have_http_status(201)
# expect(session[:user_id]).to eq(user.id)

# delete '/api/v1/logout'

# expect(response).to have_http_status(???)
# expect(session[:user_id]).to eq(user.id)
# end
end
end
end
60 changes: 54 additions & 6 deletions spec/requests/api/v1/users/loans_request_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,16 @@
let(:user_2) { create(:user, id: 2) }
let(:puzzle_1) { create(:puzzle, user: user_1) }
let(:loan_1) { create(:loan, owner: user_1, borrower: user_2) }

context "when successful" do
it 'creates a new loan' do
user_1 = create(:user, id: 1)
user_2 = create(:user, id: 2)
puzzle_1 = create(:puzzle, user: user_1)

post "/api/v1/users/#{user_1.id}/loans", params: {
puzzle_id: puzzle_1.id,
borrower_id: loan_1.borrower.id
borrower_id: user_2.id
}

expect(response).to have_http_status(201)
Expand All @@ -24,15 +29,20 @@

expect(parsed_data[:data][:attributes]).to be_a(Hash)
expect(parsed_data[:data][:attributes].keys).to eq([:owner_id, :borrower_id, :puzzle_id, :status])
expect(parsed_data[:data][:attributes][:owner_id]).to eq(loan_1.owner_id)
expect(parsed_data[:data][:attributes][:borrower_id]).to eq(loan_1.borrower_id)
expect(parsed_data[:data][:attributes][:puzzle_id]).to eq(loan_1.puzzle_id)
expect(parsed_data[:data][:attributes][:status]).to eq(loan_1.status)
expect(parsed_data[:data][:attributes][:owner_id]).to eq(user_1.id)
expect(parsed_data[:data][:attributes][:borrower_id]).to eq(user_2.id)
expect(parsed_data[:data][:attributes][:puzzle_id]).to eq(puzzle_1.id)
expect(parsed_data[:data][:attributes][:status]).to eq("Pending")
end
end

context "when NOT successful" do
it 'creates an error message' do
it 'returns an error message if trying to make the same loan twice' do
user_1 = create(:user, id: 1)
user_2 = create(:user, id: 2)
puzzle_1 = create(:puzzle, user: user_1)

create(:loan, owner: user_1, borrower: user_2, puzzle: puzzle_1)
allow(Loan).to receive(:new).and_return(double(save: false))

post "/api/v1/users/#{user_1.id}/loans", params: {
Expand All @@ -48,6 +58,44 @@
expect(parsed_error_data.keys).to eq([:error])
expect(parsed_error_data[:error]).to eq("Unable to create loan")
end

it 'returns an error message if trying to make a loan when a Puzzle status is Pending' do
user_1 = create(:user, id: 1)
user_2 = create(:user, id: 2)
puzzle_1 = create(:puzzle, user: user_1, status: 1) #Puzzle status 1 = "Pending"

post "/api/v1/users/#{user_1.id}/loans", params: {
puzzle_id: puzzle_1.id,
borrower_id: user_2.id
}

expect(response).to have_http_status(422)

parsed_error_data = JSON.parse(response.body, symbolize_names: true)

expect(parsed_error_data).to be_a(Hash)
expect(parsed_error_data.keys).to eq([:error])
expect(parsed_error_data[:error]).to eq("Puzzle is not available for loan.")
end

it 'returns an error message if trying to make a loan when a Puzzle status is Not Available' do
user_1 = create(:user, id: 1)
user_2 = create(:user, id: 2)
puzzle_1 = create(:puzzle, user: user_1, status: 2) #Puzzle status 2 = "Not Available"

post "/api/v1/users/#{user_1.id}/loans", params: {
puzzle_id: puzzle_1.id,
borrower_id: user_2.id
}

expect(response).to have_http_status(422)

parsed_error_data = JSON.parse(response.body, symbolize_names: true)

expect(parsed_error_data).to be_a(Hash)
expect(parsed_error_data.keys).to eq([:error])
expect(parsed_error_data[:error]).to eq("Puzzle is not available for loan.")
end
end
end

Expand Down
Loading