<commit_before>require 'pundit'

module JSONAPI
  module Authorization
    class PunditOperationsProcessor < ::ActiveRecordOperationsProcessor
      set_callback :find_operation, :before, :authorize_find
      set_callback :show_operation, :before, :authorize_show
      set_callback :show_related_resource_operation, :before, :authorize_show_related_resource
      set_callback :show_related_resources_operation, :before, :authorize_show_related_resources
      set_callback :create_resource_operation, :before, :authorize_create_resource
      set_callback :remove_resource_operation, :before, :authorize_remove_resource
      set_callback :replace_fields_operation, :before, :authorize_replace_fields

      def authorize_find
        ::Pundit.authorize(pundit_user, @operation.resource_klass._model_class, 'index?')
      end

      def authorize_show
        record = @operation.resource_klass.find_by_key(
          operation_resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, record, 'show?')
      end

      def authorize_show_related_resource
        source_resource = @operation.source_klass.find_by_key(
          @operation.source_id,
          context: operation_context
        )
        source_record = source_resource._model
        ::Pundit.authorize(pundit_user, source_record, 'show?')

        related_resource = source_resource.public_send(@operation.relationship_type)
        if related_resource.present?
          related_record = related_resource._model
          ::Pundit.authorize(pundit_user, related_record, 'show?')
        end
      end

      def authorize_show_related_resources
        source_record = @operation.source_klass.find_by_key(
          @operation.source_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, source_record, 'show?')
      end

      def authorize_replace_fields
        source_record = @operation.resource_klass.find_by_key(
          @operation.resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, source_record, 'update?')

        related_models.each do |rel_model|
          ::Pundit.authorize(pundit_user, rel_model, 'update?')
        end
      end

      def authorize_create_resource
        ::Pundit.authorize(pundit_user, @operation.resource_klass._model_class, 'create?')

        related_models.each do |rel_model|
          ::Pundit.authorize(pundit_user, rel_model, 'update?')
        end
      end

      def authorize_remove_resource
        record = @operation.resource_klass.find_by_key(
          operation_resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, record, 'destroy?')
      end

      private

      def pundit_user
        operation_context[:user]
      end

      # TODO: Communicate with upstream to fix this nasty hack
      def operation_context
        case @operation
        when JSONAPI::ShowRelatedResourcesOperation
          @operation.instance_variable_get('@options')[:context]
        else
          @operation.options[:context]
        end
      end

      # TODO: Communicate with upstream to fix this nasty hack
      def operation_resource_id
        case @operation
        when JSONAPI::ShowOperation
          @operation.id
        when JSONAPI::ShowRelatedResourcesOperation
          @operation.source_id
        else
          @operation.resource_id
        end
      end

      def model_class_for_relationship(assoc_name)
        @operation.resource_klass._relationships[assoc_name].resource_klass._model_class
      end

      def related_models
        data = @operation.options[:data]
        return [] if data.nil?

        [:to_one, :to_many].flat_map do |rel_type|
          data[rel_type].flat_map do |assoc_name, assoc_ids|
            assoc_klass = model_class_for_relationship(assoc_name)
            assoc_klass.find(assoc_ids)
          end
        end
      end
    end
  end
end<commit_msg>Use better API for fetching relationship from resource_klass<commit_after>require 'pundit'

module JSONAPI
  module Authorization
    class PunditOperationsProcessor < ::ActiveRecordOperationsProcessor
      set_callback :find_operation, :before, :authorize_find
      set_callback :show_operation, :before, :authorize_show
      set_callback :show_related_resource_operation, :before, :authorize_show_related_resource
      set_callback :show_related_resources_operation, :before, :authorize_show_related_resources
      set_callback :create_resource_operation, :before, :authorize_create_resource
      set_callback :remove_resource_operation, :before, :authorize_remove_resource
      set_callback :replace_fields_operation, :before, :authorize_replace_fields

      def authorize_find
        ::Pundit.authorize(pundit_user, @operation.resource_klass._model_class, 'index?')
      end

      def authorize_show
        record = @operation.resource_klass.find_by_key(
          operation_resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, record, 'show?')
      end

      def authorize_show_related_resource
        source_resource = @operation.source_klass.find_by_key(
          @operation.source_id,
          context: operation_context
        )
        source_record = source_resource._model
        ::Pundit.authorize(pundit_user, source_record, 'show?')

        related_resource = source_resource.public_send(@operation.relationship_type)
        if related_resource.present?
          related_record = related_resource._model
          ::Pundit.authorize(pundit_user, related_record, 'show?')
        end
      end

      def authorize_show_related_resources
        source_record = @operation.source_klass.find_by_key(
          @operation.source_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, source_record, 'show?')
      end

      def authorize_replace_fields
        source_record = @operation.resource_klass.find_by_key(
          @operation.resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, source_record, 'update?')

        related_models.each do |rel_model|
          ::Pundit.authorize(pundit_user, rel_model, 'update?')
        end
      end

      def authorize_create_resource
        ::Pundit.authorize(pundit_user, @operation.resource_klass._model_class, 'create?')

        related_models.each do |rel_model|
          ::Pundit.authorize(pundit_user, rel_model, 'update?')
        end
      end

      def authorize_remove_resource
        record = @operation.resource_klass.find_by_key(
          operation_resource_id,
          context: operation_context
        )._model

        ::Pundit.authorize(pundit_user, record, 'destroy?')
      end

      private

      def pundit_user
        operation_context[:user]
      end

      # TODO: Communicate with upstream to fix this nasty hack
      def operation_context
        case @operation
        when JSONAPI::ShowRelatedResourcesOperation
          @operation.instance_variable_get('@options')[:context]
        else
          @operation.options[:context]
        end
      end

      # TODO: Communicate with upstream to fix this nasty hack
      def operation_resource_id
        case @operation
        when JSONAPI::ShowOperation
          @operation.id
        when JSONAPI::ShowRelatedResourcesOperation
          @operation.source_id
        else
          @operation.resource_id
        end
      end

      def model_class_for_relationship(assoc_name)
        @operation.resource_klass._relationship(assoc_name).resource_klass._model_class
      end

      def related_models
        data = @operation.options[:data]
        return [] if data.nil?

        [:to_one, :to_many].flat_map do |rel_type|
          data[rel_type].flat_map do |assoc_name, assoc_ids|
            assoc_klass = model_class_for_relationship(assoc_name)
            assoc_klass.find(assoc_ids)
          end
        end
      end
    end
  end
end
{'fraction_non_alphanumeric': 0.07190347205121891, 'fraction_numerical': 0.0, 'mean_word_length': 2.7887126865671643, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3432081', 'n_tokens_mistral': 2342, 'n_tokens_neox': 2294, 'n_words': 426}