diff --git a/lib/architex/room_server.ex b/lib/architex/room_server.ex index 1119df6..8e712c2 100644 --- a/lib/architex/room_server.ex +++ b/lib/architex/room_server.ex @@ -19,7 +19,6 @@ defmodule Architex.RoomServer do Event, StateResolution, Account, - JoinedRoom, Device, DeviceTransaction, Membership @@ -606,8 +605,6 @@ defmodule Architex.RoomServer do room = Room.update_forward_extremities(event, room) event = Repo.insert!(event) state_set = StateResolution.resolve_forward_extremities(event) - # TODO: Do this as a background job, and not after every insert... - _ = update_joined_rooms(room, state_set) :ok = update_membership(room, state_set) {:ok, state_set, room, event} @@ -616,45 +613,11 @@ defmodule Architex.RoomServer do end end - # Update local accounts' room membership if applicable. - @spec update_joined_rooms(Room.t(), t()) :: JoinedRoom.t() | nil - defp update_joined_rooms(%Room{id: room_id}, state_set) do - server_name = Architex.server_name() - - {joined, not_joined} = - state_set - |> Enum.filter(fn {{type, state_key}, _} -> - type == "m.room.member" and Architex.get_domain(state_key) == server_name - end) - |> Enum.split_with(fn {_, %Event{content: %{"membership" => membership}}} -> - membership == "join" - end) - - map_localparts = - &Enum.map(&1, fn {{_, state_key}, _} -> Architex.get_localpart(state_key) end) - - joined_localparts = map_localparts.(joined) - not_joined_localparts = map_localparts.(not_joined) - - _ = - Repo.insert_all( - JoinedRoom, - from(a in Account, - where: a.localpart in ^joined_localparts, - select: %{account_id: a.id, room_id: ^room_id} - ), - on_conflict: :nothing - ) - - Repo.delete_all( - from jr in JoinedRoom, - join: a in Account, - on: a.id == jr.account_id, - where: jr.room_id == ^room_id and a.localpart in ^not_joined_localparts - ) - end - - # TODO: Might be better to calculate membership changes... + # TODO: Might be better to calculate membership changes only... + # TODO: I don't think this should be a background job, as it get out-of-sync and users + # could access rooms they are not allowed to. Then again, maybe we should perform + # the "normal" authorization flow for local users as well, and treat the Membership + # table only as informational. @spec update_membership(Room.t(), t()) :: :ok defp update_membership(%Room{id: room_id}, state_set) do server_name = Architex.server_name() diff --git a/lib/architex/schema/account.ex b/lib/architex/schema/account.ex index 92f9790..5468d9b 100644 --- a/lib/architex/schema/account.ex +++ b/lib/architex/schema/account.ex @@ -3,7 +3,7 @@ defmodule Architex.Account do import Ecto.{Changeset, Query} - alias Architex.{Repo, Account, Device, Room, JoinedRoom} + alias Architex.{Repo, Account, Device, Room, Membership} alias ArchitexWeb.Client.Request.{Register, Login} alias Ecto.{Multi, Changeset} @@ -19,8 +19,19 @@ defmodule Architex.Account do has_many :devices, Device many_to_many :joined_rooms, Room, - join_through: JoinedRoom, - join_keys: [account_id: :id, room_id: :id] + join_through: Membership, + join_keys: [account_id: :id, room_id: :id], + join_where: [membership: "join"] + + many_to_many :invited_rooms, Room, + join_through: Membership, + join_keys: [account_id: :id, room_id: :id], + join_where: [membership: "invite"] + + many_to_many :left_rooms, Room, + join_through: Membership, + join_keys: [account_id: :id, room_id: :id], + join_where: [membership: "leave"] timestamps(updated_at: false) end diff --git a/lib/architex/schema/joined_room.ex b/lib/architex/schema/joined_room.ex deleted file mode 100644 index 0250031..0000000 --- a/lib/architex/schema/joined_room.ex +++ /dev/null @@ -1,17 +0,0 @@ -defmodule Architex.JoinedRoom do - use Ecto.Schema - - alias Architex.{Account, Room} - - @type t :: %__MODULE__{ - account_id: integer(), - room_id: String.t() - } - - @primary_key false - schema "joined_rooms" do - belongs_to :account, Account, primary_key: true - - belongs_to :room, Room, primary_key: true, type: :string - end -end diff --git a/lib/architex_web/client/controllers/sync_controller.ex b/lib/architex_web/client/controllers/sync_controller.ex index cb720bb..7c61771 100644 --- a/lib/architex_web/client/controllers/sync_controller.ex +++ b/lib/architex_web/client/controllers/sync_controller.ex @@ -4,7 +4,7 @@ defmodule ArchitexWeb.Client.SyncController do import ArchitexWeb.Error import Ecto.Query - alias Architex.{Repo, Event, Account, Room, JoinedRoom} + alias Architex.{Repo, Event, Account, Room, Membership} alias Plug.Conn @doc """ @@ -26,10 +26,10 @@ defmodule ArchitexWeb.Client.SyncController do events_per_room = Event - |> join(:inner, [e], jr in JoinedRoom, - on: jr.room_id == e.room_id and jr.account_id == ^account_id + |> join(:inner, [e], m in Membership, + on: m.room_id == e.room_id and m.account_id == ^account_id and m.membership == "join" ) - |> join(:inner, [e, jr], r in Room, on: r.id == jr.room_id) + |> join(:inner, [e, m], r in Room, on: r.id == m.room_id) |> order_by(asc: :origin_server_ts, asc: :nid) |> Repo.all() |> Enum.group_by(& &1.room_id) diff --git a/priv/repo/migrations/20210830160818_create_initial_tables.exs b/priv/repo/migrations/20210830160818_create_initial_tables.exs index f40b72a..e8a7062 100644 --- a/priv/repo/migrations/20210830160818_create_initial_tables.exs +++ b/priv/repo/migrations/20210830160818_create_initial_tables.exs @@ -17,14 +17,6 @@ defmodule Architex.Repo.Migrations.CreateInitialTables do add :visibility, :string, null: false, default: "public" end - create table(:joined_rooms, primary_key: false) do - add :account_id, references(:accounts), primary_key: true, null: false - - add :room_id, references(:rooms, type: :string), - primary_key: true, - null: false - end - create table(:events, primary_key: false) do add :nid, :serial, primary_key: true add :id, :string, null: false