cover/Elixir.WalletNotifications.Preference.html

1 defmodule WalletNotifications.Preference do
2 @moduledoc """
3 Per-user, per-channel notification preference.
4
5 Controls whether a user receives notifications on a given channel
6 and allows defining suppression rules (quiet hours, opt-outs).
7
8 Suppression rules map — keys:
9 - `:quiet_hours` — `%{start_hour: 22, end_hour: 7}` (local time)
10 - `:opt_out_types` — list of notification types to suppress, e.g. `[:promotional]`
11 - `:daily_limit` — max notifications per day on this channel (integer | nil)
12 """
13
14 @enforce_keys [:user_id, :channel, :enabled]
15
:-(
defstruct [
16 :user_id,
17 :channel,
18 :updated_at,
19 enabled: true,
20 suppression_rules: %{}
21 ]
22
23 @type t :: %__MODULE__{
24 user_id: String.t(),
25 channel: atom(),
26 enabled: boolean(),
27 suppression_rules: map(),
28 updated_at: DateTime.t() | nil
29 }
30
31 @doc "Creates or overwrites a user preference for a channel."
32 @spec new(user_id :: String.t(), channel :: atom(), opts :: keyword()) :: t()
33 2 def new(user_id, channel, opts \\ []) do
34 16 %__MODULE__{
35 user_id: user_id,
36 channel: channel,
37 enabled: Keyword.get(opts, :enabled, true),
38 suppression_rules: Keyword.get(opts, :suppression_rules, %{}),
39 updated_at: DateTime.utc_now()
40 }
41 end
42
43 @doc "Returns true if notifications should be sent (enabled + not suppressed)."
44 @spec allowed?(t(), notification_type :: atom()) :: boolean()
45 2 def allowed?(%__MODULE__{enabled: false}, _type), do: false
46 def allowed?(%__MODULE__{suppression_rules: rules}, type) do
47 6 opt_out_types = Map.get(rules, :opt_out_types, [])
48 6 type not in opt_out_types
49 end
50 end
Line Hits Source