Save name and topic events when creating room
This commit is contained in:
parent
7a74440433
commit
3c93ddd768
4 changed files with 119 additions and 76 deletions
|
@ -17,7 +17,7 @@ defmodule MatrixServer.Event do
|
||||||
belongs_to :room, Room, type: :string
|
belongs_to :room, Room, type: :string
|
||||||
end
|
end
|
||||||
|
|
||||||
def new(room_id, sender) do
|
def new(%Room{id: room_id}, sender) do
|
||||||
%Event{
|
%Event{
|
||||||
room_id: room_id,
|
room_id: room_id,
|
||||||
sender: sender,
|
sender: sender,
|
||||||
|
@ -28,9 +28,9 @@ defmodule MatrixServer.Event do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_room(room_id, creator, room_version) do
|
def create_room(room, creator, room_version) do
|
||||||
%Event{
|
%Event{
|
||||||
new(room_id, creator)
|
new(room, creator)
|
||||||
| type: "m.room.create",
|
| type: "m.room.create",
|
||||||
state_key: "",
|
state_key: "",
|
||||||
content: %{
|
content: %{
|
||||||
|
@ -40,9 +40,9 @@ defmodule MatrixServer.Event do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def join(room_id, sender) do
|
def join(room, sender) do
|
||||||
%Event{
|
%Event{
|
||||||
new(room_id, sender)
|
new(room, sender)
|
||||||
| type: "m.room.member",
|
| type: "m.room.member",
|
||||||
state_key: sender,
|
state_key: sender,
|
||||||
content: %{
|
content: %{
|
||||||
|
@ -51,9 +51,9 @@ defmodule MatrixServer.Event do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def power_levels(room_id, sender) do
|
def power_levels(room, sender) do
|
||||||
%Event{
|
%Event{
|
||||||
new(room_id, sender)
|
new(room, sender)
|
||||||
| type: "m.room.power_levels",
|
| type: "m.room.power_levels",
|
||||||
state_key: "",
|
state_key: "",
|
||||||
content: %{
|
content: %{
|
||||||
|
@ -75,9 +75,9 @@ defmodule MatrixServer.Event do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def room_name(room_id, sender, name) do
|
def name(room, sender, name) do
|
||||||
%Event{
|
%Event{
|
||||||
new(room_id, sender)
|
new(room, sender)
|
||||||
| type: "m.room.name",
|
| type: "m.room.name",
|
||||||
state_key: "",
|
state_key: "",
|
||||||
content: %{
|
content: %{
|
||||||
|
@ -86,9 +86,9 @@ defmodule MatrixServer.Event do
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def room_topic(room_id, sender, topic) do
|
def topic(room, sender, topic) do
|
||||||
%Event{
|
%Event{
|
||||||
new(room_id, sender)
|
new(room, sender)
|
||||||
| type: "m.room.topic",
|
| type: "m.room.topic",
|
||||||
state_key: "",
|
state_key: "",
|
||||||
content: %{
|
content: %{
|
||||||
|
@ -122,13 +122,15 @@ defmodule MatrixServer.Event do
|
||||||
# We assume that required keys, as well as in the content, is already validated.
|
# We assume that required keys, as well as in the content, is already validated.
|
||||||
|
|
||||||
# Rule 1.4 is left to changeset validation.
|
# Rule 1.4 is left to changeset validation.
|
||||||
def prevalidate(%Event{
|
def prevalidate(
|
||||||
|
%Event{
|
||||||
type: "m.room.create",
|
type: "m.room.create",
|
||||||
prev_events: prev_events,
|
prev_events: prev_events,
|
||||||
auth_events: auth_events,
|
auth_events: auth_events,
|
||||||
room_id: room_id,
|
room_id: room_id,
|
||||||
sender: sender
|
sender: sender
|
||||||
}) do
|
} = event
|
||||||
|
) do
|
||||||
# TODO: error check on domains?
|
# TODO: error check on domains?
|
||||||
# TODO: rule 1.3
|
# TODO: rule 1.3
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,7 @@ defmodule MatrixServer.Room do
|
||||||
@primary_key {:id, :string, []}
|
@primary_key {:id, :string, []}
|
||||||
schema "rooms" do
|
schema "rooms" do
|
||||||
field :visibility, Ecto.Enum, values: [:public, :private]
|
field :visibility, Ecto.Enum, values: [:public, :private]
|
||||||
|
field :state, :map
|
||||||
field :forward_extremities, {:array, :string}
|
field :forward_extremities, {:array, :string}
|
||||||
has_many :events, Event, foreign_key: :event_id
|
has_many :events, Event, foreign_key: :event_id
|
||||||
end
|
end
|
||||||
|
@ -21,28 +22,24 @@ defmodule MatrixServer.Room do
|
||||||
def create_changeset(%CreateRoom{} = input) do
|
def create_changeset(%CreateRoom{} = input) do
|
||||||
visibility = input.visibility || :public
|
visibility = input.visibility || :public
|
||||||
|
|
||||||
%Room{}
|
%Room{id: generate_room_id(), forward_extremities: [], state: %{}}
|
||||||
|> changeset(%{visibility: visibility})
|
|> changeset(%{visibility: visibility})
|
||||||
|> put_change(:id, generate_room_id())
|
|
||||||
end
|
end
|
||||||
|
|
||||||
def generate_room_id do
|
def generate_room_id do
|
||||||
"!" <> MatrixServer.random_string(18) <> ":" <> MatrixServer.server_name()
|
"!" <> MatrixServer.random_string(18) <> ":" <> MatrixServer.server_name()
|
||||||
end
|
end
|
||||||
|
|
||||||
def update_forward_extremities(%Event{
|
def update_forward_extremities(
|
||||||
|
%Event{
|
||||||
event_id: event_id,
|
event_id: event_id,
|
||||||
prev_events: prev_event_ids,
|
prev_events: prev_event_ids
|
||||||
room_id: room_id
|
},
|
||||||
}) do
|
%Room{id: room_id, forward_extremities: forward_extremities}
|
||||||
%Room{forward_extremities: forward_extremities} =
|
) do
|
||||||
Room
|
|
||||||
|> where([r], r.id == ^room_id)
|
|
||||||
|> Repo.one!()
|
|
||||||
|
|
||||||
new_forward_extremities = [event_id | forward_extremities -- prev_event_ids]
|
new_forward_extremities = [event_id | forward_extremities -- prev_event_ids]
|
||||||
|
|
||||||
{_, [room | _]} =
|
{_, [room]} =
|
||||||
from(r in Room, where: r.id == ^room_id, select: r)
|
from(r in Room, where: r.id == ^room_id, select: r)
|
||||||
|> Repo.update_all(set: [forward_extremities: new_forward_extremities])
|
|> Repo.update_all(set: [forward_extremities: new_forward_extremities])
|
||||||
|
|
||||||
|
|
|
@ -29,28 +29,37 @@ defmodule MatrixServer.RoomServer do
|
||||||
|
|
||||||
@impl true
|
@impl true
|
||||||
def init(opts) do
|
def init(opts) do
|
||||||
%Room{id: room_id} = room = Keyword.fetch!(opts, :room)
|
room = Keyword.fetch!(opts, :room)
|
||||||
input = Keyword.fetch!(opts, :input)
|
input = Keyword.fetch!(opts, :input)
|
||||||
account = Keyword.fetch!(opts, :account)
|
account = Keyword.fetch!(opts, :account)
|
||||||
|
|
||||||
state_set = %{}
|
|
||||||
|
|
||||||
Repo.transaction(fn ->
|
Repo.transaction(fn ->
|
||||||
with {:ok, create_room_event, state_set} <-
|
with {:ok, create_room_id, state_set, room} <-
|
||||||
room_creation_create_room(account, input, room, state_set),
|
room_creation_create_room(account, input, room),
|
||||||
{:ok, join_creator_event, state_set} <-
|
{:ok, join_creator_id, state_set, room} <-
|
||||||
room_creation_join_creator(account, room, state_set, create_room_event),
|
room_creation_join_creator(account, room, state_set, [create_room_id]),
|
||||||
{:ok, _power_levels_event, state_set} <-
|
{:ok, pl_id, state_set, room} <-
|
||||||
room_creation_power_levels(
|
room_creation_power_levels(
|
||||||
account,
|
account,
|
||||||
room,
|
room,
|
||||||
state_set,
|
state_set,
|
||||||
create_room_event,
|
[create_room_id, join_creator_id]
|
||||||
join_creator_event
|
),
|
||||||
) do
|
{:ok, _, state_set, room} <-
|
||||||
{:ok, %{room_id: room_id, state_set: state_set}}
|
room_creation_name(account, input, room, state_set, [
|
||||||
|
create_room_id,
|
||||||
|
join_creator_id,
|
||||||
|
pl_id
|
||||||
|
]),
|
||||||
|
{:ok, _, state_set, room} <-
|
||||||
|
room_creation_topic(account, input, room, state_set, [
|
||||||
|
create_room_id,
|
||||||
|
join_creator_id,
|
||||||
|
pl_id
|
||||||
|
]) do
|
||||||
|
{:ok, %{room: room, state_set: state_set}}
|
||||||
else
|
else
|
||||||
_ -> {:error, :something}
|
_ -> {:error, :validation}
|
||||||
end
|
end
|
||||||
end)
|
end)
|
||||||
end
|
end
|
||||||
|
@ -58,39 +67,71 @@ defmodule MatrixServer.RoomServer do
|
||||||
defp room_creation_create_room(
|
defp room_creation_create_room(
|
||||||
%Account{localpart: localpart},
|
%Account{localpart: localpart},
|
||||||
%CreateRoom{room_version: room_version},
|
%CreateRoom{room_version: room_version},
|
||||||
%Room{id: room_id},
|
room
|
||||||
_state_set
|
|
||||||
) do
|
) do
|
||||||
Event.create_room(room_id, MatrixServer.get_mxid(localpart), room_version)
|
Event.create_room(room, MatrixServer.get_mxid(localpart), room_version)
|
||||||
|> verify_and_insert_event(%{})
|
|> verify_and_insert_event(%{}, room)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp room_creation_join_creator(
|
defp room_creation_join_creator(
|
||||||
%Account{localpart: localpart},
|
%Account{localpart: localpart},
|
||||||
%Room{id: room_id},
|
room,
|
||||||
state_set,
|
state_set,
|
||||||
%Event{event_id: create_room_id}
|
auth_events
|
||||||
) do
|
) do
|
||||||
Event.join(room_id, MatrixServer.get_mxid(localpart))
|
Event.join(room, MatrixServer.get_mxid(localpart))
|
||||||
|> Map.put(:auth_events, [create_room_id])
|
|> Map.put(:auth_events, auth_events)
|
||||||
|> Map.put(:prev_events, [create_room_id])
|
|> verify_and_insert_event(state_set, room)
|
||||||
|> verify_and_insert_event(state_set)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp room_creation_power_levels(
|
defp room_creation_power_levels(
|
||||||
%Account{localpart: localpart},
|
%Account{localpart: localpart},
|
||||||
%Room{id: room_id},
|
room,
|
||||||
state_set,
|
state_set,
|
||||||
%Event{event_id: create_room_id},
|
auth_events
|
||||||
%Event{event_id: join_creator_id}
|
|
||||||
) do
|
) do
|
||||||
Event.power_levels(room_id, MatrixServer.get_mxid(localpart))
|
Event.power_levels(room, MatrixServer.get_mxid(localpart))
|
||||||
|> Map.put(:auth_events, [create_room_id, join_creator_id])
|
|> Map.put(:auth_events, auth_events)
|
||||||
|> Map.put(:prev_events, [join_creator_id])
|
|> verify_and_insert_event(state_set, room)
|
||||||
|> verify_and_insert_event(state_set)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
defp verify_and_insert_event(event, current_state_set) do
|
defp room_creation_name(_, %CreateRoom{name: nil}, room, state_set, _) do
|
||||||
|
{:ok, nil, state_set, room}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp room_creation_name(
|
||||||
|
%Account{localpart: localpart},
|
||||||
|
%CreateRoom{name: name},
|
||||||
|
room,
|
||||||
|
state_set,
|
||||||
|
auth_events
|
||||||
|
) do
|
||||||
|
Event.name(room, MatrixServer.get_mxid(localpart), name)
|
||||||
|
|> Map.put(:auth_events, auth_events)
|
||||||
|
|> verify_and_insert_event(state_set, room)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp room_creation_topic(_, %CreateRoom{topic: nil}, room, state_set, _) do
|
||||||
|
{:ok, nil, state_set, room}
|
||||||
|
end
|
||||||
|
|
||||||
|
defp room_creation_topic(
|
||||||
|
%Account{localpart: localpart},
|
||||||
|
%CreateRoom{topic: topic},
|
||||||
|
room,
|
||||||
|
state_set,
|
||||||
|
auth_events
|
||||||
|
) do
|
||||||
|
Event.topic(room, MatrixServer.get_mxid(localpart), topic)
|
||||||
|
|> Map.put(:auth_events, auth_events)
|
||||||
|
|> verify_and_insert_event(state_set, room)
|
||||||
|
end
|
||||||
|
|
||||||
|
defp verify_and_insert_event(
|
||||||
|
%Event{event_id: event_id} = event,
|
||||||
|
current_state_set,
|
||||||
|
%Room{forward_extremities: forward_extremities} = room
|
||||||
|
) do
|
||||||
# Check the following things:
|
# Check the following things:
|
||||||
# 1. TODO: Is a valid event, otherwise it is dropped.
|
# 1. TODO: Is a valid event, otherwise it is dropped.
|
||||||
# 2. TODO: Passes signature checks, otherwise it is dropped.
|
# 2. TODO: Passes signature checks, otherwise it is dropped.
|
||||||
|
@ -98,6 +139,8 @@ defmodule MatrixServer.RoomServer do
|
||||||
# 4. Passes authorization rules based on the event's auth events, otherwise it is rejected.
|
# 4. Passes authorization rules based on the event's auth events, otherwise it is rejected.
|
||||||
# 5. Passes authorization rules based on the state at the event, otherwise it is rejected.
|
# 5. Passes authorization rules based on the state at the event, otherwise it is rejected.
|
||||||
# 6. Passes authorization rules based on the current state of the room, otherwise it is "soft failed".
|
# 6. Passes authorization rules based on the current state of the room, otherwise it is "soft failed".
|
||||||
|
event = %Event{event | prev_events: forward_extremities}
|
||||||
|
|
||||||
if Event.prevalidate(event) do
|
if Event.prevalidate(event) do
|
||||||
if StateResolution.is_authorized_by_auth_events(event) do
|
if StateResolution.is_authorized_by_auth_events(event) do
|
||||||
state_set = StateResolution.resolve(event, false)
|
state_set = StateResolution.resolve(event, false)
|
||||||
|
@ -105,10 +148,10 @@ defmodule MatrixServer.RoomServer do
|
||||||
if StateResolution.is_authorized(event, state_set) do
|
if StateResolution.is_authorized(event, state_set) do
|
||||||
if StateResolution.is_authorized(event, current_state_set) do
|
if StateResolution.is_authorized(event, current_state_set) do
|
||||||
# We assume here that the event is always a forward extremity.
|
# We assume here that the event is always a forward extremity.
|
||||||
Room.update_forward_extremities(event)
|
room = Room.update_forward_extremities(event, room)
|
||||||
{:ok, event} = Repo.insert(event)
|
{:ok, event} = Repo.insert(event)
|
||||||
state_set = StateResolution.resolve_forward_extremities(event)
|
state_set = StateResolution.resolve_forward_extremities(event)
|
||||||
{:ok, event, state_set}
|
{:ok, event_id, state_set, room}
|
||||||
else
|
else
|
||||||
{:error, :soft_failed}
|
{:error, :soft_failed}
|
||||||
end
|
end
|
||||||
|
@ -125,6 +168,6 @@ defmodule MatrixServer.RoomServer do
|
||||||
|
|
||||||
def testing do
|
def testing do
|
||||||
account = Repo.one!(from a in Account, limit: 1)
|
account = Repo.one!(from a in Account, limit: 1)
|
||||||
create_room(%CreateRoom{}, account)
|
create_room(%CreateRoom{name: "Sneed", topic: "City slickers"}, account)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -14,19 +14,20 @@ Repo.insert(%Device{
|
||||||
# Auth difference example from here:
|
# Auth difference example from here:
|
||||||
# https://matrix.org/docs/guides/implementing-stateres#auth-differences
|
# https://matrix.org/docs/guides/implementing-stateres#auth-differences
|
||||||
|
|
||||||
Repo.insert!(%Room{
|
room =
|
||||||
|
Repo.insert!(%Room{
|
||||||
id: "room1",
|
id: "room1",
|
||||||
visibility: :public
|
visibility: :public
|
||||||
})
|
})
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
Event.create_room("room1", "alice", "v1")
|
Event.create_room(room, "alice", "v1")
|
||||||
|> Map.put(:origin_server_ts, 0)
|
|> Map.put(:origin_server_ts, 0)
|
||||||
|> Map.put(:event_id, "create")
|
|> Map.put(:event_id, "create")
|
||||||
)
|
)
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
Event.join("room1", "alice")
|
Event.join(room, "alice")
|
||||||
|> Map.put(:prev_events, ["create"])
|
|> Map.put(:prev_events, ["create"])
|
||||||
|> Map.put(:auth_events, ["create"])
|
|> Map.put(:auth_events, ["create"])
|
||||||
|> Map.put(:origin_server_ts, 1)
|
|> Map.put(:origin_server_ts, 1)
|
||||||
|
@ -34,7 +35,7 @@ Repo.insert!(
|
||||||
)
|
)
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
Event.join("room1", "bob")
|
Event.join(room, "bob")
|
||||||
|> Map.put(:prev_events, ["join_alice"])
|
|> Map.put(:prev_events, ["join_alice"])
|
||||||
|> Map.put(:auth_events, ["create"])
|
|> Map.put(:auth_events, ["create"])
|
||||||
|> Map.put(:origin_server_ts, 2)
|
|> Map.put(:origin_server_ts, 2)
|
||||||
|
@ -42,14 +43,14 @@ Repo.insert!(
|
||||||
)
|
)
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
Event.join("room1", "charlie")
|
Event.join(room, "charlie")
|
||||||
|> Map.put(:prev_events, ["join_bob"])
|
|> Map.put(:prev_events, ["join_bob"])
|
||||||
|> Map.put(:auth_events, ["create"])
|
|> Map.put(:auth_events, ["create"])
|
||||||
|> Map.put(:origin_server_ts, 3)
|
|> Map.put(:origin_server_ts, 3)
|
||||||
|> Map.put(:event_id, "join_charlie")
|
|> Map.put(:event_id, "join_charlie")
|
||||||
)
|
)
|
||||||
|
|
||||||
%Event{content: content} = event = Event.power_levels("room1", "alice")
|
%Event{content: content} = event = Event.power_levels(room, "alice")
|
||||||
event = %Event{event | content: %{content | "users" => %{"alice" => 100, "bob" => 100}}}
|
event = %Event{event | content: %{content | "users" => %{"alice" => 100, "bob" => 100}}}
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
|
@ -60,7 +61,7 @@ Repo.insert!(
|
||||||
|> Map.put(:event_id, "a")
|
|> Map.put(:event_id, "a")
|
||||||
)
|
)
|
||||||
|
|
||||||
%Event{content: content} = event = Event.power_levels("room1", "bob")
|
%Event{content: content} = event = Event.power_levels(room, "bob")
|
||||||
|
|
||||||
event = %Event{
|
event = %Event{
|
||||||
event
|
event
|
||||||
|
@ -76,7 +77,7 @@ Repo.insert!(
|
||||||
)
|
)
|
||||||
|
|
||||||
Repo.insert!(
|
Repo.insert!(
|
||||||
Event.room_topic("room1", "alice", "sneed")
|
Event.topic(room, "alice", "sneed")
|
||||||
|> Map.put(:prev_events, ["a"])
|
|> Map.put(:prev_events, ["a"])
|
||||||
|> Map.put(:auth_events, ["create", "join_alice", "a"])
|
|> Map.put(:auth_events, ["create", "join_alice", "a"])
|
||||||
|> Map.put(:origin_server_ts, 5)
|
|> Map.put(:origin_server_ts, 5)
|
||||||
|
|
Loading…
Reference in a new issue