feat(contacts): hide Private column when the viewer has nothing private
Row-level privacy was already correct: private rows only render for the owner and admins. The header column was still showing for every viewer, leaving an always-empty slot for anyone without private contacts of their own. Drop `:private` from the fields list unless the scope can actually see at least one private row.
This commit is contained in:
parent
c38f4e2bfe
commit
4b155c5419
2 changed files with 79 additions and 1 deletions
|
|
@ -61,9 +61,31 @@ defmodule MicrowavepropWeb.ContactLive.Index do
|
||||||
socket
|
socket
|
||||||
|> assign(:page_title, "Contacts")
|
|> assign(:page_title, "Contacts")
|
||||||
|> assign(:total_contacts, total)
|
|> assign(:total_contacts, total)
|
||||||
|
|> assign(:visible_fields, visible_fields_for(scope))
|
||||||
|> assign(:data_provider, {__MODULE__, :visible_query_provider, [scope_token(scope)]})}
|
|> assign(:data_provider, {__MODULE__, :visible_query_provider, [scope_token(scope)]})}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Hide the Private column entirely unless this scope can actually see
|
||||||
|
# at least one private contact — avoids an always-empty column for
|
||||||
|
# visitors and owners who've never flagged one as private.
|
||||||
|
defp visible_fields_for(scope) do
|
||||||
|
if has_viewable_private?(scope) do
|
||||||
|
fields()
|
||||||
|
else
|
||||||
|
Keyword.delete(fields(), :private)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
defp has_viewable_private?(%Scope{user: %User{is_admin: true}}) do
|
||||||
|
Repo.exists?(from(c in Contact, where: c.private == true))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp has_viewable_private?(%Scope{user: %User{id: user_id}}) do
|
||||||
|
Repo.exists?(from(c in Contact, where: c.private == true and c.user_id == ^user_id))
|
||||||
|
end
|
||||||
|
|
||||||
|
defp has_viewable_private?(_), do: false
|
||||||
|
|
||||||
@doc false
|
@doc false
|
||||||
# Called by LiveTable to get the base queryable. Must be a
|
# Called by LiveTable to get the base queryable. Must be a
|
||||||
# named function because the helper persists MFA across renders.
|
# named function because the helper persists MFA across renders.
|
||||||
|
|
@ -183,7 +205,7 @@ defmodule MicrowavepropWeb.ContactLive.Index do
|
||||||
</.header>
|
</.header>
|
||||||
|
|
||||||
<.live_table
|
<.live_table
|
||||||
fields={fields()}
|
fields={@visible_fields}
|
||||||
filters={filters()}
|
filters={filters()}
|
||||||
options={@options}
|
options={@options}
|
||||||
streams={@streams}
|
streams={@streams}
|
||||||
|
|
|
||||||
|
|
@ -167,6 +167,62 @@ defmodule MicrowavepropWeb.ContactLiveTest do
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe "Index private column visibility" do
|
||||||
|
import Microwaveprop.AccountsFixtures
|
||||||
|
|
||||||
|
test "column hidden for anonymous viewer when no private contacts exist", %{conn: conn} do
|
||||||
|
_public = create_contact(%{station1: "W5PUB"})
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
refute html =~ ">Private<"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "column hidden for anonymous viewer even when others have private contacts", %{conn: conn} do
|
||||||
|
_private = create_contact(%{station1: "W5PRV", private: true})
|
||||||
|
_public = create_contact(%{station1: "W5PUB"})
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
refute html =~ ">Private<"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "column hidden for a user who has no private contacts of their own", %{conn: conn} do
|
||||||
|
owner = user_fixture()
|
||||||
|
viewer = user_fixture()
|
||||||
|
_others_private = create_contact(%{station1: "W5PRV", private: true, user_id: owner.id})
|
||||||
|
conn = log_in_user(conn, viewer)
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
refute html =~ ">Private<"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "column visible for a user with at least one of their own private contacts", %{conn: conn} do
|
||||||
|
owner = user_fixture()
|
||||||
|
_private = create_contact(%{station1: "W5PRV", private: true, user_id: owner.id})
|
||||||
|
conn = log_in_user(conn, owner)
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
assert html =~ ">Private<"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "column hidden for admin when there are no private contacts anywhere", %{conn: conn} do
|
||||||
|
admin = user_fixture() |> Ecto.Changeset.change(is_admin: true) |> Repo.update!()
|
||||||
|
_public = create_contact(%{station1: "W5PUB"})
|
||||||
|
conn = log_in_user(conn, admin)
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
refute html =~ ">Private<"
|
||||||
|
end
|
||||||
|
|
||||||
|
test "column visible for admin as soon as any private contact exists", %{conn: conn} do
|
||||||
|
admin = user_fixture() |> Ecto.Changeset.change(is_admin: true) |> Repo.update!()
|
||||||
|
_private = create_contact(%{station1: "W5PRV", private: true})
|
||||||
|
conn = log_in_user(conn, admin)
|
||||||
|
|
||||||
|
{:ok, _lv, html} = live(conn, ~p"/contacts")
|
||||||
|
assert html =~ ">Private<"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "Show private visibility" do
|
describe "Show private visibility" do
|
||||||
import Microwaveprop.AccountsFixtures
|
import Microwaveprop.AccountsFixtures
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue