Skip to content

Commit

Permalink
Merge pull request #61 from turingschool/feat/contact-serializer-cc-rm
Browse files Browse the repository at this point in the history
Add Support for Creating Contacts with Optional Company Information
  • Loading branch information
Sgalvin36 authored Dec 19, 2024
2 parents f98455a + d7e905a commit 229f453
Show file tree
Hide file tree
Showing 6 changed files with 131 additions and 26 deletions.
41 changes: 40 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ Successful response for users without saved contacts:
```

#### Create a contact with required and optional fields.
New contacts require a unique first and last name. All other fields are optional.
***New contacts require a unique first and last name. All other fields are optional.***

Request:
```
Expand Down Expand Up @@ -644,6 +644,45 @@ Status: 201 created
}
```
#### Create a contact with a company name from the dropdown box
***New contacts with company name require a unique first and last name, and company ID in the URI. All other fields are optional.***

Request:
```
POST api/v1/users/:user_id/companies/:company_id/contacts
Authorization: Bearer Token - put in token for user
raw json body with all fields:
{
"data": [
{
"id": "1",
"type": "contacts",
"attributes": {
"first_name": "Jane",
"last_name": "Doe",
"company_id": 2,
"email": "",
"phone_number": "",
"notes": "",
"user_id": 2,
"company": {
"id": 2,
"name": "Future Designs LLC",
"website": "https://futuredesigns.com",
"street_address": "456 Future Blvd",
"city": "Austin",
"state": "TX",
"zip_code": "73301",
"notes": "Submitted application for the UI Designer role."
}
}
}
]
},
```

#### Contact Errors
401 Error Response if no token provided:
Expand Down
42 changes: 20 additions & 22 deletions app/controllers/api/v1/contacts_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,33 +26,31 @@ def index
end
end

def show
company = @current_user.companies.find_by(id: params[:id])
authorize company

if company
contacts = company.contacts
render json: { company: CompanySerializer.new(company), contacts: ContactSerializer.new(contacts) }
def create
authorize Contact
if params[:company_id]
company = @current_user.companies.find_by(id: params[:company_id])
if company
contact = company.contacts.new(contact_params.merge(user_id: @current_user.id))
else
return render json: { error: "Company not found" }, status: :not_found
end
else
render json: { error: "Company not found or unauthorized access" }, status: :not_found
contact = @current_user.contacts.new(contact_params)
end

if contact.save
render json: ContactsSerializer.new(contact), status: :created
else
render json: { error: contact.errors.full_messages.to_sentence }, status: :unprocessable_entity
end
end

def create
authorize Contact
contact = @current_user.contacts.new(contact_params)
if contact.save
render json: ContactsSerializer.new(contact), status: :created
else
render json: { error: contact.errors.full_messages.to_sentence }, status: :unprocessable_entity
end
end
private

private

def contact_params
params.require(:contact).permit(:first_name, :last_name, :company_id, :email, :phone_number, :notes)
end
def contact_params
params.require(:contact).permit(:first_name, :last_name, :company_id, :email, :phone_number, :notes)
end
end
end
end
18 changes: 18 additions & 0 deletions app/serializers/contacts_serializer.rb
Original file line number Diff line number Diff line change
@@ -1,4 +1,22 @@
class ContactsSerializer
include JSONAPI::Serializer
attributes :first_name, :last_name, :company_id, :email, :phone_number, :notes, :user_id

attribute :company do |object|
company = object.company
if company
{
id: company.id,
name: company.name,
website: company.website,
street_address: company.street_address,
city: company.city,
state: company.state,
zip_code: company.zip_code,
notes: company.notes
}
else
nil
end
end
end
8 changes: 5 additions & 3 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,17 @@
namespace :api do
namespace :v1 do
resources :users, only: [:create, :index, :show, :update] do
resources :contacts, only: [:create, :index]

resources :job_applications, only: [:create, :index, :show]
resources :companies, only: [:create, :index, :show] do
resources :contacts, only: [:index]
resources :companies, only: [:create, :index] do
resources :contacts, only: [:create, :index]
end
resources :contacts, only: [:index, :create]
resource :dashboard, only: :show
end

resources :sessions, only: :create
end
end
end

22 changes: 22 additions & 0 deletions spec/requests/api/v1/contacts/create_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,18 @@
expect(json[:attributes][:last_name]).to eq("Smith")
expect(json[:attributes][:phone_number]).to eq("123-555-6789")
end

it 'creates a contact when given the company ID, returns a 201' do
minimal_params = { contact: {first_name: "John", last_name: "Smith" } }
post api_v1_user_company_contacts_path(user_id: @user1.id, company_id: @company.id), params: minimal_params , headers: { "Authorization" => "Bearer #{@token}" }, as: :json

expect(response).to have_http_status(:created)
json = JSON.parse(response.body, symbolize_names: true)[:data]

expect(json[:attributes][:first_name]).to eq("John")
expect(json[:attributes][:last_name]).to eq("Smith")
expect(json[:attributes][:company][:name]).to eq("Turing")
end
end

context "when the request is invalid - Sad Paths" do
Expand Down Expand Up @@ -154,6 +166,16 @@
json = JSON.parse(response.body, symbolize_names: true)
expect(json[:error]).to eq("Phone number must be in the format '555-555-5555'")
end

it 'returns a 404 error when a company is not found by ID number' do
minimal_params = { contact: {first_name: "John", last_name: "Smith" } }
post api_v1_user_company_contacts_path(user_id: @user1.id, company_id: 99999), params: minimal_params , headers: { "Authorization" => "Bearer #{@token}" }, as: :json

expect(response).to have_http_status(:not_found)
json = JSON.parse(response.body, symbolize_names: true)

expect(json[:error]).to eq("Company not found")
end
end

context "edge cases - Sad Paths" do
Expand Down
26 changes: 26 additions & 0 deletions spec/requests/api/v1/contacts/index_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,11 +40,27 @@
expect(json[:data]).to eq([])
expect(json[:message]).to eq("No contacts found")
end

it "should return 200 and all contacts associated with a company" do
get api_v1_user_company_contacts_path(user_id: @user.id, company_id: @company.id), headers: { "Authorization" => "Bearer #{@token}" }, as: :json

expect(response).to be_successful
expect(response).to have_http_status(:ok)
json = JSON.parse(response.body, symbolize_names: true)

expect(json[:company][:data][:attributes][:name]).to eq("Turing")
expect(json[:contacts][:data][0][:attributes][:last_name]).to eq("Smith")

end
end

context "Sad Paths" do
before(:each) do
@user = User.create!(name: "Me", email: "its_me", password: "reallyGoodPass")
@company = Company.create!(name: "Turing", website: "www.turing.com", street_address: "123 Main St", city: "Denver", state: "CO", zip_code: "80218", user_id: @user.id)
user_params = { email: "its_me", password: "reallyGoodPass" }
post api_v1_sessions_path, params: user_params, as: :json
@token = JSON.parse(response.body)["token"]
end

it "returns a 403 and an error message if no token is provided" do
Expand Down Expand Up @@ -76,6 +92,16 @@

expect(json[:error]).to eq("Not authenticated")
end

it "returns a 404 and an error message if company ID is not found" do
get api_v1_user_company_contacts_path(user_id: @user.id, company_id: 99999), headers: { "Authorization" => "Bearer #{@token}" }, as: :json

expect(response).to_not be_successful
expect(response).to have_http_status(:not_found)
json = JSON.parse(response.body, symbolize_names: true)

expect(json[:error]).to eq("Company not found or unauthorized access")
end
end
end
end

0 comments on commit 229f453

Please sign in to comment.