# frozen_string_literal: true require_relative 'logging' module Checkoff module Internal # Uses an enhanced version of Asana event filter configuration # # See https://developers.asana.com/reference/createwebhook | body # params | data | filters | add object for a general description of the scheme. # # Additional supported filter keys: # # * 'checkoff:parent.gid' - requires that the 'gid' key in the 'parent' object # match the given value class AsanaEventFilter include Logging # @param filters [Array, nil] The filters to match against # @param clients [Checkoff::Clients] # @param client [Asana::Client] def initialize(filters:, clients: Checkoff::Clients.new, client: clients.client) @filters = filters @client = client end # @param asana_event [Hash] The event that Asana sent def matches?(asana_event) logger.debug { "Filtering using #{@filters.inspect}" } return true if @filters.nil? failures = [] @filters.any? do |filter| filter_matches = filter_matches_asana_event?(filter, asana_event, failures) logger.debug { "Filter #{filter.inspect} matched? #{filter_matches} against event #{asana_event.inspect}" } unless filter_matches logger.info do "Filter #{filter.inspect} failed to match event #{asana_event.inspect} because of #{failures.inspect}" end failures << filter end filter_matches end end private # @param filter [Hash] # @param asana_event [Hash] # @param failures [Array] # # @sg-ignore # @return [Boolean] def filter_matches_asana_event?(filter, asana_event, failures) # @param key [String] # @param value [String, Array] filter.all? do |key, value| matches = asana_event_matches_filter_item?(key, value, asana_event) failures << "#{key.inspect} = #{value.inspect}" unless matches matches end end # @param key [String] # @param value [String, Array] # @param asana_event [Hash] # # @sg-ignore # @return [Boolean] def asana_event_matches_filter_item?(key, value, asana_event) case key when 'resource_type' asana_event.fetch('resource', {})['resource_type'] == value when 'resource_subtype' asana_event.fetch('resource', {})['resource_subtype'] == value when 'action' asana_event['action'] == value when 'fields' value.include? asana_event.fetch('change', {})['field'] when 'checkoff:parent.gid' asana_event.fetch('parent', {})['gid'] == value when 'checkoff:resource.gid' asana_event.fetch('resource', {})['gid'] == value when 'checkoff:fetched.completed' # @type [Hash{String => String}] # @sg-ignore resource = asana_event.fetch('resource') # @type [String] resource_type = resource.fetch('resource_type') unless resource_type == 'task' raise "Teach me how to check #{key.inspect} on resource type #{resource_type.inspect}" end task_gid = resource.fetch('gid') options = { fields: ['completed_at'], } task = @client.tasks.find_by_id(task_gid, options: options) task_completed = !task.completed_at.nil? task_completed == value else raise "Unknown filter key #{key}" end end end end end