nunonamorado/sinatra-slack

View on GitHub
lib/sinatra/slack.rb

Summary

Maintainability
A
1 hr
Test Coverage
# frozen_string_literal: true

require 'sinatra/async'
require_relative './slack/instance_helpers'

# Sinatra
module Sinatra
  # Sinatra Module for creating Slack apps with ease
  module Slack
    def self.registered(app)
      # We will use async request handling so that it's easier
      # so offload heavier proccessing to a background thread.
      # Sinatra::Async uses EventMachine.
      app.register Sinatra::Async

      # Slack signing secret, used for request verification
      app.set :slack_secret, nil
      app.helpers Slack::InstanceHelpers
    end

    # Defines a new HTTP POST Handler to receive
    # Slash Command notifications.
    def commands_endpoint(path, quick_reply: '')
      set_endpoint(path, quick_reply) do
        signature = "#{command.command} #{command.text}"
        command_pattern = self.class.get_pattern(signature)
        raise 'Command not defined' unless command_pattern

        request_params = command_pattern.params(signature).values

        {
          request_handler: self.class.get_handler(signature),
          request_params: request_params
        }
      end
    end

    # Defines a new HTTP POST Handler to receive
    # Actions notifications.
    def actions_endpoint(path, quick_reply: '')
      set_endpoint(path, quick_reply) do
        action_pattern = self.class.get_pattern(action.name)
        raise 'Action not defined' unless action_pattern

        request_params = action_pattern.params(action.name).values || []
        request_params << action.value

        {
          request_handler: self.class.get_handler(action.name),
          request_params: request_params
        }
      end
    end

    def register_handler(signature, &block)
      pattern = parse_signature(signature)
      method_name = get_handler_name(pattern)
      define_method(method_name, &block)
    end
    alias action register_handler
    alias command register_handler

    def get_handler(signature)
      pattern = get_pattern(signature)
      return unless pattern

      method_name = get_handler_name(pattern)
      instance_method method_name
    end

    def get_pattern(signature)
      @patterns.find { |p| p.match(signature) }
    end

    private

    def get_handler_name(pattern)
      "#{pattern.safe_string}_handler"
    end

    def parse_signature(signature)
      @patterns ||= []
      raise 'Signature already defined' if get_pattern(signature)

      @patterns << Mustermann.new(signature)
      @patterns.last
    end

    def set_endpoint(path, quick_reply, &block)
      raise 'No block given' unless block_given?

      define_method("#{path}_options", &block)

      settings.apost(path) do
        handle_with_rescue do
          halt 401, 'Invalid Headers' unless authorized?

          get_options = self.class.instance_method "#{path}_options"
          options = get_options.bind(self).call

          halt 400 unless options

          options[:quick_reply] = quick_reply

          handle_request(options)
        end
      end
    end
  end

  register Sinatra::Slack
end