Skip to content

Commit cfb3167

Browse files
committed
apply PR feedback
1 parent 7cfdb77 commit cfb3167

File tree

8 files changed

+155
-152
lines changed

8 files changed

+155
-152
lines changed
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
defmodule RealtimeWeb.Channels.Payloads.Broadcast do
2+
@moduledoc """
3+
Validate broadcast field of the join payload.
4+
"""
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias RealtimeWeb.Channels.Payloads.Join
8+
9+
embedded_schema do
10+
field :ack, :boolean, default: false
11+
field :self, :boolean, default: false
12+
end
13+
14+
def changeset(broadcast, attrs) do
15+
cast(broadcast, attrs, [:ack, :self], message: &Join.error_message/2)
16+
end
17+
end
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
defmodule RealtimeWeb.Channels.Payloads.Config do
2+
@moduledoc """
3+
Validate config field of the join payload.
4+
"""
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias RealtimeWeb.Channels.Payloads.Join
8+
alias RealtimeWeb.Channels.Payloads.Broadcast
9+
alias RealtimeWeb.Channels.Payloads.Presence
10+
alias RealtimeWeb.Channels.Payloads.PostgresChange
11+
12+
embedded_schema do
13+
embeds_one :broadcast, Broadcast
14+
embeds_one :presence, Presence
15+
embeds_many :postgres_changes, PostgresChange
16+
field :private, :boolean, default: false
17+
end
18+
19+
def changeset(config, attrs) do
20+
config
21+
|> cast(attrs, [:private], message: &Join.error_message/2)
22+
|> cast_embed(:broadcast, invalid_message: "unable to parse, expected a map")
23+
|> cast_embed(:presence, invalid_message: "unable to parse, expected a map")
24+
|> cast_embed(:postgres_changes, invalid_message: "unable to parse, expected an array of maps")
25+
end
26+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
defmodule RealtimeWeb.Channels.Payloads.Join do
2+
@moduledoc """
3+
Payload validation for the phx_join event.
4+
"""
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias RealtimeWeb.Channels.Payloads.Config
8+
alias RealtimeWeb.Channels.Payloads.Broadcast
9+
alias RealtimeWeb.Channels.Payloads.Presence
10+
11+
embedded_schema do
12+
embeds_one :config, Config
13+
field :access_token, :string
14+
field :user_token, :string
15+
end
16+
17+
def changeset(join, attrs) do
18+
join
19+
|> cast(attrs, [:access_token, :user_token], message: &error_message/2)
20+
|> cast_embed(:config, invalid_message: "unable to parse, expected a map")
21+
end
22+
23+
@spec validate(map()) :: {:ok, %__MODULE__{}} | {:error, :invalid_join_payload, map()}
24+
def validate(params) do
25+
case changeset(%__MODULE__{}, params) do
26+
%Ecto.Changeset{valid?: true} = changeset ->
27+
{:ok, Ecto.Changeset.apply_changes(changeset)}
28+
29+
%Ecto.Changeset{valid?: false} = changeset ->
30+
errors = Ecto.Changeset.traverse_errors(changeset, &elem(&1, 0))
31+
{:error, :invalid_join_payload, errors}
32+
end
33+
end
34+
35+
def presence_enabled?(%__MODULE__{config: %Config{presence: %Presence{enabled: enabled}}}), do: enabled
36+
def presence_enabled?(_), do: true
37+
38+
def presence_key(%__MODULE__{config: %Config{presence: %Presence{key: ""}}}), do: UUID.uuid1()
39+
def presence_key(%__MODULE__{config: %Config{presence: %Presence{key: key}}}), do: key
40+
def presence_key(_), do: UUID.uuid1()
41+
42+
def ack_broadcast?(%__MODULE__{config: %Config{broadcast: %Broadcast{ack: ack}}}), do: ack
43+
def ack_broadcast?(_), do: false
44+
45+
def self_broadcast?(%__MODULE__{config: %Config{broadcast: %Broadcast{self: self}}}), do: self
46+
def self_broadcast?(_), do: false
47+
48+
def private?(%__MODULE__{config: %Config{private: private}}), do: private
49+
def private?(_), do: false
50+
51+
def error_message(_field, meta) do
52+
type = Keyword.get(meta, :type)
53+
54+
if type,
55+
do: "unable to parse, expected #{type}",
56+
else: "unable to parse"
57+
end
58+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
defmodule RealtimeWeb.Channels.Payloads.PostgresChange do
2+
@moduledoc """
3+
Validate postgres_changes field of the join payload.
4+
"""
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias RealtimeWeb.Channels.Payloads.Join
8+
9+
embedded_schema do
10+
field :event, :string
11+
field :schema, :string
12+
field :table, :string
13+
field :filter, :string
14+
end
15+
16+
def changeset(postgres_change, attrs) do
17+
cast(postgres_change, attrs, [:event, :schema, :table, :filter], message: &Join.error_message/2)
18+
end
19+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
defmodule RealtimeWeb.Channels.Payloads.Presence do
2+
@moduledoc """
3+
Validate presence field of the join payload.
4+
"""
5+
use Ecto.Schema
6+
import Ecto.Changeset
7+
alias RealtimeWeb.Channels.Payloads.Join
8+
9+
embedded_schema do
10+
field :enabled, :boolean, default: true
11+
field :key, :string, default: UUID.uuid1()
12+
end
13+
14+
def changeset(presence, attrs) do
15+
cast(presence, attrs, [:enabled, :key], message: &Join.error_message/2)
16+
end
17+
end

lib/realtime_web/channels/realtime_channel.ex

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,9 +21,9 @@ defmodule RealtimeWeb.RealtimeChannel do
2121
alias Realtime.Tenants.Authorization.Policies.PresencePolicies
2222
alias Realtime.Tenants.Connect
2323

24-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join
25-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config
26-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config.PostgresChange
24+
alias RealtimeWeb.Channels.Payloads.Join
25+
alias RealtimeWeb.Channels.Payloads.Config
26+
alias RealtimeWeb.Channels.Payloads.PostgresChange
2727
alias RealtimeWeb.ChannelsAuthorization
2828
alias RealtimeWeb.RealtimeChannel.BroadcastHandler
2929
alias RealtimeWeb.RealtimeChannel.MessageDispatcher
@@ -555,9 +555,9 @@ defmodule RealtimeWeb.RealtimeChannel do
555555

556556
access_token =
557557
cond do
558-
access_token != nil and !String.starts_with?(access_token, "sb_") -> access_token
559-
user_token != nil and !String.starts_with?(user_token, "sb_") -> user_token
560-
tenant_token != nil and !String.starts_with?(tenant_token, "sb_") -> tenant_token
558+
is_binary(access_token) and !String.starts_with?(access_token, "sb_") -> access_token
559+
is_binary(user_token) and !String.starts_with?(user_token, "sb_") -> user_token
560+
is_binary(tenant_token) and !String.starts_with?(tenant_token, "sb_") -> tenant_token
561561
true -> header
562562
end
563563

lib/realtime_web/channels/realtime_channel/payloads/join.ex

Lines changed: 0 additions & 140 deletions
This file was deleted.

test/realtime_web/channels/realtime_channel/payloads/join_test.exs renamed to test/realtime_web/channels/payloads/join_test.exs

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
defmodule RealtimeWeb.Channels.RealtimeChannel.Payloads.JoinTest do
1+
defmodule RealtimeWeb.Channels.Payloads.JoinTest do
22
use ExUnit.Case
33

44
import Generators
55

6-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join
7-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config
8-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config.Broadcast
9-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config.Presence
10-
alias RealtimeWeb.Channels.RealtimeChannel.Payloads.Join.Config.PostgresChange
6+
alias RealtimeWeb.Channels.Payloads.Join
7+
alias RealtimeWeb.Channels.Payloads.Config
8+
alias RealtimeWeb.Channels.Payloads.Broadcast
9+
alias RealtimeWeb.Channels.Payloads.Presence
10+
alias RealtimeWeb.Channels.Payloads.PostgresChange
1111

1212
describe "validate/1" do
1313
test "valid payload allows join" do
@@ -56,6 +56,12 @@ defmodule RealtimeWeb.Channels.RealtimeChannel.Payloads.JoinTest do
5656
assert is_binary(key)
5757
end
5858

59+
test "missing enabled presence defaults to true" do
60+
config = %{"config" => %{"presence" => %{}}}
61+
62+
assert {:ok, %Join{config: %Config{presence: %Presence{enabled: true}}}} = Join.validate(config)
63+
end
64+
5965
test "invalid payload returns errors" do
6066
config = %{"config" => ["test"]}
6167

0 commit comments

Comments
 (0)