Skip to content

Restricted routes should work without can permissions #777

@Tal-Shavit

Description

@Tal-Shavit

Describe the bug
When I add only: [:index] in the router, I get an error no match of right hand side value: nil.
To fix this, I need to add can to allow only the index action, or not allow the new action. But it shouldn’t be like that. Once I allow the route for index only, I shouldn’t need to add can, it should directly create the route for index only.

To Reproduce
Steps to reproduce the behavior:

  1. Configurer live_resources route with only: [:index] or use except: [:new].
  2. Visit index page.
  3. See the error.

Expected behavior
When using only: [:index] in the router, the index action should work without requiring explicit can permissions.

Please complete the following information:
OS: MacOS
Browser Checked on Chrome, Safari, Firefox
Elixir Version 1.17.2
Backpex Version 0.10.0

Code example

Mix.install([
  {:phoenix_playground, "~> 0.1.6"},
  {:backpex, "~> 0.10.0"},
  {:phoenix_pubsub, "~> 2.1"}
])

defmodule CustomAdapter do
  use Backpex.Adapter
  require Logger

  @impl Backpex.Adapter
  def get(_id, _assigns, _live_resource) do
    raise "not implemented yet"
  end

  @impl Backpex.Adapter
  def get!(id, _assigns, _live_resource) do
    %{id: "1", name: "Ido"}
  end

  @impl Backpex.Adapter
  def list(_fields, assigns, _config, criteria) do
    [%{id: "1", name: "Ido"}]
  end

  @impl Backpex.Adapter
  def count(_fields, _assigns, _config, _criteria) do
    100
  end

  @impl Backpex.Adapter
  def delete_all(_items, _live_resource) do
    raise "not implemented yet"
  end

  @impl Backpex.Adapter
  def insert(_item, _config) do
    raise "not implemented yet"
  end

  @impl Backpex.Adapter
  def update(_item, _config) do
    raise "not implemented yet"
  end

  @impl Backpex.Adapter
  def update_all(_items, _updates, _config) do
    raise "not implemented yet"
  end

  @impl Backpex.Adapter
  def change(_item, _attrs, _fields, _assigns, _config, _opts) do
    raise "not implemented yet"
  end
end

defmodule BackpexDemoLive do
  use Phoenix.LiveView

  use Backpex.LiveResource,
    adapter: CustomAdapter,
    adapter_config: [],
    layout: {BackpexDemoLive, :layout},
    pubsub: [
      name: :pubsub,
      topic: "admin:brands",
      event_prefix: "brands_"
    ]

  @impl Backpex.LiveResource
  def singular_name, do: "Brand"

  @impl Backpex.LiveResource
  def plural_name, do: "Brands"

  @impl Backpex.LiveResource
  def item_actions(default_actions) do
    default_actions
    |> Keyword.drop([:delete])
    |> Keyword.drop([:edit])
  end

  @impl Backpex.LiveResource

  # def can?(_assigns, :index, _item), do: true

  # def can?(_assigns, _action, _item), do: false

  @impl Backpex.LiveResource
  def fields do
    [
      id: %{
        module: Backpex.Fields.Text,
        label: "Id",
        only: [:index]
      },
      name: %{
        module: Backpex.Fields.Text,
        label: "Name",
        only: [:index]
      }
    ]
  end

  def layout(assigns) do
    assigns = assign(assigns, :current_url, "/")

    ~H"""
    <Backpex.HTML.Layout.app_shell fluid={@fluid?}>
      <:topbar>
        <Backpex.HTML.Layout.topbar_branding />

        <Backpex.HTML.Layout.topbar_dropdown>
          <:label>
            <label tabindex="0" class="btn btn-square btn-ghost">
              label
            </label>
          </:label>
          <li>
            <.link navigate="/" class="flex justify-between text-red-600 hover:bg-gray-100">
              <p>Logout</p>
            </.link>
          </li>
        </Backpex.HTML.Layout.topbar_dropdown>
      </:topbar>
      <:sidebar></:sidebar>
      <Backpex.HTML.Layout.flash_messages flash={@flash} />
      {@inner_content}
    </Backpex.HTML.Layout.app_shell>
    """
  end
end

defmodule DemoRouter do
  use Phoenix.Router
  import Phoenix.LiveView.Router
  import Backpex.Router

  pipeline :browser do
    plug :accepts, ["html"]
    plug :fetch_session
    plug :put_root_layout, html: {PhoenixPlayground.Layout, :root}
    plug :put_secure_browser_headers
  end

  scope "/demo" do
    pipe_through :browser

    backpex_routes()

    live_session :default, on_mount: Backpex.InitAssigns do
      live_resources("/", BackpexDemoLive, only: [:index])
    end
  end
end

children = [
  {Phoenix.PubSub, name: :pubsub}
]

Supervisor.start_link(children, strategy: :one_for_one)

PhoenixPlayground.start(plug: DemoRouter)

Note: To fix the issue, remove can from the comment.

Metadata

Metadata

Assignees

No one assigned

    Labels

    needs-discussionAn issue that still needs speficiation.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions