Merge pull request 'Update format of guests API and document endpoints' (#130) from guests-api-changes into main
Reviewed-on: #130
This commit is contained in:
		
						commit
						d73f59b05c
					
				@ -1,15 +1,43 @@
 | 
				
			|||||||
# Copyright (C) 2024 Manuel Bustillo
 | 
					# Copyright (C) 2024 Manuel Bustillo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class ApplicationController < ActionController::Base
 | 
					class ApplicationController < ActionController::Base
 | 
				
			||||||
    after_action :set_csrf_cookie
 | 
					  after_action :set_csrf_cookie
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private
 | 
					  skip_before_action :verify_authenticity_token, if: :development_swagger?
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    def set_csrf_cookie
 | 
					  rescue_from ActiveRecord::RecordInvalid do |exception|
 | 
				
			||||||
      cookies["csrf-token"] = {
 | 
					    render json: {
 | 
				
			||||||
        value: form_authenticity_token,
 | 
					      message: 'Record invalid',
 | 
				
			||||||
        secure: Rails.env.production?,
 | 
					      errors: exception.record.errors.full_messages
 | 
				
			||||||
        same_site: :strict,
 | 
					    }, status: :unprocessable_entity
 | 
				
			||||||
      }
 | 
					  end
 | 
				
			||||||
    end
 | 
					
 | 
				
			||||||
 | 
					  rescue_from ActionController::ParameterMissing do |exception|
 | 
				
			||||||
 | 
					    render json: {
 | 
				
			||||||
 | 
					      message: 'Parameter missing',
 | 
				
			||||||
 | 
					      errors: [exception.message]
 | 
				
			||||||
 | 
					    }, status: :bad_request
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  rescue_from ActiveRecord::RecordNotFound do |exception|
 | 
				
			||||||
 | 
					    render json: {
 | 
				
			||||||
 | 
					      message: 'Record not found',
 | 
				
			||||||
 | 
					      errors: [exception.message]
 | 
				
			||||||
 | 
					    }, status: :not_found
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def development_swagger?
 | 
				
			||||||
 | 
					    Rails.env.test? ||
 | 
				
			||||||
 | 
					    Rails.env.development? && request.headers['referer'].include?('/api-docs/index.html')
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def set_csrf_cookie
 | 
				
			||||||
 | 
					    cookies['csrf-token'] = {
 | 
				
			||||||
 | 
					      value: form_authenticity_token,
 | 
				
			||||||
 | 
					      secure: Rails.env.production?,
 | 
				
			||||||
 | 
					      same_site: :strict
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -4,15 +4,14 @@ require 'csv'
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
class GuestsController < ApplicationController
 | 
					class GuestsController < ApplicationController
 | 
				
			||||||
  def index
 | 
					  def index
 | 
				
			||||||
    @guests = Guest.all.includes(:group)
 | 
					    render json: Guest.all.includes(:group)
 | 
				
			||||||
                   .joins(:group)
 | 
					                      .joins(:group)
 | 
				
			||||||
                   .order('groups.name' => :asc, name: :asc)
 | 
					                      .order('groups.name' => :asc, name: :asc)
 | 
				
			||||||
 | 
					                      .as_json(only: %i[id name status], include: { group: { only: %i[id name] } })
 | 
				
			||||||
    render jsonapi: @guests
 | 
					 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  def update
 | 
					  def update
 | 
				
			||||||
    Guests::UpdateUseCase.new(guest_ids: [params[:id]], params: params.require(:guest).permit(:name)).call
 | 
					    Guest.find(params[:id]).update!(params.require(:guest).permit(:name))
 | 
				
			||||||
    render json: {}, status: :ok
 | 
					    render json: {}, status: :ok
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -29,7 +29,9 @@ class Guest < ApplicationRecord
 | 
				
			|||||||
    confirmed: 20,
 | 
					    confirmed: 20,
 | 
				
			||||||
    declined: 30,
 | 
					    declined: 30,
 | 
				
			||||||
    tentative: 40
 | 
					    tentative: 40
 | 
				
			||||||
  }
 | 
					  }, validate: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  validates :name, presence: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  scope :potential, -> { where.not(status: %i[declined considered]) }
 | 
					  scope :potential, -> { where.not(status: %i[declined considered]) }
 | 
				
			||||||
end
 | 
					end
 | 
				
			||||||
 | 
				
			|||||||
@ -3,14 +3,17 @@
 | 
				
			|||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.describe Guest, type: :model do
 | 
					RSpec.describe Guest, type: :model do
 | 
				
			||||||
  it do
 | 
					  describe 'validations' do
 | 
				
			||||||
    should define_enum_for(:status).with_values(
 | 
					    it { should validate_presence_of(:name) }
 | 
				
			||||||
      considered: 0,
 | 
					    it do
 | 
				
			||||||
      invited: 10,
 | 
					      should define_enum_for(:status).with_values(
 | 
				
			||||||
      confirmed: 20,
 | 
					        considered: 0,
 | 
				
			||||||
      declined: 30,
 | 
					        invited: 10,
 | 
				
			||||||
      tentative: 40
 | 
					        confirmed: 20,
 | 
				
			||||||
    )
 | 
					        declined: 30,
 | 
				
			||||||
 | 
					        tentative: 40
 | 
				
			||||||
 | 
					      )
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it { should belong_to(:group) }
 | 
					  it { should belong_to(:group) }
 | 
				
			||||||
 | 
				
			|||||||
@ -5,6 +5,7 @@ require 'swagger_helper'
 | 
				
			|||||||
RSpec.describe 'groups', type: :request do
 | 
					RSpec.describe 'groups', type: :request do
 | 
				
			||||||
  path '/groups' do
 | 
					  path '/groups' do
 | 
				
			||||||
    get('list groups') do
 | 
					    get('list groups') do
 | 
				
			||||||
 | 
					      tags 'Groups'
 | 
				
			||||||
      produces 'application/json'
 | 
					      produces 'application/json'
 | 
				
			||||||
      response(200, 'successful') do
 | 
					      response(200, 'successful') do
 | 
				
			||||||
        schema type: :array,
 | 
					        schema type: :array,
 | 
				
			||||||
@ -25,7 +26,7 @@ RSpec.describe 'groups', type: :request do
 | 
				
			|||||||
                   tentative: { type: :integer, minimum: 0 }
 | 
					                   tentative: { type: :integer, minimum: 0 }
 | 
				
			||||||
                 }
 | 
					                 }
 | 
				
			||||||
               }
 | 
					               }
 | 
				
			||||||
        run_test!
 | 
					        xit
 | 
				
			||||||
      end
 | 
					      end
 | 
				
			||||||
    end
 | 
					    end
 | 
				
			||||||
  end
 | 
					  end
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										89
									
								
								spec/requests/guests_spec.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										89
									
								
								spec/requests/guests_spec.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,89 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2024 Manuel Bustillo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					require 'swagger_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RSpec.describe 'guests', type: :request do
 | 
				
			||||||
 | 
					  path '/guests/bulk_update' do
 | 
				
			||||||
 | 
					    post('Update multiple guests in a single request') do
 | 
				
			||||||
 | 
					      tags 'Guests'
 | 
				
			||||||
 | 
					      consumes 'application/json'
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      parameter name: :body, in: :body, schema: {
 | 
				
			||||||
 | 
					        type: :object,
 | 
				
			||||||
 | 
					        required: %i[guest_ids properties],
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          guest_ids: { type: :array, items: { type: :string, format: :uuid } },
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            type: :object,
 | 
				
			||||||
 | 
					            required: %i[status],
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              status: { type: :string, enum: Guest.statuses.keys }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      let(:body) do
 | 
				
			||||||
 | 
					        {
 | 
				
			||||||
 | 
					          guest_ids: [SecureRandom.uuid, SecureRandom.uuid],
 | 
				
			||||||
 | 
					          properties: {
 | 
				
			||||||
 | 
					            status: 'confirmed'
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					      response_empty_200
 | 
				
			||||||
 | 
					      response_422
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path '/guests' do
 | 
				
			||||||
 | 
					    get('list guests') do
 | 
				
			||||||
 | 
					      tags 'Guests'
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      response(200, 'successful') do
 | 
				
			||||||
 | 
					        schema type: :array,
 | 
				
			||||||
 | 
					               items: {
 | 
				
			||||||
 | 
					                 type: :object,
 | 
				
			||||||
 | 
					                 required: %i[id name status group],
 | 
				
			||||||
 | 
					                 properties: {
 | 
				
			||||||
 | 
					                   id: { type: :string, format: :uuid },
 | 
				
			||||||
 | 
					                   name: { type: :string },
 | 
				
			||||||
 | 
					                   status: { type: :string, enum: Guest.statuses.keys },
 | 
				
			||||||
 | 
					                   group: { type: :object,
 | 
				
			||||||
 | 
					                            required: %i[id name],
 | 
				
			||||||
 | 
					                            properties: {
 | 
				
			||||||
 | 
					                              id: { type: :string, format: :uuid },
 | 
				
			||||||
 | 
					                              name: { type: :string }
 | 
				
			||||||
 | 
					                            } }
 | 
				
			||||||
 | 
					                 }
 | 
				
			||||||
 | 
					               }
 | 
				
			||||||
 | 
					        xit
 | 
				
			||||||
 | 
					      end
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  path '/guests/{id}' do
 | 
				
			||||||
 | 
					    patch('update guest') do
 | 
				
			||||||
 | 
					      tags 'Guests'
 | 
				
			||||||
 | 
					      consumes 'application/json'
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      parameter name: 'id', in: :path, type: :string, format: :uuid
 | 
				
			||||||
 | 
					      parameter name: :body, in: :body, schema: {
 | 
				
			||||||
 | 
					        type: :object,
 | 
				
			||||||
 | 
					        required: %i[guest],
 | 
				
			||||||
 | 
					        properties: {
 | 
				
			||||||
 | 
					          guest: {
 | 
				
			||||||
 | 
					            type: :object,
 | 
				
			||||||
 | 
					            required: %i[name],
 | 
				
			||||||
 | 
					            properties: {
 | 
				
			||||||
 | 
					              name: { type: :string }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      response_empty_200
 | 
				
			||||||
 | 
					      response_422
 | 
				
			||||||
 | 
					      response_404
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
@ -3,6 +3,9 @@
 | 
				
			|||||||
# frozen_string_literal: true
 | 
					# frozen_string_literal: true
 | 
				
			||||||
 | 
					
 | 
				
			||||||
require 'rails_helper'
 | 
					require 'rails_helper'
 | 
				
			||||||
 | 
					require_relative './swagger_response_helper'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					include SwaggerResponseHelper
 | 
				
			||||||
 | 
					
 | 
				
			||||||
RSpec.configure do |config|
 | 
					RSpec.configure do |config|
 | 
				
			||||||
  # Specify a root folder where Swagger JSON files are generated
 | 
					  # Specify a root folder where Swagger JSON files are generated
 | 
				
			||||||
@ -19,6 +22,15 @@ RSpec.configure do |config|
 | 
				
			|||||||
  config.openapi_specs = {
 | 
					  config.openapi_specs = {
 | 
				
			||||||
    'v1/swagger.yaml' => {
 | 
					    'v1/swagger.yaml' => {
 | 
				
			||||||
      openapi: '3.0.1',
 | 
					      openapi: '3.0.1',
 | 
				
			||||||
 | 
					      components: {
 | 
				
			||||||
 | 
					        securitySchemes: {
 | 
				
			||||||
 | 
					          csrfToken: {
 | 
				
			||||||
 | 
					            type: :apiKey,
 | 
				
			||||||
 | 
					            in: :header,
 | 
				
			||||||
 | 
					            name: 'X-CSRF-Token'
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
      info: {
 | 
					      info: {
 | 
				
			||||||
        title: 'API V1',
 | 
					        title: 'API V1',
 | 
				
			||||||
        version: 'v1'
 | 
					        version: 'v1'
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										38
									
								
								spec/swagger_response_helper.rb
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								spec/swagger_response_helper.rb
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
				
			|||||||
 | 
					# Copyright (C) 2024 Manuel Bustillo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module SwaggerResponseHelper
 | 
				
			||||||
 | 
					  def response_422
 | 
				
			||||||
 | 
					    response(422, 'Validation errors in input parameters') do
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      error_schema
 | 
				
			||||||
 | 
					      xit
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def response_empty_200
 | 
				
			||||||
 | 
					    response(200, 'Success') do
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      schema type: :object
 | 
				
			||||||
 | 
					      xit
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def response_404
 | 
				
			||||||
 | 
					    response(404, 'Record not found') do
 | 
				
			||||||
 | 
					      produces 'application/json'
 | 
				
			||||||
 | 
					      error_schema
 | 
				
			||||||
 | 
					      xit
 | 
				
			||||||
 | 
					    end
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  def error_schema
 | 
				
			||||||
 | 
					    schema type: :object,
 | 
				
			||||||
 | 
					           required: %i[message errors],
 | 
				
			||||||
 | 
					           properties: {
 | 
				
			||||||
 | 
					             message: { type: :string },
 | 
				
			||||||
 | 
					             errors: { type: :array, items: { type: :string } }
 | 
				
			||||||
 | 
					           }
 | 
				
			||||||
 | 
					  end
 | 
				
			||||||
 | 
					end
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user