Add part of room creation endpoint

This commit is contained in:
Pim Kunis 2021-07-17 17:38:20 +02:00
parent 585de861d6
commit 9be94751dc
12 changed files with 168 additions and 48 deletions

View file

@ -33,18 +33,18 @@ defmodule MatrixServer.Account do
end
end
def register(%Register{} = api) do
def register(%Register{} = input) do
account_params = %{
localpart: api.username || MatrixServer.random_string(10, ?a..?z),
password_hash: Bcrypt.hash_pwd_salt(api.password)
localpart: input.username || MatrixServer.random_string(10, ?a..?z),
password_hash: Bcrypt.hash_pwd_salt(input.password)
}
Multi.new()
|> Multi.insert(:account, changeset(%Account{}, account_params))
|> Multi.insert(:device, fn %{account: account} ->
device_params = %{
display_name: api.initial_device_display_name,
device_id: api.device_id || Device.generate_device_id(account.localpart)
display_name: input.initial_device_display_name,
device_id: input.device_id || Device.generate_device_id(account.localpart)
}
Ecto.build_assoc(account, :devices)
@ -53,14 +53,14 @@ defmodule MatrixServer.Account do
|> Multi.run(:device_with_access_token, &Device.insert_new_access_token/2)
end
def login(%Login{} = api) do
localpart = try_get_localpart(api.identifier.user)
def login(%Login{} = input) do
localpart = try_get_localpart(input.identifier.user)
fn repo ->
case repo.one(from a in Account, where: a.localpart == ^localpart) do
%Account{password_hash: hash} = account ->
if Bcrypt.verify_pass(api.password, hash) do
case Device.login(api, account) do
if Bcrypt.verify_pass(input.password, hash) do
case Device.login(input, account) do
{:ok, device} ->
device
@ -87,6 +87,7 @@ defmodule MatrixServer.Account do
end
def changeset(account, params \\ %{}) do
# TODO: fix password_hash in params
account
|> cast(params, [:localpart, :password_hash])
|> validate_required([:localpart, :password_hash])

View file

@ -50,16 +50,16 @@ defmodule MatrixServer.Device do
"#{localpart}_#{time_string}"
end
def login(%Login{} = api, account) do
device_id = api.device_id || generate_device_id(account.localpart)
def login(%Login{} = input, account) do
device_id = input.device_id || generate_device_id(account.localpart)
access_token = generate_access_token(account.localpart, device_id)
update_query =
from(d in Device)
|> update(set: [access_token: ^access_token, device_id: ^device_id])
|> then(fn q ->
if api.initial_device_display_name do
update(q, set: [display_name: ^api.initial_device_display_name])
if input.initial_device_display_name do
update(q, set: [display_name: ^input.initial_device_display_name])
else
q
end
@ -67,7 +67,7 @@ defmodule MatrixServer.Device do
device_params = %{
device_id: device_id,
display_name: api.initial_device_display_name
display_name: input.initial_device_display_name
}
Ecto.build_assoc(account, :devices)

View file

@ -3,17 +3,19 @@ defmodule MatrixServer.Event do
import Ecto.Changeset
alias MatrixServer.Room
alias MatrixServer.{Room, Event, Account}
alias MatrixServerWeb.API.CreateRoom
@primary_key {:event_id, :string, []}
schema "events" do
field :type, :string
field :timestamp, :naive_datetime
field :origin_server_ts, :integer
field :state_key, :string
field :sender, :string
field :content, :string
field :content, :map
field :prev_events, {:array, :string}
field :auth_events, {:array, :string}
belongs_to :room, Room
belongs_to :room, Room, type: :string
end
def changeset(event, params \\ %{}) do
@ -22,4 +24,84 @@ defmodule MatrixServer.Event do
|> cast(params, [:type, :timestamp, :state_key, :sender, :content])
|> validate_required([:type, :timestamp, :sender])
end
def new(room_id, sender) do
%Event{
room_id: room_id,
sender: sender,
event_id: generate_event_id(),
origin_server_ts: DateTime.utc_now() |> DateTime.to_unix(),
prev_events: [],
auth_events: []
}
end
def create_room(room_id, creator, room_version) do
%Event{
new(room_id, creator)
| type: "m.room.create",
state_key: "",
content: %{
creator: creator,
room_version: room_version || MatrixServer.default_room_version()
}
}
end
def join(room_id, sender) do
%Event{
new(room_id, sender)
| type: "m.room.member",
state_key: sender,
content: %{
membership: "invite"
}
}
end
def room_creation_create_room(%CreateRoom{room_version: room_version}, %Account{
localpart: localpart
}) do
fn repo, %{room: %Room{id: room_id}} ->
# TODO: state resolution
create_room(room_id, MatrixServer.get_mxid(localpart), room_version)
|> repo.insert()
end
end
def room_creation_join_creator do
fn repo,
%{
create_room_event: %Event{sender: creator, event_id: create_room_event_id},
room: %Room{id: room_id}
} ->
# TODO: state resolution
join(room_id, creator)
|> Map.put(:prev_events, [create_room_event_id])
|> Map.put(:auth_events, [create_room_event_id])
|> repo.insert()
end
end
def room_creation_power_levels(_input) do
fn _repo, %{} ->
{:ok, :ok}
end
end
def room_creation_name(_input) do
fn _repo, %{} ->
{:ok, :ok}
end
end
def room_creation_topic(_input) do
fn _repo, %{} ->
{:ok, :ok}
end
end
def generate_event_id do
"$" <> MatrixServer.random_string(17) <> ":" <> MatrixServer.server_name()
end
end

View file

@ -12,18 +12,19 @@ defmodule MatrixServer.Room do
field :visibility, Ecto.Enum, values: [:public, :private]
end
def create(%CreateRoom{} = api) do
Multi.new()
|> Multi.insert(:room, Room.create_changeset(api))
end
def changeset(room, params \\ %{}) do
room
|> cast(params, [:visibility])
cast(room, params, [:visibility])
end
def create_changeset(%CreateRoom{} = api) do
%Room{visibility: api.visibility, id: MatrixServer.random_string(18)}
|> changeset()
def create_changeset(%CreateRoom{} = input) do
visibility = input.visibility || :public
%Room{}
|> changeset(%{visibility: visibility})
|> put_change(:id, generate_room_id())
end
def generate_room_id do
"!" <> MatrixServer.random_string(18) <> "@" <> MatrixServer.server_name()
end
end

View file

@ -1,15 +1,16 @@
defmodule MatrixServer.RoomServer do
use GenServer
alias MatrixServer.{Repo, Room}
alias MatrixServer.{Repo, Room, Event}
alias MatrixServerWeb.API.CreateRoom
alias Ecto.Multi
def start_link(_opts) do
GenServer.start_link(__MODULE__, :ok, name: __MODULE__)
end
def create_room(params) do
GenServer.call(__MODULE__, {:create_room, params})
def create_room(%CreateRoom{} = input, account) do
GenServer.call(__MODULE__, {:create_room, input, account})
end
@impl true
@ -18,10 +19,18 @@ defmodule MatrixServer.RoomServer do
end
@impl true
def handle_call({:create_room, %CreateRoom{} = api}, _from, state) do
Room.create(api)
|> Repo.transaction()
def handle_call({:create_room, input, account}, _from, state) do
# TODO: preset events, initial_state events, invite, invite_3pid
result =
Multi.new()
|> Multi.insert(:room, Room.create_changeset(input))
|> Multi.run(:create_room_event, Event.room_creation_create_room(input, account))
|> Multi.run(:join_creator_event, Event.room_creation_join_creator())
|> Multi.run(:power_levels_event, Event.room_creation_power_levels(input))
|> Multi.run(:name_event, Event.room_creation_name(input))
|> Multi.run(:topic_event, Event.room_creation_topic(input))
|> Repo.transaction()
{:reply, :ok, state}
{:reply, result, state}
end
end