Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Interpolates messages with variables #4

Merged
merged 11 commits into from
Mar 17, 2023
22 changes: 20 additions & 2 deletions lib/kino_slack/message_cell.ex
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ defmodule KinoSlack.MessageCell do
@impl true
def to_source(attrs) do
required_fields = ~w(token_secret_name channel message)
interpolated_message = interpolate(attrs["message"])

if all_fields_filled?(attrs, required_fields) do
quote do
Expand All @@ -63,7 +64,7 @@ defmodule KinoSlack.MessageCell do
url: "/chat.postMessage",
json: %{
channel: unquote(attrs["channel"]),
text: unquote(attrs["message"])
text: unquote(interpolated_message)
}
)

Expand All @@ -78,7 +79,24 @@ defmodule KinoSlack.MessageCell do
end
end

def all_fields_filled?(attrs, keys) do
defp interpolate(message) do
~r/(?<before_interpolation>){{[^}]+}}(?<after_interpolation>)/
hugobarauna marked this conversation as resolved.
Show resolved Hide resolved
|> Regex.split(message, on: [:before_interpolation, :after_interpolation])
|> Enum.map(fn message_chunk ->
case Regex.named_captures(~r/{{(?<var_name>.*)}}/, message_chunk) do
%{"var_name" => var_name} ->
"\#{#{var_name}}"

_ ->
message_chunk
end
end)
|> Enum.join()
|> then(fn message -> "\"" <> message <> "\"" end)
|> Code.string_to_quoted!()
end

defp all_fields_filled?(attrs, keys) do
Enum.all?(keys, fn key -> attrs[key] not in [nil, ""] end)
end
end
41 changes: 41 additions & 0 deletions test/kino_slack/message_cell_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,47 @@ defmodule KinoSlack.MessageCellTest do
assert generated_code == expected_code
end

test "generates source code with variable interpolation" do
{kino, _source} = start_smart_cell!(MessageCell, %{})

push_event(kino, "update_token_secret_name", "SLACK_TOKEN")
push_event(kino, "update_channel", "#slack-channel")
push_event(kino, "update_message", "Hello {{first_name}} {{last_name}}!")

assert_smart_cell_update(
kino,
%{
"token_secret_name" => "SLACK_TOKEN",
"channel" => "#slack-channel",
"message" => "Hello {{first_name}} {{last_name}}!"
},
generated_code
)

expected_code = ~S"""
req =
Req.new(
base_url: "https://slack.com/api",
auth: {:bearer, System.fetch_env!("LB_SLACK_TOKEN")}
)

response =
Req.post!(req,
url: "/chat.postMessage",
json: %{channel: "#slack-channel", text: "Hello #{first_name} #{last_name}!"}
)

case response.body do
%{"ok" => true} -> :ok
%{"ok" => false, "error" => error} -> {:error, error}
end
"""

expected_code = String.trim(expected_code)

assert generated_code == expected_code
end

test "generates source code from stored attributes" do
stored_attrs = %{
"token_secret_name" => "SLACK_TOKEN",
Expand Down