Skip to content

Commit

Permalink
Merge pull request #52 from WWC-Hackathon-2023/image_upload
Browse files Browse the repository at this point in the history
BE | Create `UserPuzzles#create` & Update `UserLoans#create` Endpoints
  • Loading branch information
kem247 authored Oct 22, 2023
2 parents b1f1330 + ca8af1c commit 38bed36
Show file tree
Hide file tree
Showing 11 changed files with 211 additions and 36 deletions.
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

0 comments on commit 38bed36

Please sign in to comment.