# frozen_string_literal: true module SmartTodo module Dispatchers # Dispatcher that sends TODO reminders on Slack. Assignees can be either individual # (using the associated slack email address) or a channel. class Slack < Base class << self def validate_options!(options) options[:slack_token] ||= ENV.fetch("SMART_TODO_SLACK_TOKEN") { raise(ArgumentError, "Missing :slack_token") } options.fetch(:fallback_channel) { raise(ArgumentError, "Missing :fallback_channel") } end end # Make a Slack API call to dispatch the message to each assignee # # @raise [SlackClient::Error] in case the Slack API returns an error # other than `users_not_found` # # @return [Array] Slack response for each assignee a message was sent to def dispatch @assignees.each do |assignee| dispatch_one(assignee) end end # Make a Slack API call to dispatch the message to the user or channel # # @raise [SlackClient::Error] in case the Slack API returns an error # other than `users_not_found` # # @param [String] the assignee handle string # @return [Hash] the Slack response def dispatch_one(assignee) user = slack_user_or_channel(assignee) client.post_message(user.dig("user", "id"), slack_message(user, assignee)) rescue SlackClient::Error => error if ["users_not_found", "channel_not_found", "is_archived"].include?(error.error_code) user = { "user" => { "id" => @options[:fallback_channel] }, "fallback" => true } else raise(error) end client.post_message(user.dig("user", "id"), slack_message(user, assignee)) end private # Returns a formatted hash containing either the user id of a slack user or # the channel the message should be sent to. # # @return [Hash] a suited hash containing the user ID for a given individual or a slack channel def slack_user_or_channel(assignee) if assignee.include?("@") client.lookup_user_by_email(assignee) else { "user" => { "id" => assignee } } end end # @return [SlackClient] an instance of SlackClient def client @client ||= SlackClient.new(@options[:slack_token]) end end end end