Packages

Evision Slack integration with Livebook

Current section

Files

Jump to
evision_slack lib evision_slack.ex
Raw

lib/evision_slack.ex

defmodule EvisionSlack.ImageCell do
@moduledoc false
use Kino.JS, assets_path: "lib/assets"
use Kino.JS.Live
use Kino.SmartCell, name: "Evision Image to Slack"
@impl true
def init(attrs, ctx) do
fields = %{
"token_secret_name" => attrs["token_secret_name"] || "",
"channel" => attrs["channel"] || "",
"message" => attrs["message"] || "",
"variable" => attrs["variable"] || ""
}
ctx = assign(ctx, fields: fields)
{:ok, ctx}
end
@impl true
def handle_connect(ctx) do
{:ok, %{fields: ctx.assigns.fields}, ctx}
end
@impl true
def handle_event("update_channel", value, ctx) do
ctx = update(ctx, :fields, &Map.merge(&1, %{"channel" => value}))
{:noreply, ctx}
end
@impl true
def handle_event("update_message", value, ctx) do
ctx = update(ctx, :fields, &Map.merge(&1, %{"message" => value}))
{:noreply, ctx}
end
@impl true
def handle_event("update_variable", value, ctx) do
ctx = update(ctx, :fields, &Map.merge(&1, %{"variable" => value}))
{:noreply, ctx}
end
@impl true
def handle_event("update_token_secret_name", value, ctx) do
broadcast_event(ctx, "update_token_secret_name", value)
ctx = update(ctx, :fields, &Map.merge(&1, %{"token_secret_name" => value}))
{:noreply, ctx}
end
@impl true
def to_attrs(ctx) do
ctx.assigns.fields
end
def quoted_var(nil), do: nil
def quoted_var(string), do: {String.to_atom(string), [], nil}
@impl true
def to_source(attrs) do
required_fields = ~w(token_secret_name channel message variable)
if all_fields_filled?(attrs, required_fields) do
quote do
boundary = "evision_slack_msg"
channel = String.trim("#" <> unquote(attrs["channel"]))
initial_comment = String.trim(unquote(attrs["message"]))
file_data = Evision.imencode(".png", unquote(quoted_var(attrs["variable"])))
filename = "attached#{System.monotonic_time()}.png"
form_data = """
--#{boundary}
Content-Disposition: form-data; name="channels"
#{channel}
--#{boundary}
Content-Disposition: form-data; name="initial_comment"
#{initial_comment}
--#{boundary}
Content-Disposition: form-data; name="file"; filename="#{filename}"
Content-Type: image/png
Content-Transfer-Encoding: binary
#{file_data}
--#{boundary}
Content-Disposition: form-data; name="filetype"
png
--#{boundary}-
"""
req =
Req.new(
base_url: "https://slack.com/api",
auth: {:bearer, System.fetch_env!(unquote("LB_#{attrs["token_secret_name"]}"))}
)
|> Req.Request.put_header("Content-Type", "multipart/form-data; boundary=#{boundary}")
response =
Req.post!(req,
url: "/files.upload",
body: form_data
)
case response.body do
%{"ok" => true} -> :ok
%{"ok" => false, "error" => error} -> {:error, error}
end
end
|> Kino.SmartCell.quoted_to_string()
else
""
end
end
def all_fields_filled?(attrs, keys) do
Enum.all?(keys, fn key -> attrs[key] not in [nil, ""] end)
end
end