defmodule Mix.Tasks.Cairnloop.Gen.Notifier do
@shortdoc "Scaffolds a Cairnloop.Notifier implementation"
@moduledoc """
Scaffolds a Cairnloop.Notifier implementation in your host application
and injects the configuration into `config/config.exs`.
## Examples
mix cairnloop.gen.notifier
"""
use Mix.Task
import Mix.Generator
@doc false
def run(_args) do
if Mix.Project.umbrella?() do
Mix.raise("mix cairnloop.gen.notifier is not supported inside umbrella projects")
end
app = Mix.Project.config()[:app] || :my_app
app_module = Macro.camelize(to_string(app))
assigns = [
app_module: app_module
]
target_file = "lib/#{app}/cairnloop_notifier.ex"
create_file(target_file, notifier_template(assigns))
inject_config(app_module)
Mix.shell().info("""
Done! A new Notifier has been generated at #{target_file}.
Please verify your config/config.exs contains the correct configuration:
config :cairnloop, :notifier, #{app_module}.CairnloopNotifier
""")
end
defp inject_config(app_module) do
config_file = "config/config.exs"
config_snippet = """
# Configure Cairnloop Notifier
config :cairnloop, :notifier, #{app_module}.CairnloopNotifier
"""
if File.exists?(config_file) do
content = File.read!(config_file)
if String.contains?(content, "#{app_module}.CairnloopNotifier") do
Mix.shell().info([
:yellow,
"* skipped ",
:reset,
"config/config.exs (already configured)"
])
else
File.write!(config_file, content <> config_snippet)
Mix.shell().info([:green, "* injecting ", :reset, "config/config.exs"])
end
else
Mix.shell().info([
:yellow,
"* warning ",
:reset,
"could not find config/config.exs to inject configuration. Please add manually:\n#{config_snippet}"
])
end
end
embed_template(:notifier, """
defmodule <%= @app_module %>.CairnloopNotifier do
@moduledoc \"\"\"
A callback handler for Cairnloop events.
\"\"\"
@behaviour Cairnloop.Notifier
require Logger
@impl true
def on_conversation_resolved(conversation, metadata) do
Logger.info("Conversation \#{conversation.id} was resolved. Metadata: \#{inspect(metadata)}")
# Perform durable side-effects here (e.g., sync to CRM, send an email, update host user)
# This runs asynchronously within a transactional Oban worker, retries are handled for you.
:ok
end
@impl true
def on_sla_breach(conversation, sla, _metadata) do
Logger.info("SLA breach for conversation \#{conversation.id}. SLA: \#{inspect(sla)}")
:ok
end
@impl true
def on_outbound_triggered(message, conversation) do
Logger.info("Outbound message triggered for conversation \#{conversation.id}. Template: \#{message.metadata["template_id"]}")
:ok
end
end
""")
end