Aspects API Endpoint complete with full tests

This commit is contained in:
Hank Grabowski 2018-11-08 15:22:15 -05:00
parent 6924781bb0
commit 97af2441ee
6 changed files with 414 additions and 4 deletions

View file

@ -0,0 +1,72 @@
# frozen_string_literal: true
module Api
module V1
class AspectsController < Api::V1::BaseController
before_action only: %i[index show] do
require_access_token %w[read]
end
before_action only: %i[create update destroy] do
require_access_token %w[read write]
end
def index
aspects = current_user.aspects.map {|a| AspectPresenter.new(a).as_api_json(false) }
render json: aspects
end
def show
aspect = current_user.aspects.where(id: params[:id]).first
if aspect
render json: AspectPresenter.new(aspect).as_api_json(true)
else
render json: I18n.t("api.endpoint_errors.aspects.not_found"), status: :not_found
end
end
def create
params.require(%i[name chat_enabled])
aspect = current_user.aspects.build(name: params[:name], chat_enabled: params[:chat_enabled])
if aspect&.save
render json: AspectPresenter.new(aspect).as_api_json(true)
else
render json: I18n.t("api.endpoint_errors.aspects.cant_create"), status: :unprocessable_entity
end
rescue ActionController::ParameterMissing
render json: I18n.t("api.endpoint_errors.aspects.cant_create"), status: :unprocessable_entity
end
def update
aspect = current_user.aspects.where(id: params[:id]).first
if !aspect
render json: I18n.t("api.endpoint_errors.aspects.cant_update"), status: :not_found
elsif aspect.update!(aspect_params(true))
render json: AspectPresenter.new(aspect).as_api_json(true)
else
render json: I18n.t("api.endpoint_errors.aspects.cant_update"), status: :unprocessable_entity
end
rescue ActionController::ParameterMissing, ActiveRecord::RecordInvalid
render json: I18n.t("api.endpoint_errors.aspects.cant_update"), status: :unprocessable_entity
end
def destroy
aspect = current_user.aspects.where(id: params[:id]).first
if aspect&.destroy
head :no_content
else
render json: I18n.t("api.endpoint_errors.aspects.cant_delete"), status: :unprocessable_entity
end
end
private
def aspect_params(allow_order=false)
parameters = params.permit(:name, :chat_enabled)
parameters[:order_id] = params[:order] if params.has_key?(:order) && allow_order
parameters
end
end
end
end

View file

@ -11,7 +11,18 @@ class AspectPresenter < BasePresenter
}
end
def to_json(options = {})
def as_api_json(full=false)
values = {
id: @aspect.id,
name: @aspect.name,
order: @aspect.order_id
}
values[:chat_enabled] = @aspect.chat_enabled if full
values
end
def to_json(options={})
as_json.to_json(options)
end
end
end

View file

@ -951,6 +951,11 @@ en:
login_required: "You must first login before you can authorize this application"
could_not_authorize: "The application could not be authorized"
endpoint_errors:
aspects:
cant_create: "Failed to create the aspect"
cant_delete: "Failed to delete the aspect"
cant_update: "Failed to update the aspect"
not_found: "Aspect with provided ID could not be found"
conversations:
not_found: "Conversation with provided guid could not be found"
cant_process: "Couldnt accept or process the conversation"

View file

@ -222,6 +222,7 @@ Rails.application.routes.draw do
get "podmin", to: "home#podmin"
api_version(module: "Api::V1", path: {value: "api/v1"}) do
resources :aspects, only: %i[show index create destroy update]
resources :posts, only: %i[show create destroy] do
resources :comments, only: %i[create index destroy] do
post "report" => "comments#report"
@ -232,6 +233,7 @@ Rails.application.routes.draw do
resources :conversations, only: %i[show index create destroy] do
resources :messages, only: %i[index create]
end
get "streams/activity" => "streams#activity", :as => "activity_stream"
get "streams/main" => "streams#multi", :as => "stream"
get "streams/tags" => "streams#followed_tags", :as => "followed_tags_stream"

View file

@ -0,0 +1,302 @@
# frozen_sTring_literal: true
require "spec_helper"
describe Api::V1::AspectsController do
let(:auth) { FactoryGirl.create(:auth_with_read_and_write) }
let(:auth_read_only) { FactoryGirl.create(:auth_with_read) }
let!(:access_token) { auth.create_access_token.to_s }
let!(:access_token_read_only) { auth_read_only.create_access_token.to_s }
before do
@aspect1 = auth.user.aspects.where(name: "generic").first
@aspect2 = auth.user.aspects.create(name: "another aspect")
end
describe "#index" do
it "returns list of aspects" do
get(
api_v1_aspects_path,
params: {access_token: access_token}
)
expect(response.status).to eq(200)
aspects = JSON.parse(response.body)
expect(aspects.length).to eq(auth.user.aspects.length)
aspects.each do |aspect|
found_aspect = auth.user.aspects.find_by(id: aspect["id"])
expect(aspect["name"]).to eq(found_aspect.name)
expect(aspect["order"]).to eq(found_aspect.order_id)
end
end
it "fails if invalid token" do
get(
api_v1_aspects_path,
params: {access_token: "999_999_999"}
)
expect(response.status).to eq(401)
end
end
describe "#show" do
context "with correct id" do
it "returns aspect" do
get(
api_v1_aspect_path(@aspect2.id),
params: {access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["id"]).to eq(@aspect2.id)
expect(aspect["name"]).to eq(@aspect2.name)
expect(aspect["order"]).to eq(@aspect2.order_id)
expect(aspect["chat_enabled"]).to eq(@aspect2.chat_enabled)
end
end
context "with incorrect id" do
it "fails to return with error" do
get(
api_v1_aspect_path("-1"),
params: {access_token: access_token}
)
expect(response.status).to eq(404)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.not_found"))
end
end
context "when not logged in" do
it "fails to return with error" do
get(
api_v1_aspect_path(@aspect2.id),
params: {access_token: "999_999_999"}
)
expect(response.status).to eq(401)
end
end
end
describe "#create" do
context "with full aspect settings" do
it "creates aspect" do
new_name = "diaspora developers"
post(
api_v1_aspects_path,
params: {name: new_name, chat_enabled: true, access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["name"]).to eq(new_name)
expect(aspect["chat_enabled"]).to be_truthy
expect(aspect.has_key?("id")).to be_truthy
expect(aspect.has_key?("order")).to be_truthy
end
it "fails to create duplicate aspect" do
post(
api_v1_aspects_path,
params: {name: @aspect1.name, chat_enabled: true, access_token: access_token}
)
expect(response.status).to eq(422)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_create"))
end
end
context "with malformed settings" do
it "fails when missing name" do
post(
api_v1_aspects_path,
params: {chat_enabled: true, access_token: access_token}
)
expect(response.status).to eq(422)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_create"))
end
it "fails when missing chat" do
post(
api_v1_aspects_path,
params: {name: "new_aspect", access_token: access_token}
)
expect(response.status).to eq(422)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_create"))
end
end
context "improper credentials" do
it "fails when not logged in" do
post(
api_v1_aspects_path,
params: {name: "new_name", chat_enabled: true, access_token: "999_999_999"}
)
expect(response.status).to eq(401)
end
it "fails when logged in read only" do
post(
api_v1_aspects_path,
params: {name: "new_name", chat_enabled: true, access_token: access_token_read_only}
)
expect(response.status).to eq(403)
end
end
end
describe "#update" do
context "with aspect settings" do
it "updates full aspect" do
new_name = "NewAspectName"
new_chat = @aspect2.chat_enabled
order = @aspect2.order_id + 1
patch(
api_v1_aspect_path(@aspect2.id),
params: {name: new_name, chat_enabled: new_chat, order: order, access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["name"]).to eq(new_name)
expect(aspect["chat_enabled"]).to eq(new_chat)
expect(aspect["order"]).to eq(order)
expect(aspect["id"]).to eq(@aspect2.id)
end
it "updates name only aspect" do
new_name = "NewAspectName"
patch(
api_v1_aspect_path(@aspect2.id),
params: {name: new_name, access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["name"]).to eq(new_name)
expect(aspect["id"]).to eq(@aspect2.id)
end
it "updates chat only" do
new_chat = @aspect2.chat_enabled
patch(
api_v1_aspect_path(@aspect2.id),
params: {chat_enabled: new_chat, access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["chat_enabled"]).to eq(new_chat)
expect(aspect["id"]).to eq(@aspect2.id)
end
it "updates order only" do
order = @aspect2.order_id + 1
patch(
api_v1_aspect_path(@aspect2.id),
params: {order: order, access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["order"]).to eq(order)
expect(aspect["id"]).to eq(@aspect2.id)
end
it "succeds with no arguments" do
patch(
api_v1_aspect_path(@aspect2.id),
params: {access_token: access_token}
)
expect(response.status).to eq(200)
aspect = JSON.parse(response.body)
expect(aspect["name"]).to eq(@aspect2.name)
expect(aspect["chat_enabled"]).to eq(@aspect2.chat_enabled)
expect(aspect["id"]).to eq(@aspect2.id)
end
end
context "with bad parameters" do
it "fails with reused name" do
patch(
api_v1_aspect_path(@aspect2.id),
params: {name: @aspect1.name, access_token: access_token}
)
expect(response.status).to eq(422)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_update"))
end
it "fails with bad id" do
patch(
api_v1_aspect_path("-1"),
params: {name: "NewAspectName", access_token: access_token}
)
expect(response.status).to eq(404)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_update"))
end
end
context "improper credentials" do
it "fails when not logged in" do
patch(
api_v1_aspect_path(@aspect2.id),
params: {access_token: "999_999_999"}
)
expect(response.status).to eq(401)
end
it "fails when logged in read only" do
patch(
api_v1_aspect_path(@aspect2.id),
params: {access_token: access_token_read_only}
)
expect(response.status).to eq(403)
end
end
end
describe "#delete" do
context "with correct ID" do
it "deletes aspect" do
delete(
api_v1_aspect_path(@aspect2.id),
params: {access_token: access_token}
)
expect(response.status).to eq(204)
end
end
context "with bad ID" do
it "fails to delete with error" do
delete(
api_v1_aspect_path("-1"),
params: {access_token: access_token}
)
expect(response.status).to eq(422)
expect(response.body).to eq(I18n.t("api.endpoint_errors.aspects.cant_delete"))
end
end
context "improper credentials" do
it "fails when not logged in" do
delete(
api_v1_aspect_path(@aspect2.id),
params: {access_token: "999_999_999"}
)
expect(response.status).to eq(401)
end
it "fails when logged in read only" do
delete(
api_v1_aspect_path(@aspect2.id),
params: {access_token: access_token_read_only}
)
expect(response.status).to eq(403)
end
end
end
end

View file

@ -2,7 +2,8 @@
describe AspectPresenter do
before do
@presenter = AspectPresenter.new(bob.aspects.first)
@aspect = bob.aspects.first
@presenter = AspectPresenter.new(@aspect)
end
describe '#to_json' do
@ -10,4 +11,21 @@ describe AspectPresenter do
expect(@presenter.to_json).to be_present
end
end
end
describe "#to_api_json" do
it "creates simple JSON" do
aspect_json = @presenter.as_api_json(false)
expect(aspect_json[:id]).to eq(@aspect.id)
expect(aspect_json[:name]).to eq(@aspect.name)
expect(aspect_json[:order]).to eq(@aspect.order_id)
end
it "produces full JSON" do
aspect_json = @presenter.as_api_json(true)
expect(aspect_json[:id]).to eq(@aspect.id)
expect(aspect_json[:name]).to eq(@aspect.name)
expect(aspect_json[:order]).to eq(@aspect.order_id)
expect(aspect_json[:chat_enabled]).to eq(@aspect.chat_enabled)
end
end
end