neiam
/apollos_crib
It's Apollo's Crib
public · Issues · Pulls 1 · Labels · Forks · Compare · Actions failure · Badges · Packages
⭐
Log in to mark this repository.
Plani: the plani pages only reach the user's own
f2c072f · Gabe Morell · 2026-11-04 22:10
Message
{commit_body(@commit)}
Files changed
modified
apps/room_sanctum/lib/room_sanctum/configuration.ex
+9
−0
@@ -709,6 +709,15 @@ defmodule RoomSanctum.Configuration do
| 709 | 709 | |
| 710 | 710 | def get_plani!(id), do: Repo.get!(Plani, id) |
| 711 | 711 | |
| 712 | + # Someone else's plani raises the not-found a missing one -- or a junk id -- | |
| 713 | + # does. | |
| 714 | + def get_plani!({:user, uid}, id) do | |
| 715 | + case Integer.parse(to_string(id)) do | |
| 716 | + {n, ""} -> Repo.get_by!(Plani, id: n, user_id: uid) | |
| 717 | + _ -> raise Ecto.NoResultsError, queryable: Plani | |
| 718 | + end | |
| 719 | + end | |
| 720 | + | |
| 712 | 721 | def create_plani(attrs \\ %{}) do |
| 713 | 722 | %Plani{} |> Plani.changeset(attrs) |> Repo.insert() |> announce(:plani) |
| 714 | 723 | end |
modified
apps/room_sanctum/lib/room_sanctum_web/live/cfg_plani_live/index.ex
+5
−2
@@ -17,7 +17,7 @@ defmodule RoomSanctumWeb.PlaniLive.Index do
| 17 | 17 | defp apply_action(socket, :edit, %{"id" => id}) do |
| 18 | 18 | socket |
| 19 | 19 | |> assign(:page_title, "Modify Plani") |
| 20 | − |> assign(:plani, Configuration.get_plani!(id)) | |
| 20 | + |> assign(:plani, Configuration.get_plani!(owner(socket), id)) | |
| 21 | 21 | end |
| 22 | 22 | |
| 23 | 23 | defp apply_action(socket, :new, _params) do |
@@ -39,9 +39,12 @@ defmodule RoomSanctumWeb.PlaniLive.Index do
| 39 | 39 | |
| 40 | 40 | @impl true |
| 41 | 41 | def handle_event("delete", %{"id" => id}, socket) do |
| 42 | − plani = Configuration.get_plani!(id) | |
| 42 | + plani = Configuration.get_plani!(owner(socket), id) | |
| 43 | 43 | {:ok, _} = Configuration.delete_plani(plani) |
| 44 | 44 | |
| 45 | 45 | {:noreply, stream_delete(socket, :plani, plani)} |
| 46 | 46 | end |
| 47 | + | |
| 48 | + # Ids from the URL or the client are looked up among the user's own. | |
| 49 | + defp owner(socket), do: {:user, socket.assigns.current_user.id} | |
| 47 | 50 | end |
modified
apps/room_sanctum/lib/room_sanctum_web/live/cfg_plani_live/show.ex
+16
−4
@@ -25,9 +25,9 @@ defmodule RoomSanctumWeb.PlaniLive.Show do
| 25 | 25 | {:noreply, |
| 26 | 26 | socket |
| 27 | 27 | |> assign(:page_title, "Plani") |
| 28 | − |> assign(:plani, Configuration.get_plani!(id)) | |
| 29 | − |> assign(:sources, Configuration.list_cfg_sources({:user, socket.assigns.current_user.id})) | |
| 30 | − |> assign(:pythiae, Configuration.list_pythiae(:plani, id)) | |
| 28 | + |> assign(:plani, Configuration.get_plani!(owner(socket), id)) | |
| 29 | + |> assign(:sources, Configuration.list_cfg_sources({:user, socket.assigns.current_user.id})) | |
| 30 | + |> assign(:pythiae, own_pythiae(socket, id)) | |
| 31 | 31 | |> look()} |
| 32 | 32 | end |
| 33 | 33 |
@@ -113,7 +113,8 @@ defmodule RoomSanctumWeb.PlaniLive.Show do
| 113 | 113 | curvature to show, and the longitude scale is taken at the ring's own |
| 114 | 114 | latitude so it does not go oval further north. |
| 115 | 115 | """ |
| 116 | − def radius_ring(%{anchor: %Geo.Point{coordinates: {lon, lat}}}, radius_m) when is_integer(radius_m) do | |
| 116 | + def radius_ring(%{anchor: %Geo.Point{coordinates: {lon, lat}}}, radius_m) | |
| 117 | + when is_integer(radius_m) do | |
| 117 | 118 | d_lat = radius_m / 111_320 |
| 118 | 119 | d_lon = radius_m / (111_320 * max(:math.cos(lat * :math.pi() / 180), 0.01)) |
| 119 | 120 |
@@ -270,4 +271,15 @@ defmodule RoomSanctumWeb.PlaniLive.Show do
| 270 | 271 | nil -> nil |
| 271 | 272 | end |
| 272 | 273 | end |
| 274 | + | |
| 275 | + # The pythiae driven by this plani, of the user's own: another user's screen | |
| 276 | + # pointed at it is none of this page's business. | |
| 277 | + defp own_pythiae(socket, id) do | |
| 278 | + :plani | |
| 279 | + |> Configuration.list_pythiae(id) | |
| 280 | + |> Enum.filter(&(&1.user_id == socket.assigns.current_user.id)) | |
| 281 | + end | |
| 282 | + | |
| 283 | + # The plani comes from the URL, so it is looked up among the user's own. | |
| 284 | + defp owner(socket), do: {:user, socket.assigns.current_user.id} | |
| 273 | 285 | end |
modified
apps/room_sanctum/test/room_sanctum_web/live/ownership_test.exs
+41
−0
@@ -387,4 +387,45 @@ defmodule RoomSanctumWeb.OwnershipTest do
| 387 | 387 | assert Repo.reload!(screen).curr_vision == second.id |
| 388 | 388 | end |
| 389 | 389 | end |
| 390 | + | |
| 391 | + defp plani_for(user) do | |
| 392 | + {:ok, plani} = | |
| 393 | + Configuration.create_plani(%{ | |
| 394 | + name: "Pocket", | |
| 395 | + user_id: user.id, | |
| 396 | + home_foci_id: foci_for(user).id, | |
| 397 | + sources: [] | |
| 398 | + }) | |
| 399 | + | |
| 400 | + plani | |
| 401 | + end | |
| 402 | + | |
| 403 | + describe "the plani pages" do | |
| 404 | + setup :users_rabbit! | |
| 405 | + | |
| 406 | + test "will not show another user's plani", ctx do | |
| 407 | + theirs = plani_for(ctx.them) | |
| 408 | + | |
| 409 | + assert_raise Ecto.NoResultsError, fn -> | |
| 410 | + live(ctx.conn, Routes.plani_show_path(ctx.conn, :show, theirs)) | |
| 411 | + end | |
| 412 | + end | |
| 413 | + | |
| 414 | + test "will not open another user's plani for editing", ctx do | |
| 415 | + theirs = plani_for(ctx.them) | |
| 416 | + | |
| 417 | + assert_raise Ecto.NoResultsError, fn -> | |
| 418 | + live(ctx.conn, Routes.plani_index_path(ctx.conn, :edit, theirs)) | |
| 419 | + end | |
| 420 | + end | |
| 421 | + | |
| 422 | + test "will not delete another user's plani", ctx do | |
| 423 | + theirs = plani_for(ctx.them) | |
| 424 | + {:ok, live, _html} = live(ctx.conn, Routes.plani_index_path(ctx.conn, :index)) | |
| 425 | + | |
| 426 | + forge(live, "delete", %{"id" => to_string(theirs.id)}) | |
| 427 | + | |
| 428 | + assert Repo.reload(theirs) | |
| 429 | + end | |
| 430 | + end | |
| 390 | 431 | end |
Parents: 099a0e1