archangel/archangel

View on GitHub
app/controllers/api/v1/collections/collection_entries_controller.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

# API
module Api
  # API v1
  module V1
    # Collection API v1
    module Collections
      # Collection Entries API v1
      class CollectionEntriesController < V1Controller
        include Toller
        include Controllers::Api::V1::PaginationConcern
        include Controllers::Api::V1::PaperTrailConcern

        before_action :parent_resource
        before_action :resource_collection, only: %i[index]
        before_action :resource_object, only: %i[show update destroy restore]
        before_action :resource_create_object, only: %i[create]
        before_action :resource_reposition_collection, only: %i[reposition]

        # All resources
        #
        # @todo Filter; include unpublished, include deleted, include Collection and Field info
        #
        # @example All resources
        #   GET /api/v1/collections/{slug}/entries
        #
        # @example All resources paginated
        #   GET /api/v1/collections/{slug}/entries?per=100
        #   GET /api/v1/collections/{slug}/entries?page=2&per=12
        def index; end

        # Show resource
        #
        # @todo Filter; include unpublished, include deleted, include Collection and Field info
        #
        # @example Show resource
        #   GET /api/v1/collections/{slug}/entries/{id}
        def show; end

        # Create resource
        #
        # @example Create resource
        #   POST /api/v1/collections/{slug}/entries
        def create
          respond_to do |format|
            if @collection_entry.save
              format.json { render :create, status: :created }
            else
              format.json { render json: json_unprocessable(@collection_entry), status: :unprocessable_entity }
            end
          end
        end

        # Update resource
        #
        # @example Update resource
        #   PUT /api/v1/collections/{slug}/entries/{id}
        def update
          respond_to do |format|
            if @collection_entry.update(resource_params)
              format.json { render :update, status: :accepted }
            else
              format.json { render json: json_unprocessable(@collection_entry), status: :unprocessable_entity }
            end
          end
        end

        # Delete or destroy resource
        #
        # When the resource has not been discarded (soft deleted), the record will be marked as discarded. When the
        # resource is already discarded, the record will be hard deleted
        #
        # @example Delete or destroy resource
        #   DELETE /api/v1/collections/{slug}/entries/{id}
        def destroy
          @collection_entry.discarded? ? @collection_entry.destroy : @collection_entry.discard

          respond_to do |format|
            format.json { head :no_content }
          end
        end

        # Reposition resource
        #
        # @example Reposition resource
        #   POST /api/v1/collections/{slug}/entries/reposition
        def reposition
          new_positions = params.fetch(:positions, [])
          positions = {}.tap do |option|
            new_positions.each.with_index { |id, index| option[id] = { position: index } }
          end

          @collection.collection_entries.update(positions.keys, positions.values)

          respond_to do |format|
            format.json { head :accepted }
          end
        end

        # Restore resource
        #
        # When a resource has been discarded (soft deleted), the record will be marked as undiscarded
        #
        # @example Restore resource
        #   POST /api/v1/collections/{slug}/entries/{id}/restore
        def restore
          @collection_entry.undiscard

          respond_to do |format|
            format.json { head :accepted }
          end
        end

        protected

        def parent_resource
          resource_id = params.fetch(:collection_id, nil)

          @collection = current_site.collections.find_by!(slug: resource_id)
        rescue ActiveRecord::RecordNotFound
          render json: json_not_found(controller_name), status: :not_found
        end

        def resource_collection
          @collection_entries = @collection.collection_entries.order(position: :asc).page(page_num).per(per_page)

          authorize :collection_entry
        end

        def resource_object
          resource_id = params.fetch(:id, '')

          @collection_entry = @collection.collection_entries.find_by!(id: resource_id)

          authorize :collection_entry
        rescue ActiveRecord::RecordNotFound
          render json: json_not_found(controller_name), status: :not_found
        end

        def resource_create_object
          entry_resource = @collection.collection_entries.new(nil)

          collection_field_key_map.each do |field|
            entry_resource.assign_attributes(field => resource_params.fetch(field, nil))
          end

          entry_resource[:published_at] = resource_params.fetch(:published_at, nil)

          @collection_entry = entry_resource

          authorize :collection_entry
        end

        def resource_reposition_collection
          @collection_entries = @collection.collection_entries.all

          authorize :collection_entry
        end

        def permitted_attributes
          fields = collection_field_key_map.map(&:to_sym)

          fields + %i[published_at]
        end

        def resource_params
          params.permit(permitted_attributes)
        end

        private

        def collection_field_key_map
          @collection.collection_fields.map(&:key)
        end
      end
    end
  end
end