module ActiveNotifier # The third notifier implement module Notifiable extend ActiveSupport::Concern # Core functions for Notifiable module ClassMethods # Message execute. # # @example Command Usage # ActiveNotifier.exec(token: "your-webhook-token", message: "your-message") # @example Common Usage # # Configure it # ActiveNotifier.configure do |config| # config.channel_tokens = { my_channel: "xxx" } # config.template_home = Rails.root.join("app", "views", "active_notifier") # end # # # Add template # echo "## #{data[:title]\n> #{data[:body]}}" > app/views/active_notifier/my_channel.markdown.erb # # # Execute it # ActiveNotifier.exec(:my_channel, data: { title: "Message Title", body: "Message Body" }) # @param channel [#to_sym] (nil) Message channel, it will set template and token_channel together # @param options [#to_h] ({}) # @option options [#to_s] :token (nil) Message webhook token, # @option options [#to_s] :message (nil) Message # @option options [#to_sym] :token_channel (nil) Message webhook token channel, # will use `channel` when this value is blank # @option options [#to_sym] :template (nil) Message template, will use `channel` when this value is blank # @option options [#to_sym] :adapter (ActiveNotifier.config.adapter) Message adapter # @option options [#to_sym] :type (nil) Message type, it will use a specific template file, for example, # when type is :text and template is :order, then ActiveNotifier will choose `order.text.erb` for template file # @option options [#to_h] :data ({}) Message variable data for template, it can used in erb template file # @option options [Anything] Other options will used in adapter message execute, like Dingtalk require title # for message, we can pass it here: `ActiveNotifer.exec(:default, title: "dingtalk title")` # @raise [TemplateNotFoundError] # @raise [UndefinedTokenError] # @raise [AdapterOptionsInvalidError] # @raise [AdapterTypeInvalidError] # @raise [MessageBlankError] # @see Get more see README def exec(channel = nil, **options) channel = channel&.to_sym token = options[:token]&.to_s message = options[:message]&.to_s token_channel = options[:token_channel]&.to_sym template = options[:template]&.to_sym adapter = options[:adapter]&.to_sym type = options[:type]&.to_sym data = options[:data].to_h token = fetch_token(token, token_channel, channel) template ||= channel type ||= get_type_by_template(template) || :text message ||= get_message(template, type, data) adapter_options = options.except(:token, :message, :token_channel, :template, :adapter, :type, :data) adapter ||= ActiveNotifier.config.adapter.to_sym notify(adapter, token, type, message, adapter_options) end private # @param token [String, nil] # @param token_channel [Symbol, nil] # @param channel [Symbol, nil] # @return [String] def fetch_token(token, token_channel, channel) token = token || token_channel && ActiveNotifier.config.channel_tokens[token_channel]&.to_s || channel && ActiveNotifier.config.channel_tokens[channel]&.to_s raise ActiveNotifier::UndefinedTokenError unless token token end # @param template [Symbol, nil] # @return [Symbol, nil] def get_type_by_template(template) return unless template template_paths = Dir["#{ActiveNotifier.config.template_home}/#{template}.*.erb"] raise ActiveNotifier::TemplateNotFoundError if template_paths.empty? types = template_paths.map do |template_path| template_path[%r{#{ActiveNotifier.config.template_home}/#{template}.([a-zA-Z]+).erb}, 1].to_sym end if types.include?(ActiveNotifier.config.priority_type) ActiveNotifier.config.priority_type else types.first end end # @param template [Symbol, nil] # @param type [Symbol] # @param data [Hash] # @return [String] def get_message(template, type, data) return unless template template_data = File.read("#{ActiveNotifier.config.template_home}/#{template}.#{type}.erb") ERB.new(template_data).result_with_hash(data: data) rescue Errno::ENOENT => e raise ActiveNotifier::TemplateNotFoundError, e end # @param adapter [Symbol] # @param token [String] # @param type [Symbol] # @param message [String] # @param adapter_options [Hash] # @return [Response] def notify(adapter, token, type, message, adapter_options) notifier = ActiveNotifier::Notifier.adapt(adapter) notifier.notify(token, type, message, adapter_options) end end end end