feat(chat): add auth logic for room memberships

This commit is contained in:
João Paulo Dubas 2024-11-17 21:16:52 +00:00
parent d3253bd900
commit 9755dc2b9e
Signed by: joao.dubas
SSH Key Fingerprint: SHA256:V1mixgOGRc/YMhGx/DNkOSmJxgA2vHNrDZEk3wt/kOA
3 changed files with 80 additions and 12 deletions

View File

@ -29,6 +29,12 @@ defmodule Slax.Chat do
Repo.insert!(%RoomMembership{room: room, user: user}) Repo.insert!(%RoomMembership{room: room, user: user})
end end
def joined?(%Room{} = room, %User{} = user) do
Repo.exists?(
from rm in RoomMembership, where: rm.room_id == ^room.id and rm.user_id == ^user.id
)
end
def change_room(room, attrs \\ %{}) do def change_room(room, attrs \\ %{}) do
Room.changeset(room, attrs) Room.changeset(room, attrs)
end end
@ -47,6 +53,13 @@ defmodule Slax.Chat do
Repo.all(query) Repo.all(query)
end end
def list_joined_rooms(%User{} = user) do
user
|> Repo.preload(:rooms)
|> Map.fetch!(:rooms)
|> Enum.sort_by(& &1.name)
end
def list_messages_in_room(%Room{id: room_id}) do def list_messages_in_room(%Room{id: room_id}) do
query = query =
from(m in Message, from(m in Message,

View File

@ -65,6 +65,7 @@ defmodule SlaxWeb.ChatRoomLive do
<h1 class="text-sm font-bold leading-none"> <h1 class="text-sm font-bold leading-none">
#<%= @room.name %> #<%= @room.name %>
<.link <.link
:if={@joined?}
class="font-normal text-xs text-blue-600 hover:text-blue-700" class="font-normal text-xs text-blue-600 hover:text-blue-700"
navigate={~p"/rooms/#{@room}/edit"} navigate={~p"/rooms/#{@room}/edit"}
> >
@ -135,7 +136,7 @@ defmodule SlaxWeb.ChatRoomLive do
timezone={@timezone} timezone={@timezone}
/> />
</div> </div>
<div class="h-12 bg-white px-4 pb-4"> <div :if={@joined?} class="h-12 bg-white px-4 pb-4">
<.form <.form
id="new-message-form" id="new-message-form"
for={@new_message_form} for={@new_message_form}
@ -158,13 +159,41 @@ defmodule SlaxWeb.ChatRoomLive do
</button> </button>
</.form> </.form>
</div> </div>
<div
:if={!@joined?}
class="flex justify-around mx-5 mb-5 p-6 bg-slate-100 border-slate-300 border rounded-lg"
>
<div class="max-w-3-xl text-center">
<div class="mb-4">
<h1 class="text-xl font-semibold"><%= @room.name %></h1>
<p :if={@room.topic} class="text-sm mt-1 text-gray-600"><%= @room.topic %></p>
</div>
<div class="flex items-center justify-around">
<buttom
phx-click="join-room"
class="px-4 py-2 bg-green-600 text-white rounded hover:bg-green-600 focus:outline-none focus:ring-2 focus:ring-green-500"
>
Join Room
</buttom>
</div>
<div class="mt-4">
<.link
navigate={~p"/rooms"}
href="#"
class="text-sm text-slate-500 underline hover:text-slate-600"
>
Back to All Rooms
</.link>
</div>
</div>
</div>
</div> </div>
""" """
end end
@impl Phoenix.LiveView @impl Phoenix.LiveView
def mount(_params, _session, socket) do def mount(_params, _session, socket) do
rooms = Chat.list_rooms() rooms = Chat.list_joined_rooms(socket.assigns.current_user)
users = Accounts.list_users() users = Accounts.list_users()
timezone = get_connect_params(socket)["timezone"] timezone = get_connect_params(socket)["timezone"]
@ -206,7 +235,12 @@ defmodule SlaxWeb.ChatRoomLive do
{:noreply, {:noreply,
socket socket
|> assign(hide_topic?: false, page_title: "# #{room.name}", room: room) |> assign(
hide_topic?: false,
joined?: Chat.joined?(room, socket.assigns.current_user),
page_title: "# #{room.name}",
room: room
)
|> stream(:messages, messages, reset: true) |> stream(:messages, messages, reset: true)
|> assign_message_form(Chat.change_message(%Message{})) |> assign_message_form(Chat.change_message(%Message{}))
|> push_event("scroll_messages_to_bottom", %{})} |> push_event("scroll_messages_to_bottom", %{})}
@ -228,6 +262,7 @@ defmodule SlaxWeb.ChatRoomLive do
%{current_user: user, room: room} = socket.assigns %{current_user: user, room: room} = socket.assigns
socket = socket =
if Chat.joined?(room, user) do
case Chat.create_message(room, user, message_params) do case Chat.create_message(room, user, message_params) do
{:ok, _message} -> {:ok, _message} ->
assign_message_form(socket, Chat.change_message(%Message{})) assign_message_form(socket, Chat.change_message(%Message{}))
@ -235,6 +270,9 @@ defmodule SlaxWeb.ChatRoomLive do
{:error, changeset} -> {:error, changeset} ->
assign_message_form(socket, changeset) assign_message_form(socket, changeset)
end end
else
socket
end
{:noreply, socket} {:noreply, socket}
end end
@ -246,6 +284,16 @@ defmodule SlaxWeb.ChatRoomLive do
{:noreply, socket} {:noreply, socket}
end end
@impl Phoenix.LiveView
def handle_event("join-room", _, socket) do
current_user = socket.assigns.current_user
room = socket.assigns.room
Chat.join_room!(room, current_user)
Chat.subscribe_to_room(room)
socket = assign(socket, joined?: true, rooms: Chat.list_joined_rooms(current_user))
{:noreply, socket}
end
@impl Phoenix.LiveView @impl Phoenix.LiveView
def handle_info({:new_message, message}, socket) do def handle_info({:new_message, message}, socket) do
socket = socket =

View File

@ -33,12 +33,19 @@ defmodule SlaxWeb.ChatRoomLive.Edit do
@impl Phoenix.LiveView @impl Phoenix.LiveView
def mount(%{"id" => id}, _session, socket) do def mount(%{"id" => id}, _session, socket) do
room = Chat.get_room!(id) room = Chat.get_room!(id)
changeset = Chat.change_room(room)
socket = socket =
if Chat.joined?(room, socket.assigns.current_user) do
changeset = Chat.change_room(room)
socket socket
|> assign(page_title: "Edit chat room", room: room) |> assign(page_title: "Edit chat room", room: room)
|> assign_form(changeset) |> assign_form(changeset)
else
socket
|> put_flash(:error, "Permission denied")
|> push_navigate(to: ~p"/")
end
{:ok, socket} {:ok, socket}
end end