Skip to content

Restricted routes should work without can permissions #777

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.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to 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