<commit_before>require 'open_food_network/referer_parser'
require 'open_food_network/permissions'
require 'open_food_network/order_cycle_permissions'

module Admin
  class EnterprisesController < ResourceController
    # These need to run before #load_resource so that @object is initialised with sanitised values
    prepend_before_filter :override_owner, only: :create
    prepend_before_filter :override_sells, only: :create

    before_filter :load_enterprise_set, only: :index
    before_filter :load_countries, except: [:index, :register, :check_permalink]
    before_filter :load_methods_and_fees, only: [:edit, :update]
    before_filter :load_groups, only: [:new, :edit, :update, :create]
    before_filter :load_taxons, only: [:new, :edit, :update, :create]
    before_filter :check_can_change_sells, only: :update
    before_filter :check_can_change_bulk_sells, only: :bulk_update
    before_filter :check_can_change_owner, only: :update
    before_filter :check_can_change_bulk_owner, only: :bulk_update
    before_filter :check_can_change_managers, only: :update
    before_filter :strip_new_properties, only: [:create, :update]
    before_filter :load_properties, only: [:edit, :update]
    before_filter :setup_property, only: [:edit]

    helper 'spree/products'
    include OrderCyclesHelper

    def index
      respond_to do |format|
        format.html
        format.json { render_as_json @collection, ams_prefix: params[:ams_prefix], spree_current_user: spree_current_user }
      end
    end

    def welcome
      render layout: "spree/layouts/bare_admin"
    end

    def update
      invoke_callbacks(:update, :before)
      tag_rules_attributes = params[object_name].delete :tag_rules_attributes
      update_tag_rules(tag_rules_attributes) if tag_rules_attributes.present?
      update_enterprise_notifications
      if @object.update_attributes(params[object_name])
        invoke_callbacks(:update, :after)
        flash[:success] = flash_message_for(@object, :successfully_updated)
        respond_with(@object) do |format|
          format.html { redirect_to location_after_save }
          format.js   { render layout: false }
          format.json { render_as_json @object, ams_prefix: 'index', spree_current_user: spree_current_user }
        end
      else
        invoke_callbacks(:update, :fails)
        respond_with(@object) do |format|
          format.json { render json: { errors: @object.errors.messages }, status: :unprocessable_entity }
        end
      end
    end

    def register
      if params[:sells] == 'unspecified'
        flash[:error] = I18n.t(:enterprise_register_package_error)
        return render :welcome, layout: "spree/layouts/bare_admin"
      end

      attributes = { sells: params[:sells], visible: true }

      if @enterprise.update_attributes(attributes)
        flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
        redirect_to admin_dashboard_path
      else
        flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
        render :welcome, layout: "spree/layouts/bare_admin"
      end
    end

    def bulk_update
      @enterprise_set = EnterpriseSet.new(collection, params[:enterprise_set])
      if @enterprise_set.save
        flash[:success] = I18n.t(:enterprise_bulk_update_success_notice)

        redirect_to main_app.admin_enterprises_path
      else
        touched_enterprises = @enterprise_set.collection.select(&:changed?)
        @enterprise_set.collection.select! { |e| touched_enterprises.include? e }
        flash[:error] = I18n.t(:enterprise_bulk_update_error)
        render :index
      end
    end

    def for_order_cycle
      respond_to do |format|
        format.json do
          render json: @collection, each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer, order_cycle: @order_cycle, spree_current_user: spree_current_user
        end
      end
    end

    def visible
      respond_to do |format|
        format.json do
          render_as_json @collection, ams_prefix: params[:ams_prefix] || 'basic', spree_current_user: spree_current_user
        end
      end
    end

    protected

    def build_resource_with_address
      enterprise = build_resource_without_address
      enterprise.address ||= Spree::Address.new
      enterprise.address.country ||= Spree::Country.find_by_id(Spree::Config[:default_country_id])
      enterprise
    end
    alias_method_chain :build_resource, :address

    # Overriding method on Spree's resource controller,
    # so that resources are found using permalink
    def find_resource
      Enterprise.find_by_permalink(params[:id])
    end

    private

    def load_enterprise_set
      @enterprise_set = EnterpriseSet.new(collection) if spree_current_user.admin?
    end

    def load_countries
      @countries = Spree::Country.order(:name)
    end

    def collection
      case action
      when :for_order_cycle
        @order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
        coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
        @order_cycle = OrderCycle.new(coordinator: coordinator) if @order_cycle.nil? && coordinator.present?

        enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, @order_cycle)
          .visible_enterprises

        unless enterprises.empty?
          enterprises.includes(
            supplied_products:
              [:supplier, master: [:images], variants: { option_values: :option_type }]
          )
        end
      when :index
        if spree_current_user.admin?
          OpenFoodNetwork::Permissions.new(spree_current_user).
            editable_enterprises.
            order('is_primary_producer ASC, name')
        elsif json_request?
          OpenFoodNetwork::Permissions.new(spree_current_user).editable_enterprises.ransack(params[:q]).result
        else
          Enterprise.where("1=0")
        end
      when :visible
        OpenFoodNetwork::Permissions.new(spree_current_user).visible_enterprises
          .includes(:shipping_methods, :payment_methods).ransack(params[:q]).result
      else
        # TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
        OpenFoodNetwork::Permissions.new(spree_current_user).
          editable_enterprises.
          order('is_primary_producer ASC, name')
      end
    end

    def collection_actions
      [:index, :for_order_cycle, :visible, :bulk_update]
    end

    def load_methods_and_fees
      # rubocop:disable Style/TernaryParentheses
      @payment_methods = Spree::PaymentMethod.managed_by(spree_current_user).sort_by! do |pm|
        [(@enterprise.payment_methods.include? pm) ? 0 : 1, pm.name]
      end
      @shipping_methods = Spree::ShippingMethod.managed_by(spree_current_user).sort_by! do |sm|
        [(@enterprise.shipping_methods.include? sm) ? 0 : 1, sm.name]
      end
      # rubocop:enable Style/TernaryParentheses

      @enterprise_fees = EnterpriseFee
        .managed_by(spree_current_user)
        .for_enterprise(@enterprise)
        .order(:fee_type, :name)
        .all
    end

    def load_groups
      @groups = EnterpriseGroup.managed_by(spree_current_user) | @enterprise.groups
    end

    def load_taxons
      @taxons = Spree::Taxon.order(:name)
    end

    def update_tag_rules(tag_rules_attributes)
      # Due to the combination of trying to use nested attributes and type inheritance
      # we cannot apply all attributes to tag rules in one hit because mass assignment
      # methods that are specific to each class do not become available until after the
      # record is persisted. This problem is compounded by the use of calculators.
      @object.transaction do
        tag_rules_attributes.select{ |_i, attrs| attrs[:type].present? }.each do |_i, attrs|
          rule = @object.tag_rules.find_by_id(attrs.delete(:id)) || attrs[:type].constantize.new(enterprise: @object)
          create_calculator_for(rule, attrs) if rule.type == "TagRule::DiscountOrder" && rule.calculator.nil?
          rule.update_attributes(attrs)
        end
      end
    end<commit_msg>Fix big N+1 issues in enterprises#edit for superadmin<commit_after>require 'open_food_network/referer_parser'
require 'open_food_network/permissions'
require 'open_food_network/order_cycle_permissions'

module Admin
  class EnterprisesController < ResourceController
    # These need to run before #load_resource so that @object is initialised with sanitised values
    prepend_before_filter :override_owner, only: :create
    prepend_before_filter :override_sells, only: :create

    before_filter :load_enterprise_set, only: :index
    before_filter :load_countries, except: [:index, :register, :check_permalink]
    before_filter :load_methods_and_fees, only: [:edit, :update]
    before_filter :load_groups, only: [:new, :edit, :update, :create]
    before_filter :load_taxons, only: [:new, :edit, :update, :create]
    before_filter :check_can_change_sells, only: :update
    before_filter :check_can_change_bulk_sells, only: :bulk_update
    before_filter :check_can_change_owner, only: :update
    before_filter :check_can_change_bulk_owner, only: :bulk_update
    before_filter :check_can_change_managers, only: :update
    before_filter :strip_new_properties, only: [:create, :update]
    before_filter :load_properties, only: [:edit, :update]
    before_filter :setup_property, only: [:edit]

    helper 'spree/products'
    include OrderCyclesHelper

    def index
      respond_to do |format|
        format.html
        format.json { render_as_json @collection, ams_prefix: params[:ams_prefix], spree_current_user: spree_current_user }
      end
    end

    def edit
      @object = Enterprise.where(permalink: params[:id]).includes(users: [:ship_address, :bill_address]).first
      super
    end

    def welcome
      render layout: "spree/layouts/bare_admin"
    end

    def update
      invoke_callbacks(:update, :before)
      tag_rules_attributes = params[object_name].delete :tag_rules_attributes
      update_tag_rules(tag_rules_attributes) if tag_rules_attributes.present?
      update_enterprise_notifications
      if @object.update_attributes(params[object_name])
        invoke_callbacks(:update, :after)
        flash[:success] = flash_message_for(@object, :successfully_updated)
        respond_with(@object) do |format|
          format.html { redirect_to location_after_save }
          format.js   { render layout: false }
          format.json { render_as_json @object, ams_prefix: 'index', spree_current_user: spree_current_user }
        end
      else
        invoke_callbacks(:update, :fails)
        respond_with(@object) do |format|
          format.json { render json: { errors: @object.errors.messages }, status: :unprocessable_entity }
        end
      end
    end

    def register
      if params[:sells] == 'unspecified'
        flash[:error] = I18n.t(:enterprise_register_package_error)
        return render :welcome, layout: "spree/layouts/bare_admin"
      end

      attributes = { sells: params[:sells], visible: true }

      if @enterprise.update_attributes(attributes)
        flash[:success] = I18n.t(:enterprise_register_success_notice, enterprise: @enterprise.name)
        redirect_to admin_dashboard_path
      else
        flash[:error] = I18n.t(:enterprise_register_error, enterprise: @enterprise.name)
        render :welcome, layout: "spree/layouts/bare_admin"
      end
    end

    def bulk_update
      @enterprise_set = EnterpriseSet.new(collection, params[:enterprise_set])
      if @enterprise_set.save
        flash[:success] = I18n.t(:enterprise_bulk_update_success_notice)

        redirect_to main_app.admin_enterprises_path
      else
        touched_enterprises = @enterprise_set.collection.select(&:changed?)
        @enterprise_set.collection.select! { |e| touched_enterprises.include? e }
        flash[:error] = I18n.t(:enterprise_bulk_update_error)
        render :index
      end
    end

    def for_order_cycle
      respond_to do |format|
        format.json do
          render json: @collection, each_serializer: Api::Admin::ForOrderCycle::EnterpriseSerializer, order_cycle: @order_cycle, spree_current_user: spree_current_user
        end
      end
    end

    def visible
      respond_to do |format|
        format.json do
          render_as_json @collection, ams_prefix: params[:ams_prefix] || 'basic', spree_current_user: spree_current_user
        end
      end
    end

    protected

    def build_resource_with_address
      enterprise = build_resource_without_address
      enterprise.address ||= Spree::Address.new
      enterprise.address.country ||= Spree::Country.find_by_id(Spree::Config[:default_country_id])
      enterprise
    end
    alias_method_chain :build_resource, :address

    # Overriding method on Spree's resource controller,
    # so that resources are found using permalink
    def find_resource
      Enterprise.find_by_permalink(params[:id])
    end

    private

    def load_enterprise_set
      @enterprise_set = EnterpriseSet.new(collection) if spree_current_user.admin?
    end

    def load_countries
      @countries = Spree::Country.order(:name)
    end

    def collection
      case action
      when :for_order_cycle
        @order_cycle = OrderCycle.find_by_id(params[:order_cycle_id]) if params[:order_cycle_id]
        coordinator = Enterprise.find_by_id(params[:coordinator_id]) if params[:coordinator_id]
        @order_cycle = OrderCycle.new(coordinator: coordinator) if @order_cycle.nil? && coordinator.present?

        enterprises = OpenFoodNetwork::OrderCyclePermissions.new(spree_current_user, @order_cycle)
          .visible_enterprises

        unless enterprises.empty?
          enterprises.includes(
            supplied_products:
              [:supplier, master: [:images], variants: { option_values: :option_type }]
          )
        end
      when :index
        if spree_current_user.admin?
          OpenFoodNetwork::Permissions.new(spree_current_user).
            editable_enterprises.
            order('is_primary_producer ASC, name')
        elsif json_request?
          OpenFoodNetwork::Permissions.new(spree_current_user).editable_enterprises.ransack(params[:q]).result
        else
          Enterprise.where("1=0")
        end
      when :visible
        OpenFoodNetwork::Permissions.new(spree_current_user).visible_enterprises
          .includes(:shipping_methods, :payment_methods).ransack(params[:q]).result
      else
        # TODO was ordered with is_distributor DESC as well, not sure why or how we want to sort this now
        OpenFoodNetwork::Permissions.new(spree_current_user).
          editable_enterprises.
          order('is_primary_producer ASC, name')
      end
    end

    def collection_actions
      [:index, :for_order_cycle, :visible, :bulk_update]
    end

    def load_methods_and_fees
      enterprise_payment_methods = @enterprise.payment_methods.to_a
      enterprise_shipping_methods = @enterprise.shipping_methods.to_a
      # rubocop:disable Style/TernaryParentheses
      @payment_methods = Spree::PaymentMethod.managed_by(spree_current_user).sort_by! do |pm|
        [(enterprise_payment_methods.include? pm) ? 0 : 1, pm.name]
      end
      @shipping_methods = Spree::ShippingMethod.managed_by(spree_current_user).sort_by! do |sm|
        [(enterprise_shipping_methods.include? sm) ? 0 : 1, sm.name]
      end
      # rubocop:enable Style/TernaryParentheses

      @enterprise_fees = EnterpriseFee
        .managed_by(spree_current_user)
        .for_enterprise(@enterprise)
        .order(:fee_type, :name)
        .all
    end

    def load_groups
      @groups = EnterpriseGroup.managed_by(spree_current_user) | @enterprise.groups
    end

    def load_taxons
      @taxons = Spree::Taxon.order(:name)
    end

    def update_tag_rules(tag_rules_attributes)
      # Due to the combination of trying to use nested attributes and type inheritance
      # we cannot apply all attributes to tag rules in one hit because mass assignment
      # methods that are specific to each class do not become available until after the
      # record is persisted. This problem is compounded by the use of calculators.
      @object.transaction do
        tag_rules_attributes.select{ |_i, attrs| attrs[:type].present? }.each do |_i, attrs|
          rule = @object.tag_rules.find_by_id(attrs.delete(:id)) || attrs[:type].constantize.new(enterprise: @object)
          create_calculator_for(rule, attrs) if rule.type == "TagRule::DiscountOrder" && rule.calculator.nil?
          rule.update_attributes(attrs)
        end
      end
    end
{'fraction_non_alphanumeric': 0.08520929121633726, 'fraction_numerical': 0.001970502179494835, 'mean_word_length': 3.391190351337179, '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': '5823125', 'n_tokens_mistral': 5063, 'n_tokens_neox': 4967, 'n_words': 1075}