<commit_before>module OpenFoodNetwork
  class Permissions
    def initialize(user)
      @user = user
    end

    def can_manage_complex_order_cycles?
      managed_and_related_enterprises_granting(:add_to_order_cycle).any? do |e|
        e.sells == 'any'
      end
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def visible_enterprises_for_order_reports
      managed_and_related_enterprises_with :add_to_order_cycle
    end

    def visible_enterprises
      # Return enterprises that the user manages and those that have granted P-OC to managed enterprises
      managed_and_related_enterprises_granting :add_to_order_cycle
    end

    # Find enterprises for which an admin is allowed to edit their profile
    def editable_enterprises
      managed_and_related_enterprises_granting :edit_profile
    end

    def variant_override_hubs
      managed_enterprises.is_distributor
    end

    def variant_override_producers
      producer_ids = variant_override_enterprises_per_hub.values.flatten.uniq
      Enterprise.where(id: producer_ids)
    end

    # For every hub that an admin manages, show all the producers for which that hub may
    # override variants
    # {hub1_id => [producer1_id, producer2_id, ...], ...}
    def variant_override_enterprises_per_hub
      hubs = variant_override_hubs

      # Permissions granted by create_variant_overrides relationship from producer to hub
      permissions = Hash[
           EnterpriseRelationship.
             permitting(hubs.select(:id)).
             with_permission(:create_variant_overrides).
             group_by(&:child_id).
             map { |child_id, ers| [child_id, ers.map(&:parent_id)] }
          ]

      # Allow a producer hub to override it's own products without explicit permission
      hubs.is_primary_producer.each do |hub|
        permissions[hub.id] ||= []
        permissions[hub.id] |= [hub.id]
      end

      permissions
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def visible_orders
      # Any orders that I can edit
      editable = editable_orders.pluck(:id)

      # Any orders placed through hubs that my producers have granted P-OC, and which contain my their products
      # This is pretty complicated but it's looking for order where at least one of my producers has granted
      # P-OC to the distributor AND the order contains products of at least one of THE SAME producers
      granted_distributor_ids = related_enterprises_granted(:add_to_order_cycle, by: managed_enterprises.is_primary_producer.pluck(:id))
      produced = Spree::Order.with_line_items_variants_and_products_outer.
        where(
          "spree_orders.distributor_id IN (?) AND spree_products.supplier_id IN (?)",
          granted_distributor_ids,
          related_enterprises_granting(:add_to_order_cycle, to: granted_distributor_ids).merge(managed_enterprises.is_primary_producer)
        ).pluck(:id)

      Spree::Order.where(id: editable | produced)
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def editable_orders
      # Any orders placed through any hub that I manage
      managed = Spree::Order.where(distributor_id: managed_enterprises.pluck(:id)).pluck(:id)

      # Any order that is placed through an order cycle one of my managed enterprises coordinates
      coordinated = Spree::Order.where(order_cycle_id: coordinated_order_cycles.pluck(:id)).pluck(:id)

      Spree::Order.where(id: managed | coordinated )
    end

    def visible_line_items
      # Any line items that I can edit
      editable = editable_line_items.pluck(:id)

      # Any from visible orders, where the product is produced by one of my managed producers
      produced = Spree::LineItem.where(order_id: visible_orders.pluck(:id)).joins(:product).
        where('spree_products.supplier_id IN (?)', managed_enterprises.is_primary_producer.pluck(:id))

      Spree::LineItem.where(id: editable | produced)
    end

    def editable_line_items
      Spree::LineItem.where(order_id: editable_orders)
    end

    def editable_products
      managed_enterprise_products_ids = managed_enterprise_products.pluck :id
      permitted_enterprise_products_ids = product_ids_supplied_by(
        related_enterprises_granting(:manage_products)
      )
      Spree::Product.where('spree_products.id IN (?)', managed_enterprise_products_ids | permitted_enterprise_products_ids)
    end

    def visible_products
      managed_enterprise_products_ids = managed_enterprise_products.pluck :id
      permitted_enterprise_products_ids = product_ids_supplied_by(
        related_enterprises_granting(:manage_products) | related_enterprises_granting(:add_to_order_cycle)
      )
      Spree::Product.where('spree_products.id IN (?)', managed_enterprise_products_ids | permitted_enterprise_products_ids)
    end

    def managed_product_enterprises
      managed_and_related_enterprises_granting :manage_products
    end

    def manages_one_enterprise?
      @user.enterprises.length == 1
    end

    def editable_schedules
      Schedule.joins(:order_cycles).where(order_cycles: { id: OrderCycle.managed_by(@user).pluck(:id) }).select("DISTINCT schedules.*")
    end

    def visible_schedules
      Schedule.joins(:order_cycles).where(order_cycles: { id: OrderCycle.accessible_by(@user).pluck(:id) }).select("DISTINCT schedules.*")
    end

    def editable_subscriptions
      Subscription.where('subscriptions.shop_id IN (?)', managed_enterprises)
    end

    def visible_subscriptions
      editable_subscriptions
    end

    private

    def admin?
      @user.admin?
    end

    def managed_and_related_enterprises_granting(permission)
      if admin?
        Enterprise.scoped
      else
        managed_enterprise_ids = managed_enterprises.pluck :id
        permitting_enterprise_ids = related_enterprises_granting(permission)

        Enterprise.where('id IN (?)', managed_enterprise_ids + permitting_enterprise_ids)
      end
    end

    def managed_and_related_enterprises_with(permission)
      if admin?
        Enterprise.scoped
      else
        managed_enterprise_ids = managed_enterprises.pluck(:id)
        granting_enterprise_ids = related_enterprises_granting(permission)
        granted_enterprise_ids = related_enterprises_granted(permission)
        Enterprise.where(id: managed_enterprise_ids | granting_enterprise_ids | granted_enterprise_ids)
      end
    end

    def managed_enterprises
      return @managed_enterprises unless @managed_enterprises.nil?
      @managed_enterprises = Enterprise.managed_by(@user)
    end

    def coordinated_order_cycles
      return @coordinated_order_cycles unless @coordinated_order_cycles.nil?
      @coordinated_order_cycles = OrderCycle.managed_by(@user)
    end

    def related_enterprises_granting(permission, options = {})
      parent_ids = EnterpriseRelationship.
        permitting(options[:to] || managed_enterprises.select(:id)).
        with_permission(permission).
        pluck(:parent_id)

      (options[:scope] || Enterprise).where('enterprises.id IN (?)', parent_ids)
    end

    def related_enterprises_granted(permission, options = {})
      child_ids = EnterpriseRelationship.
        permitted_by(options[:by] || managed_enterprises.select(:id)).
        with_permission(permission).
        pluck(:child_id)

      (options[:scope] || Enterprise).where('enterprises.id IN (?)', child_ids).select(:id)
    end

    def managed_enterprise_products
      Spree::Product.managed_by(@user)
    end

    def product_ids_supplied_by(supplier_ids)
      Spree::Product.where('supplier_id IN (?)', supplier_ids).pluck(:id)
    end
  end<commit_msg>Fix Permissions.related_enterprises_granted by adding explicit reference to table<commit_after>module OpenFoodNetwork
  class Permissions
    def initialize(user)
      @user = user
    end

    def can_manage_complex_order_cycles?
      managed_and_related_enterprises_granting(:add_to_order_cycle).any? do |e|
        e.sells == 'any'
      end
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def visible_enterprises_for_order_reports
      managed_and_related_enterprises_with :add_to_order_cycle
    end

    def visible_enterprises
      # Return enterprises that the user manages and those that have granted P-OC to managed enterprises
      managed_and_related_enterprises_granting :add_to_order_cycle
    end

    # Find enterprises for which an admin is allowed to edit their profile
    def editable_enterprises
      managed_and_related_enterprises_granting :edit_profile
    end

    def variant_override_hubs
      managed_enterprises.is_distributor
    end

    def variant_override_producers
      producer_ids = variant_override_enterprises_per_hub.values.flatten.uniq
      Enterprise.where(id: producer_ids)
    end

    # For every hub that an admin manages, show all the producers for which that hub may
    # override variants
    # {hub1_id => [producer1_id, producer2_id, ...], ...}
    def variant_override_enterprises_per_hub
      hubs = variant_override_hubs

      # Permissions granted by create_variant_overrides relationship from producer to hub
      permissions = Hash[
           EnterpriseRelationship.
             permitting(hubs.select(:id)).
             with_permission(:create_variant_overrides).
             group_by(&:child_id).
             map { |child_id, ers| [child_id, ers.map(&:parent_id)] }
          ]

      # Allow a producer hub to override it's own products without explicit permission
      hubs.is_primary_producer.each do |hub|
        permissions[hub.id] ||= []
        permissions[hub.id] |= [hub.id]
      end

      permissions
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def visible_orders
      # Any orders that I can edit
      editable = editable_orders.pluck(:id)

      # Any orders placed through hubs that my producers have granted P-OC, and which contain my their products
      # This is pretty complicated but it's looking for order where at least one of my producers has granted
      # P-OC to the distributor AND the order contains products of at least one of THE SAME producers
      granted_distributor_ids = related_enterprises_granted(:add_to_order_cycle, by: managed_enterprises.is_primary_producer.pluck(:id))
      produced = Spree::Order.with_line_items_variants_and_products_outer.
        where(
          "spree_orders.distributor_id IN (?) AND spree_products.supplier_id IN (?)",
          granted_distributor_ids,
          related_enterprises_granting(:add_to_order_cycle, to: granted_distributor_ids).merge(managed_enterprises.is_primary_producer)
        ).pluck(:id)

      Spree::Order.where(id: editable | produced)
    end

    # Find enterprises that an admin is allowed to add to an order cycle
    def editable_orders
      # Any orders placed through any hub that I manage
      managed = Spree::Order.where(distributor_id: managed_enterprises.pluck(:id)).pluck(:id)

      # Any order that is placed through an order cycle one of my managed enterprises coordinates
      coordinated = Spree::Order.where(order_cycle_id: coordinated_order_cycles.pluck(:id)).pluck(:id)

      Spree::Order.where(id: managed | coordinated )
    end

    def visible_line_items
      # Any line items that I can edit
      editable = editable_line_items.pluck(:id)

      # Any from visible orders, where the product is produced by one of my managed producers
      produced = Spree::LineItem.where(order_id: visible_orders.pluck(:id)).joins(:product).
        where('spree_products.supplier_id IN (?)', managed_enterprises.is_primary_producer.pluck(:id))

      Spree::LineItem.where(id: editable | produced)
    end

    def editable_line_items
      Spree::LineItem.where(order_id: editable_orders)
    end

    def editable_products
      managed_enterprise_products_ids = managed_enterprise_products.pluck :id
      permitted_enterprise_products_ids = product_ids_supplied_by(
        related_enterprises_granting(:manage_products)
      )
      Spree::Product.where('spree_products.id IN (?)', managed_enterprise_products_ids | permitted_enterprise_products_ids)
    end

    def visible_products
      managed_enterprise_products_ids = managed_enterprise_products.pluck :id
      permitted_enterprise_products_ids = product_ids_supplied_by(
        related_enterprises_granting(:manage_products) | related_enterprises_granting(:add_to_order_cycle)
      )
      Spree::Product.where('spree_products.id IN (?)', managed_enterprise_products_ids | permitted_enterprise_products_ids)
    end

    def managed_product_enterprises
      managed_and_related_enterprises_granting :manage_products
    end

    def manages_one_enterprise?
      @user.enterprises.length == 1
    end

    def editable_schedules
      Schedule.joins(:order_cycles).where(order_cycles: { id: OrderCycle.managed_by(@user).pluck(:id) }).select("DISTINCT schedules.*")
    end

    def visible_schedules
      Schedule.joins(:order_cycles).where(order_cycles: { id: OrderCycle.accessible_by(@user).pluck(:id) }).select("DISTINCT schedules.*")
    end

    def editable_subscriptions
      Subscription.where('subscriptions.shop_id IN (?)', managed_enterprises)
    end

    def visible_subscriptions
      editable_subscriptions
    end

    private

    def admin?
      @user.admin?
    end

    def managed_and_related_enterprises_granting(permission)
      if admin?
        Enterprise.scoped
      else
        managed_enterprise_ids = managed_enterprises.pluck :id
        permitting_enterprise_ids = related_enterprises_granting(permission)

        Enterprise.where('id IN (?)', managed_enterprise_ids + permitting_enterprise_ids)
      end
    end

    def managed_and_related_enterprises_with(permission)
      if admin?
        Enterprise.scoped
      else
        managed_enterprise_ids = managed_enterprises.pluck(:id)
        granting_enterprise_ids = related_enterprises_granting(permission)
        granted_enterprise_ids = related_enterprises_granted(permission)
        Enterprise.where(id: managed_enterprise_ids | granting_enterprise_ids | granted_enterprise_ids)
      end
    end

    def managed_enterprises
      return @managed_enterprises unless @managed_enterprises.nil?
      @managed_enterprises = Enterprise.managed_by(@user)
    end

    def coordinated_order_cycles
      return @coordinated_order_cycles unless @coordinated_order_cycles.nil?
      @coordinated_order_cycles = OrderCycle.managed_by(@user)
    end

    def related_enterprises_granting(permission, options = {})
      parent_ids = EnterpriseRelationship.
        permitting(options[:to] || managed_enterprises.select(:id)).
        with_permission(permission).
        pluck(:parent_id)

      (options[:scope] || Enterprise).where('enterprises.id IN (?)', parent_ids)
    end

    def related_enterprises_granted(permission, options = {})
      child_ids = EnterpriseRelationship.
        permitted_by(options[:by] || managed_enterprises.select(:id)).
        with_permission(permission).
        pluck(:child_id)

      (options[:scope] || Enterprise).where('enterprises.id IN (?)', child_ids).select("enterprises.id")
    end

    def managed_enterprise_products
      Spree::Product.managed_by(@user)
    end

    def product_ids_supplied_by(supplier_ids)
      Spree::Product.where('supplier_id IN (?)', supplier_ids).pluck(:id)
    end
  end
{'fraction_non_alphanumeric': 0.07276131448124476, 'fraction_numerical': 0.0005164955775066176, 'mean_word_length': 3.5909899229401305, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 5, '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': '804414', 'n_tokens_mistral': 4570, 'n_tokens_neox': 4411, 'n_words': 998}