Skip to content

Commit

Permalink
Merge pull request #4444 from santiment/add-manual-notification
Browse files Browse the repository at this point in the history
Create manual notification
  • Loading branch information
tspenov authored Oct 30, 2024
2 parents d09cc55 + 083606e commit 4405447
Show file tree
Hide file tree
Showing 7 changed files with 218 additions and 2 deletions.
8 changes: 7 additions & 1 deletion lib/sanbase/ecto_enum.ex
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ defenum(SubscriptionStatusEnum, :status, [

defenum(LangEnum, :lang, ["en", "jp"])

defenum(NotificationActionTypeEnum, :notification_action_type, [:create, :update, :delete, :alert])
defenum(NotificationActionTypeEnum, :notification_action_type, [
:create,
:update,
:delete,
:alert,
:manual
])

defenum(NotificationChannelEnum, :notification_channel, [:discord, :email, :telegram])
defenum(NotificationStatusEnum, :notification_status, [:pending, :completed, :failed])
Expand Down
8 changes: 8 additions & 0 deletions lib/sanbase/notifications/template_renderer.ex
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,14 @@ defmodule Sanbase.Notifications.TemplateRenderer do
alias Sanbase.Notifications.{Notification, NotificationAction}
alias Sanbase.TemplateEngine

def render_content(%Notification{
notification_action: %NotificationAction{action_type: :manual},
content: content
})
when is_binary(content) do
String.trim(content)
end

def render_content(%Notification{
notification_action: %NotificationAction{action_type: action_type},
step: step,
Expand Down
152 changes: 152 additions & 0 deletions lib/sanbase_web/live/notification/manual_notification_live.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
defmodule SanbaseWeb.ManualNotificationLive do
use SanbaseWeb, :live_view

alias Sanbase.Notifications

@channel_discord :discord
@channel_email :email
@valid_channels [@channel_discord, @channel_email]

@impl true
def mount(_params, _session, socket) do
{:ok,
assign(socket,
page_title: "Create Manual Notification",
form:
to_form(
%{
"channels_discord" => "true",
"channels_email" => "false",
"content" => "",
"scheduled_at" => ""
},
as: "notification"
),
notification: nil
)}
end

@impl true
def render(assigns) do
~H"""
<div class="max-w-2xl mx-auto py-8">
<h1 class="text-2xl font-bold mb-6">Create Manual Notification</h1>
<.form for={@form} phx-submit="save" class="space-y-6">
<div>
<.label>Channels</.label>
<div class="mt-2 space-y-2">
<.input
type="checkbox"
field={@form[:channels_discord]}
value="true"
checked
label="Discord"
name="notification[channels_discord]"
/>
<.input
type="checkbox"
field={@form[:channels_email]}
value="true"
label="Email"
name="notification[channels_email]"
/>
</div>
</div>
<div>
<.label>Content</.label>
<.input type="textarea" field={@form[:content]} rows="4" required class="w-full" />
</div>
<div>
<.label>Schedule For (optional)</.label>
<.input type="datetime-local" field={@form[:scheduled_at]} class="w-full" />
</div>
<.button type="submit" phx-disable-with="Creating...">
Create Notification
</.button>
</.form>
<%= if @notification do %>
<div class="mt-6 p-4 bg-green-100 text-green-700 rounded">
Notification created successfully!
</div>
<% end %>
</div>
"""
end

@impl true
def handle_event("save", %{"notification" => notification_params}, socket) do
# Convert the checkbox boolean values to actual channel names
discord_selected? = notification_params["channels_discord"] == "true"
email_selected? = notification_params["channels_email"] == "true"

channels =
[]
|> then(fn list -> if discord_selected?, do: [@channel_discord | list], else: list end)
|> then(fn list -> if email_selected?, do: [@channel_email | list], else: list end)
|> then(fn list -> if list == [], do: [@channel_discord], else: list end)

scheduled_at =
case notification_params["scheduled_at"] do
"" -> DateTime.utc_now()
datetime_str -> parse_datetime(datetime_str)
end

{:ok, notification_action} =
Notifications.create_notification_action(%{
action_type: :manual,
scheduled_at: scheduled_at,
status: :pending,
requires_verification: false,
verified: true
})

{:ok, notification} =
Notifications.create_notification(%{
notification_action_id: notification_action.id,
step: :once,
status: :pending,
scheduled_at: scheduled_at,
channels: channels,
display_in_ui: true,
content: notification_params["content"]
})

{:noreply,
assign(socket,
notification: notification,
form:
to_form(
%{
"channels_discord" => "true",
"channels_email" => "false",
"content" => "",
"scheduled_at" => ""
},
as: "notification"
)
)}
end

defp parse_datetime(datetime_str) do
[date, time] = String.split(datetime_str, "T")
[year, month, day] = String.split(date, "-")
[hour, minute] = String.split(time, ":")

{:ok, datetime} =
NaiveDateTime.new(
String.to_integer(year),
String.to_integer(month),
String.to_integer(day),
String.to_integer(hour),
String.to_integer(minute),
0
)

DateTime.from_naive!(datetime, "Etc/UTC")
end
end
2 changes: 2 additions & 0 deletions lib/sanbase_web/router.ex
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,8 @@ defmodule SanbaseWeb.Router do
live "/notifications/:id", NotificationLive.Show, :show
live "/notifications/:id/show/edit", NotificationLive.Show, :edit

live "/notifications/manual/new", ManualNotificationLive, :new

resources("/reports", ReportController)
resources("/sheets_templates", SheetsTemplateController)
resources("/webinars", WebinarController)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
defmodule Sanbase.Repo.Migrations.AddManualNotificationActionType do
use Ecto.Migration

def up do
execute("ALTER TYPE notification_action_type ADD VALUE IF NOT EXISTS 'manual'")
end

def down do
:ok
end
end
4 changes: 3 additions & 1 deletion priv/repo/structure.sql
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,8 @@ CREATE TYPE public.notification_action_type AS ENUM (
'create',
'update',
'delete',
'alert'
'alert',
'manual'
);


Expand Down Expand Up @@ -9537,3 +9538,4 @@ INSERT INTO public."schema_migrations" (version) VALUES (20241018073651);
INSERT INTO public."schema_migrations" (version) VALUES (20241018075640);
INSERT INTO public."schema_migrations" (version) VALUES (20241029080754);
INSERT INTO public."schema_migrations" (version) VALUES (20241029082533);
INSERT INTO public."schema_migrations" (version) VALUES (20241029151959);
35 changes: 35 additions & 0 deletions test/sanbase/notifications/actions_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,41 @@ defmodule Sanbase.Notifications.ActionsTest do
Sanbase.Notifications.Sender.send_notification(resolved_notification)
end

test "sends manual notification with custom text on Discord" do
custom_text = "Important announcement: System maintenance scheduled for tomorrow"

{:ok, notification_action} =
Notifications.create_notification_action(%{
action_type: :manual,
scheduled_at: DateTime.utc_now(),
status: :pending,
requires_verification: false,
verified: true
})

{:ok, notification} =
Notifications.create_notification(%{
notification_action_id: notification_action.id,
step: :once,
status: :pending,
scheduled_at: DateTime.utc_now(),
channels: [:discord],
display_in_ui: true,
content: custom_text
})

Sanbase.Notifications.MockDiscordClient
|> expect(:send_message, fn _webhook, message, _opts ->
assert String.trim(message) == custom_text
:ok
end)

Sanbase.Notifications.Sender.send_notification(notification)

notification = Notifications.get_notification!(notification.id)
assert notification.status == :completed
end

defp get_scheduled_at(:before), do: DateTime.utc_now()
defp get_scheduled_at(:reminder), do: DateTime.add(DateTime.utc_now(), 3600 * 24 * 27, :second)
defp get_scheduled_at(:after), do: DateTime.add(DateTime.utc_now(), 3600 * 24 * 30, :second)
Expand Down

0 comments on commit 4405447

Please sign in to comment.