esigler/lita-zerocater

View on GitHub
lib/lita/handlers/zerocater.rb

Summary

Maintainability
A
0 mins
Test Coverage
# frozen_string_literal: true

require_relative 'icons'

module Lita
  module Handlers
    class Zerocater < Handler
      config :locations, type: Hash, required: true

      route(
        /^zerocater\s(?<date>today|tomorrow|yesterday)$/,
        :menu,
        command: true,
        help: {
          t('help.menu.syntax') => t('help.menu.desc')
        }
      )

      route(
        /^(breakfast|brunch|lunch|dinner)$/i,
        :alias,
        command: true,
        help: {
          t('help.alias.syntax') => t('help.alias.desc')
        }
      )

      # rubocop:disable Metrics/MethodLength
      def menu(response)
        search_date = case response.match_data['date']
                      when 'tomorrow'
                        Date.today + 1
                      when 'yesterday'
                        Date.today - 1
                      else
                        Date.today
                      end

        config.locations.each_key do |location|
          response.reply(fetch_menu(location, search_date))
        end
      end
      # rubocop:enable Metrics/MethodLength

      def alias(response)
        config.locations.each_key do |location|
          response.reply(fetch_menu(location, Date.today))
        end
      end

      private

      def fetch_meal(id)
        JSON.parse(http.get("https://api.zerocater.com/v3/meals/#{id}").body)
      end

      def fetch_meals(location)
        JSON.parse(
          http.get("https://api.zerocater.com/v3/companies/#{location}/meals")
          .body
        )
      end

      def fetch_menu(location, search_date)
        cache_key = "#{location}_#{search_date}"
        return redis.get(cache_key) if redis.exists(cache_key)

        menu = render_menu(location, search_date)
        redis.set(cache_key, menu, ex: 300)

        menu
      end

      def find_meals(meals, search_date)
        results = []

        meals.each do |item|
          results << item['id'] if Time.at(item['time']).to_date == search_date
        end

        results
      end

      def find_menu(location, search_date)
        results = find_meals(fetch_meals(location), search_date)
        meals = []

        results.each do |result|
          m = fetch_meal(result)
          meals << m
        end

        meals
      end

      # append emoji icons based on item labels
      def append_icons(item)
        labels = get_label_icons(item)
        # if it's vegan, it's necessarily vegetarian. Remove redundant icon.
        if labels.include?(ICONS['vegetarian']) &&
           labels.include?(ICONS['vegan'])
          labels.delete_at(labels.index(ICONS['vegetarian']))
        end
        labels.empty? ? item['name'] : item['name'] << ' | ' << labels.join(' ')
      end

      def get_label_icons(item)
        labels = item['labels'].select do |label, value|
          value['value'] == true && ICONS.key?(label)
        end
        labels.map { |label, _| ICONS[label] }
      end

      def render_menu(location, search_date)
        menu = find_menu(config.locations[location], search_date)
        return t('error.empty') if menu.empty?

        items = menu.map { |m| m['items'].map { |item| append_icons(item) } }
        render_template('menu',
                        menu: menu,
                        items: items,
                        locale: t('menu.locale', location: location))
      rescue StandardError
        t('error.retrieve')
      end
    end

    Lita.register_handler(Zerocater)
  end
end