From 5bc39a1a9da055c88d87c6ad0c7ae804bc37edbe Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:25:36 +0000 Subject: [PATCH 1/4] Initial plan From ac8559ab95c3b4565d68a6da4add7c354ca4ac11 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:37:05 +0000 Subject: [PATCH 2/4] Implement email template extraction and reading functionality Co-authored-by: dthaler <6547784+dthaler@users.noreply.github.com> --- server/lib/orcasite/notifications/email.ex | 143 +----------------- .../templates/confirmed_candidate.mjml.eex | 64 ++++++++ .../templates/new_detection.mjml.eex | 68 +++++++++ 3 files changed, 139 insertions(+), 136 deletions(-) create mode 100644 server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex create mode 100644 server/lib/orcasite/notifications/templates/new_detection.mjml.eex diff --git a/server/lib/orcasite/notifications/email.ex b/server/lib/orcasite/notifications/email.ex index 802b9d53f..07931816c 100644 --- a/server/lib/orcasite/notifications/email.ex +++ b/server/lib/orcasite/notifications/email.ex @@ -28,76 +28,7 @@ defmodule Orcasite.Notifications.Email do url(~p"/s/subscription/unsubscribe?token=#{assigns.unsubscribe_token}") ) - """ - - - - - - - A new detection has been submitted at {{ node_name }} ({{ node }})! - - - - Description: {{#if meta["description"]}}{{ meta["description"] }}{{else}}(no description){{/if}} - - {{#if meta["listener_count"] }} - - Listeners: {{ meta["listener_count"] }} - - {{/if}} - {{#if meta["candidate_id"] }} - - Review here: {{ meta["candidate_id"] }} - - {{/if}} - {{#if node && meta["start_time"] && meta["category"] }} - - Start a new bout - - {{/if}} - - {{#if notifications_since_count > 0}} - - There have been {{ notifications_since_count }} other detections since the last notification. - - - - Feed - # - Description - Action - - {{#each notifications_since as |notif_meta|}} - - {{ notif_meta["node"] }} - {{ notif_meta["listener_count"] }} - {{ notif_meta["description"] }} - - {{#if notif_meta["candidate_id"] }} - Review - {{/if}} - - - {{/each}} - - {{/if}} - - - - Listen here: https://live.orcasound.net/listen/{{ node }} - - - {{#if unsubscribe_token }} - - If you no longer wish to receive these emails, you can unsubscribe. - - {{/if}} - - - - - """ + read_template("new_detection") |> compile_mjml(assigns) end @@ -109,72 +40,7 @@ defmodule Orcasite.Notifications.Email do url(~p"/s/subscription/unsubscribe?token=#{assigns.unsubscribe_token}") ) - """ - - - - - - - - - - - - - {{ meta["message"] }} - - - - - - - - - LISTEN NOW! - - - - - - - If you miss the concert,
watch the Orcasound blog for recordings & bioacoustic analysis! -
-
-
- - - - - - If you encounter whales at sea, Be Whale Wise.
- Know the laws and best practices in both the U.S. and Canada. -
- - - - - Copyright © 2023 Orcasound, All rights reserved.
- You are receiving this email because you opted in via our website. -
- - Our mailing address is:
- Orcasound
- 7044 17th Ave NE
- Seattle, WA 98115-5739 -
- {{#if unsubscribe_token }} - - If you no longer wish to receive these emails,
- you can unsubscribe. -
- {{/if}} -
-
- -
-
- """ + read_template("confirmed_candidate") |> compile_mjml(assigns) end @@ -199,6 +65,11 @@ defmodule Orcasite.Notifications.Email do ) end + defp read_template(name) do + Path.expand("lib/orcasite/notifications/templates/#{name}.mjml.eex") + |> File.read!() + end + def compile_mjml(mjml, assigns) do mjml |> Zappa.compile!() diff --git a/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex b/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex new file mode 100644 index 000000000..1dfef4c5a --- /dev/null +++ b/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex @@ -0,0 +1,64 @@ + + + + + + + + + + + + + {{ meta["message"] }} + + + + + + + + + LISTEN NOW! + + + + + + + If you miss the concert,
watch the Orcasound blog for recordings & bioacoustic analysis! +
+
+
+ + + + + + If you encounter whales at sea, Be Whale Wise.
+ Know the laws and best practices in both the U.S. and Canada. +
+ + + + + Copyright © 2023 Orcasound, All rights reserved.
+ You are receiving this email because you opted in via our website. +
+ + Our mailing address is:
+ Orcasound
+ 7044 17th Ave NE
+ Seattle, WA 98115-5739 +
+ {{#if unsubscribe_token }} + + If you no longer wish to receive these emails,
+ you can unsubscribe. +
+ {{/if}} +
+
+ +
+
\ No newline at end of file diff --git a/server/lib/orcasite/notifications/templates/new_detection.mjml.eex b/server/lib/orcasite/notifications/templates/new_detection.mjml.eex new file mode 100644 index 000000000..558eb81b4 --- /dev/null +++ b/server/lib/orcasite/notifications/templates/new_detection.mjml.eex @@ -0,0 +1,68 @@ + + + + + + + A new detection has been submitted at {{ node_name }} ({{ node }})! + + + + Description: {{#if meta["description"]}}{{ meta["description"] }}{{else}}(no description){{/if}} + + {{#if meta["listener_count"] }} + + Listeners: {{ meta["listener_count"] }} + + {{/if}} + {{#if meta["candidate_id"] }} + + Review here: {{ meta["candidate_id"] }} + + {{/if}} + {{#if node && meta["start_time"] && meta["category"] }} + + Start a new bout + + {{/if}} + + {{#if notifications_since_count > 0}} + + There have been {{ notifications_since_count }} other detections since the last notification. + + + + Feed + # + Description + Action + + {{#each notifications_since as |notif_meta|}} + + {{ notif_meta["node"] }} + {{ notif_meta["listener_count"] }} + {{ notif_meta["description"] }} + + {{#if notif_meta["candidate_id"] }} + Review + {{/if}} + + + {{/each}} + + {{/if}} + + + + Listen here: https://live.orcasound.net/listen/{{ node }} + + + {{#if unsubscribe_token }} + + If you no longer wish to receive these emails, you can unsubscribe. + + {{/if}} + + + + \ No newline at end of file From a5e61a7f393517cb0541197a2d20fa5441eae985 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Wed, 17 Sep 2025 15:41:38 +0000 Subject: [PATCH 3/4] Complete email template implementation with tests and validation Co-authored-by: dthaler <6547784+dthaler@users.noreply.github.com> --- .../notifications/email_template_test.exs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 server/test/orcasite/notifications/email_template_test.exs diff --git a/server/test/orcasite/notifications/email_template_test.exs b/server/test/orcasite/notifications/email_template_test.exs new file mode 100644 index 000000000..3a1e66b5d --- /dev/null +++ b/server/test/orcasite/notifications/email_template_test.exs @@ -0,0 +1,40 @@ +defmodule Orcasite.Notifications.EmailTemplateTest do + use ExUnit.Case + + describe "email templates" do + test "new_detection template exists and is readable" do + template_path = Path.expand("lib/orcasite/notifications/templates/new_detection.mjml.eex") + assert File.exists?(template_path), "new_detection template file should exist" + + {:ok, content} = File.read(template_path) + assert String.length(content) > 0, "template should not be empty" + assert String.contains?(content, ""), "template should contain MJML structure" + assert String.contains?(content, "A new detection has been submitted"), "template should contain expected content" + end + + test "confirmed_candidate template exists and is readable" do + template_path = Path.expand("lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex") + assert File.exists?(template_path), "confirmed_candidate template file should exist" + + {:ok, content} = File.read(template_path) + assert String.length(content) > 0, "template should not be empty" + assert String.contains?(content, ""), "template should contain MJML structure" + assert String.contains?(content, "LISTEN NOW!"), "template should contain expected content" + end + + test "templates contain required variables" do + # Test new_detection template variables + {:ok, new_detection_content} = File.read(Path.expand("lib/orcasite/notifications/templates/new_detection.mjml.eex")) + assert String.contains?(new_detection_content, "{{ node_name }}"), "should contain node_name variable" + assert String.contains?(new_detection_content, "{{ node }}"), "should contain node variable" + assert String.contains?(new_detection_content, "meta[\"description\"]"), "should contain description variable" + assert String.contains?(new_detection_content, "{{unsubscribe_url}}"), "should contain unsubscribe_url variable" + + # Test confirmed_candidate template variables + {:ok, confirmed_candidate_content} = File.read(Path.expand("lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex")) + assert String.contains?(confirmed_candidate_content, "{{ node }}"), "should contain node variable" + assert String.contains?(confirmed_candidate_content, "meta[\"message\"]"), "should contain message variable" + assert String.contains?(confirmed_candidate_content, "{{ unsubscribe_url }}"), "should contain unsubscribe_url variable" + end + end +end \ No newline at end of file From eb7c76d91db20e7d875707f520d62373e0c17691 Mon Sep 17 00:00:00 2001 From: Dave Thaler Date: Wed, 17 Sep 2025 11:14:35 -0700 Subject: [PATCH 4/4] Update server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- .../notifications/templates/confirmed_candidate.mjml.eex | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex b/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex index 1dfef4c5a..c1f5b7df6 100644 --- a/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex +++ b/server/lib/orcasite/notifications/templates/confirmed_candidate.mjml.eex @@ -19,7 +19,7 @@ - LISTEN NOW! + LISTEN NOW!