ulmic/tramway-dev

View on GitHub
tramway-api/app/controllers/tramway/api/v1/application_controller.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

module Tramway
  module Api
    module V1
      class ApplicationController < ::Tramway::Api::ApplicationController
        def render_errors_for(model)
          render json: model, status: :unprocessable_entity, serializer: ::Tramway::Api::V1::ErrorSerializer
        end

        def render_error_with_text(text)
          render json: { text: text }, status: :bad_request
        end

        def snake_case(params)
          hash = {}
          params.each do |attribute, value|
            key = ::UUID.validate(attribute) ? attribute : attribute.to_s.gsub('-', '_')
            hash.merge! key => value
          end
          hash
        end

        private

        def record
          if params[:key].present?
            if Tramway::Api.other_id_methods_of(model: model_class).include? params[:key].to_sym
              @record = model_class.find_by! params[:key] => params[:id] if params[:id].present?
            end
          else
            default_id_method = Tramway::Api.default_id_method_of(model: model_class) || :uuid
            @record = model_class.find_by! default_id_method => params[:id] if params[:id].present?
          end
        end

        def records
          active_records = model_class.respond_to?(:active) ? model_class.active : model_class.all
          collection = active_records.order(id: :desc).send params[:scope] || :all
          collection = collection.page(params[:page]).per(params[:per]) if params[:page].present?
          collection = collection.full_text_search params[:search] if params[:search].present?
          collection
        end

        def check_available_model_class
          unless model_class
            head(:unauthorized) && return unless current_tramway_user

            head(:unprocessable_entity) && return
          end
        end

        def check_available_model_action_for_record
          action_is_available = check_action
          action_is_available.tap do
            if action_is_available.is_a?(Proc) && !action_is_available.call(record, current_tramway_user)
              head(:unprocessable_entity) && return
            end
          end
        end

        def available_action_for_collection
          action_is_available = check_action
          return records if action_is_available == true

          action_is_available.call records, current_tramway_user if action_is_available.is_a?(Proc)
        end

        def check_action
          action_is_available = checking_roles.map do |role|
            Tramway::Api.action_is_available(
              action: action_name.to_sym,
              project: (@application_engine || application_name),
              role: role,
              model_name: params[:model],
              current_user: current_tramway_user
            )
          end.compact.uniq - [false]

          if action_is_available.count > 1
            Tramway::Error.raise_error(:tramway, :api, :api, :v1, :records_controller, :available_action_for_collection, :duplicate_actions)
          end

          action_is_available = action_is_available.first

          action_is_available.tap do
            head(:unprocessable_entity) && return unless action_is_available
          end
        end

        def authenticate_user_if_needed
          action_is_open = Tramway::Api.action_is_available(
            action: action_name.to_sym,
            project: (@application_engine || application_name),
            model_name: params[:model]
          )
          head(:unauthorized) && return if !current_tramway_user && !action_is_open
        end

        def available_models_for_current_tramway_user
          checking_roles.reduce([]) do |models, role|
            models += ::Tramway::Api.available_models(role: role).map(&:to_s)
          end
        end

        def checking_roles
          [:open, current_tramway_user&.role].compact
        end

        protected

        def application_name
          @application ||= Tramway.application&.model_class&.first || Tramway.application
          begin
            @application.name
          rescue
            raise("Tramway::Api @application not initialized, Tramway.application: #{::Tramway.application}, model_class: #{Tramway.application&.model_class }")
          end
        end

        def model_class
          params[:model].constantize
        rescue ActiveSupport::Concern::MultipleIncludedBlocks => e
          raise "#{e}. Maybe #{params[:model]} model doesn't exists or there is naming conflicts with it"
        end

        def decorator_class(model_name = nil)
          "#{model_name || model_class}Decorator".constantize
        end

        def form_class(model_name = nil)
          "#{model_name || model_class}Form".constantize
        end

        def serializer_class(model_name = nil)
          "#{model_name || model_class}Serializer".constantize
        end
      end
    end
  end
end