diff --git a/lib/architex/room_server.ex b/lib/architex/room_server.ex index d32ae55..1119df6 100644 --- a/lib/architex/room_server.ex +++ b/lib/architex/room_server.ex @@ -21,7 +21,8 @@ defmodule Architex.RoomServer do Account, JoinedRoom, Device, - DeviceTransaction + DeviceTransaction, + Membership } alias Architex.StateResolution.Authorization @@ -607,6 +608,7 @@ defmodule Architex.RoomServer do 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} else @@ -651,4 +653,34 @@ defmodule Architex.RoomServer do where: jr.room_id == ^room_id and a.localpart in ^not_joined_localparts ) end + + # TODO: Might be better to calculate membership changes... + @spec update_membership(Room.t(), t()) :: :ok + defp update_membership(%Room{id: room_id}, state_set) do + server_name = Architex.server_name() + + state_set + |> Enum.filter(fn {{type, state_key}, _} -> + type == "m.room.member" and Architex.get_domain(state_key) == server_name + end) + |> Enum.group_by( + fn {_, %Event{content: %{"membership" => membership}}} -> + membership + end, + fn {{_, state_key}, _} -> + Architex.get_localpart(state_key) + end + ) + |> Enum.each(fn {membership, localparts} -> + Repo.insert_all( + Membership, + from(a in Account, + where: a.localpart in ^localparts, + select: %{account_id: a.id, room_id: ^room_id, membership: ^membership} + ), + on_conflict: {:replace, [:membership]}, + conflict_target: [:account_id, :room_id] + ) + end) + end end diff --git a/lib/architex/schema/membership.ex b/lib/architex/schema/membership.ex new file mode 100644 index 0000000..0d24bf8 --- /dev/null +++ b/lib/architex/schema/membership.ex @@ -0,0 +1,18 @@ +defmodule Architex.Membership do + use Ecto.Schema + + alias Architex.{Account, Room} + + @type t :: %__MODULE__{ + account_id: integer(), + room_id: String.t(), + membership: String.t() + } + + @primary_key false + schema "membership" do + belongs_to :account, Account, primary_key: true + belongs_to :room, Room, primary_key: true, type: :string + field :membership, :string + end +end diff --git a/lib/architex_web/client/controllers/sync_controller.ex b/lib/architex_web/client/controllers/sync_controller.ex index ce6d2c9..cb720bb 100644 --- a/lib/architex_web/client/controllers/sync_controller.ex +++ b/lib/architex_web/client/controllers/sync_controller.ex @@ -47,11 +47,12 @@ defmodule ArchitexWeb.Client.SyncController do {room_id, joined_room} end) - next_batch = Enum.map(events_per_room, fn {_, events} -> - %Event{nid: last_nid} = List.last(events) - last_nid - end) - |> Enum.max(fn -> 0 end) + next_batch = + Enum.map(events_per_room, fn {_, events} -> + %Event{nid: last_nid} = List.last(events) + last_nid + end) + |> Enum.max(fn -> 0 end) data = %{ next_batch: Integer.to_string(next_batch), diff --git a/priv/repo/migrations/20210830160818_create_initial_tables.exs b/priv/repo/migrations/20210830160818_create_initial_tables.exs index 21b7fb2..f40b72a 100644 --- a/priv/repo/migrations/20210830160818_create_initial_tables.exs +++ b/priv/repo/migrations/20210830160818_create_initial_tables.exs @@ -91,5 +91,11 @@ defmodule Architex.Repo.Migrations.CreateInitialTables do add :event_id, :string, null: false end + + create table(:membership, primary_key: false) do + add :account_id, references(:accounts), primary_key: true + add :room_id, references(:rooms, type: :string), primary_key: true + add :membership, :string, null: false + end end end