Save preset events when creating room

This commit is contained in:
Pim Kunis 2021-07-27 12:55:36 +02:00
parent 3c93ddd768
commit dc12575923
4 changed files with 160 additions and 60 deletions

View file

@ -3,7 +3,7 @@ defmodule MatrixServer.Event do
import Ecto.Query import Ecto.Query
alias MatrixServer.{Repo, Room, Event} alias MatrixServer.{Repo, Room, Event, Account}
@primary_key {:event_id, :string, []} @primary_key {:event_id, :string, []}
schema "events" do schema "events" do
@ -17,10 +17,10 @@ defmodule MatrixServer.Event do
belongs_to :room, Room, type: :string belongs_to :room, Room, type: :string
end end
def new(%Room{id: room_id}, sender) do def new(%Room{id: room_id}, %Account{localpart: localpart}) do
%Event{ %Event{
room_id: room_id, room_id: room_id,
sender: sender, sender: MatrixServer.get_mxid(localpart),
event_id: generate_event_id(), event_id: generate_event_id(),
origin_server_ts: DateTime.utc_now() |> DateTime.to_unix(), origin_server_ts: DateTime.utc_now() |> DateTime.to_unix(),
prev_events: [], prev_events: [],
@ -28,30 +28,36 @@ defmodule MatrixServer.Event do
} }
end end
def create_room(room, creator, room_version) do def create_room(room, %Account{localpart: localpart} = creator, room_version) do
mxid = MatrixServer.get_mxid(localpart)
%Event{ %Event{
new(room, creator) new(room, creator)
| type: "m.room.create", | type: "m.room.create",
state_key: "", state_key: "",
content: %{ content: %{
"creator" => creator, "creator" => mxid,
"room_version" => room_version || MatrixServer.default_room_version() "room_version" => room_version || MatrixServer.default_room_version()
} }
} }
end end
def join(room, sender) do def join(room, %Account{localpart: localpart} = sender) do
mxid = MatrixServer.get_mxid(localpart)
%Event{ %Event{
new(room, sender) new(room, sender)
| type: "m.room.member", | type: "m.room.member",
state_key: sender, state_key: mxid,
content: %{ content: %{
"membership" => "join" "membership" => "join"
} }
} }
end end
def power_levels(room, sender) do def power_levels(room, %Account{localpart: localpart} = sender) do
mxid = MatrixServer.get_mxid(localpart)
%Event{ %Event{
new(room, sender) new(room, sender)
| type: "m.room.power_levels", | type: "m.room.power_levels",
@ -65,7 +71,7 @@ defmodule MatrixServer.Event do
"redact" => 50, "redact" => 50,
"state_default" => 50, "state_default" => 50,
"users" => %{ "users" => %{
sender => 50 mxid => 50
}, },
"users_default" => 0, "users_default" => 0,
"notifications" => %{ "notifications" => %{
@ -97,6 +103,39 @@ defmodule MatrixServer.Event do
} }
end end
def join_rules(room, sender, join_rule) do
%Event{
new(room, sender)
| type: "m.room.join_rules",
state_key: "",
content: %{
"join_rule" => join_rule
}
}
end
def history_visibility(room, sender, history_visibility) do
%Event{
new(room, sender)
| type: "m.room.history_visibility",
state_key: "",
content: %{
"history_visibility" => history_visibility
}
}
end
def guest_access(room, sender, guest_access) do
%Event{
new(room, sender)
| type: "m.room.guest_access",
state_key: "",
content: %{
"guest_access" => guest_access
}
}
end
def generate_event_id do def generate_event_id do
"$" <> MatrixServer.random_string(17) <> ":" <> MatrixServer.server_name() "$" <> MatrixServer.random_string(17) <> ":" <> MatrixServer.server_name()
end end
@ -122,15 +161,13 @@ 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( def prevalidate(%Event{
%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

View file

@ -45,6 +45,12 @@ defmodule MatrixServer.RoomServer do
state_set, state_set,
[create_room_id, join_creator_id] [create_room_id, join_creator_id]
), ),
{:ok, _, state_set, room} <-
room_creation_preset(account, input, room, state_set, [
create_room_id,
join_creator_id,
pl_id
]),
{:ok, _, state_set, room} <- {:ok, _, state_set, room} <-
room_creation_name(account, input, room, state_set, [ room_creation_name(account, input, room, state_set, [
create_room_id, create_room_id,
@ -64,33 +70,74 @@ defmodule MatrixServer.RoomServer do
end) end)
end end
defp room_creation_create_room( defp room_creation_create_room(account, %CreateRoom{room_version: room_version}, room) do
%Account{localpart: localpart}, Event.create_room(room, account, room_version)
%CreateRoom{room_version: room_version},
room
) do
Event.create_room(room, MatrixServer.get_mxid(localpart), room_version)
|> verify_and_insert_event(%{}, room) |> verify_and_insert_event(%{}, room)
end end
defp room_creation_join_creator( defp room_creation_join_creator(account, room, state_set, auth_events) do
%Account{localpart: localpart}, Event.join(room, account)
room,
state_set,
auth_events
) do
Event.join(room, MatrixServer.get_mxid(localpart))
|> Map.put(:auth_events, auth_events) |> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room) |> verify_and_insert_event(state_set, room)
end end
defp room_creation_power_levels( defp room_creation_power_levels(account, room, state_set, auth_events) do
%Account{localpart: localpart}, Event.power_levels(room, account)
room, |> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room)
end
# TODO: trusted_private_chat:
# All invitees are given the same power level as the room creator.
defp room_creation_preset(
account,
%CreateRoom{preset: nil},
%Room{visibility: visibility} = room,
state_set, state_set,
auth_events auth_events
) do ) do
Event.power_levels(room, MatrixServer.get_mxid(localpart)) preset =
case visibility do
:public -> "public_chat"
:private -> "private_chat"
end
room_creation_preset(account, preset, room, state_set, auth_events)
end
defp room_creation_preset(account, %CreateRoom{preset: preset}, room, state_set, auth_events) do
room_creation_preset(account, preset, room, state_set, auth_events)
end
defp room_creation_preset(account, preset, room, state_set, auth_events) do
{join_rule, his_vis, guest_access} =
case preset do
"private_chat" -> {"invite", "shared", "can_join"}
"trusted_private_chat" -> {"invite", "shared", "can_join"}
"public_chat" -> {"public", "shared", "forbidden"}
end
with {:ok, _, _, _} <-
room_creation_join_rules(account, join_rule, room, state_set, auth_events),
{:ok, _, _, _} <- room_creation_his_vis(account, his_vis, room, state_set, auth_events) do
room_creation_guest_access(account, guest_access, room, state_set, auth_events)
end
end
defp room_creation_join_rules(account, join_rule, room, state_set, auth_events) do
Event.join_rules(room, account, join_rule)
|> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room)
end
defp room_creation_his_vis(account, his_vis, room, state_set, auth_events) do
Event.history_visibility(room, account, his_vis)
|> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room)
end
defp room_creation_guest_access(account, guest_access, room, state_set, auth_events) do
Event.guest_access(room, account, guest_access)
|> Map.put(:auth_events, auth_events) |> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room) |> verify_and_insert_event(state_set, room)
end end
@ -99,14 +146,8 @@ defmodule MatrixServer.RoomServer do
{:ok, nil, state_set, room} {:ok, nil, state_set, room}
end end
defp room_creation_name( defp room_creation_name(account, %CreateRoom{name: name}, room, state_set, auth_events) do
%Account{localpart: localpart}, Event.name(room, account, name)
%CreateRoom{name: name},
room,
state_set,
auth_events
) do
Event.name(room, MatrixServer.get_mxid(localpart), name)
|> Map.put(:auth_events, auth_events) |> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room) |> verify_and_insert_event(state_set, room)
end end
@ -115,14 +156,8 @@ defmodule MatrixServer.RoomServer do
{:ok, nil, state_set, room} {:ok, nil, state_set, room}
end end
defp room_creation_topic( defp room_creation_topic(account, %CreateRoom{topic: topic}, room, state_set, auth_events) do
%Account{localpart: localpart}, Event.topic(room, account, topic)
%CreateRoom{topic: topic},
room,
state_set,
auth_events
) do
Event.topic(room, MatrixServer.get_mxid(localpart), topic)
|> Map.put(:auth_events, auth_events) |> Map.put(:auth_events, auth_events)
|> verify_and_insert_event(state_set, room) |> verify_and_insert_event(state_set, room)
end end

View file

@ -13,14 +13,24 @@ defmodule MatrixServerWeb.API.CreateRoom do
field :topic, :string field :topic, :string
field :invite, {:array, :string} field :invite, {:array, :string}
field :room_version, :string field :room_version, :string
field :preset, :string
# TODO: unimplemented: # TODO: unimplemented:
# creation_content, initial_state, invite_3pid, initial_state, preset, # creation_content, initial_state, invite_3pid, initial_state,
# is_direct, power_level_content_override # is_direct, power_level_content_override
end end
def changeset(params) do def changeset(params) do
%__MODULE__{} %__MODULE__{}
|> cast(params, [:visibility, :room_alias_name, :name, :topic, :invite, :room_version]) |> cast(params, [
:visibility,
:room_alias_name,
:name,
:topic,
:invite,
:room_version,
:preset
])
|> validate_inclusion(:preset, ["private_chat", "public_chat", "trusted_private_chat"])
end end
def get_error(%Changeset{errors: [error | _]}), do: get_error(error) def get_error(%Changeset{errors: [error | _]}), do: get_error(error)

View file

@ -14,6 +14,24 @@ 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
alice =
Repo.insert!(%Account{
localpart: "alice",
password_hash: Bcrypt.hash_pwd_salt("sneed")
})
bob =
Repo.insert!(%Account{
localpart: "bob",
password_hash: Bcrypt.hash_pwd_salt("sneed")
})
charlie =
Repo.insert!(%Account{
localpart: "charlie",
password_hash: Bcrypt.hash_pwd_salt("sneed")
})
room = room =
Repo.insert!(%Room{ Repo.insert!(%Room{
id: "room1", id: "room1",
@ -21,13 +39,13 @@ room =
}) })
Repo.insert!( Repo.insert!(
Event.create_room(room, "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(room, "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)
@ -35,7 +53,7 @@ Repo.insert!(
) )
Repo.insert!( Repo.insert!(
Event.join(room, "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)
@ -43,14 +61,14 @@ Repo.insert!(
) )
Repo.insert!( Repo.insert!(
Event.join(room, "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(room, "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!(
@ -61,7 +79,7 @@ Repo.insert!(
|> Map.put(:event_id, "a") |> Map.put(:event_id, "a")
) )
%Event{content: content} = event = Event.power_levels(room, "bob") %Event{content: content} = event = Event.power_levels(room, bob)
event = %Event{ event = %Event{
event event
@ -77,7 +95,7 @@ Repo.insert!(
) )
Repo.insert!( Repo.insert!(
Event.topic(room, "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)