defmodule ToweropsWeb.PermissionsTest do use Towerops.DataCase, async: true import Towerops.AccountsFixtures import Towerops.OrganizationsFixtures alias Phoenix.LiveView.Socket alias Towerops.Accounts.Scope alias Towerops.Repo alias ToweropsWeb.Permissions doctest Permissions, except: [can?: 3, owner?: 1, admin?: 1] describe "can?/3 with superuser" do setup do user = user_fixture(%{is_superuser: true}) organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) %{scope: scope, user: user, organization: organization} end test "superuser can perform any action", %{scope: scope} do # Test various actions and resources assert Permissions.can?(scope, :delete, :organization) assert Permissions.can?(scope, :delete, :device) assert Permissions.can?(scope, :edit, :device) assert Permissions.can?(scope, :create, :device) assert Permissions.can?(scope, :delete, :backup) assert Permissions.can?(scope, :manage, :anything) end test "superuser can? works with Socket", %{scope: scope} do socket = %Socket{assigns: %{current_scope: scope}} assert Permissions.can?(socket, :delete, :organization) assert Permissions.can?(socket, :delete, :device) end end describe "can?/3 with owner role" do setup do user = user_fixture() organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) %{scope: scope, user: user, organization: organization} end test "owner can perform any action", %{scope: scope} do assert Permissions.can?(scope, :delete, :organization) assert Permissions.can?(scope, :delete, :device) assert Permissions.can?(scope, :edit, :device) assert Permissions.can?(scope, :create, :device) assert Permissions.can?(scope, :delete, :backup) assert Permissions.can?(scope, :create, :invitation) end end describe "can?/3 with admin role" do setup do owner = user_fixture() organization = organization_fixture(owner.id) admin_user = user_fixture() membership_fixture(organization.id, admin_user.id, :admin) organization = Repo.preload(organization, :memberships, force: true) scope = admin_user |> Scope.for_user() |> Scope.put_organization(organization) %{scope: scope, user: admin_user, organization: organization} end test "admin can perform most actions", %{scope: scope} do assert Permissions.can?(scope, :edit, :device) assert Permissions.can?(scope, :create, :device) assert Permissions.can?(scope, :delete, :device) assert Permissions.can?(scope, :delete, :backup) assert Permissions.can?(scope, :create, :invitation) assert Permissions.can?(scope, :view, :organization) end test "admin cannot delete organization", %{scope: scope} do refute Permissions.can?(scope, :delete, :organization) end end describe "can?/3 with member role" do setup do owner = user_fixture() organization = organization_fixture(owner.id) member_user = user_fixture() membership_fixture(organization.id, member_user.id, :member) organization = Repo.preload(organization, :memberships, force: true) scope = member_user |> Scope.for_user() |> Scope.put_organization(organization) %{scope: scope, user: member_user, organization: organization} end test "member can view and edit devices", %{scope: scope} do assert Permissions.can?(scope, :view, :device) assert Permissions.can?(scope, :list, :device) assert Permissions.can?(scope, :create, :device) assert Permissions.can?(scope, :edit, :device) end test "member can view and edit sites", %{scope: scope} do assert Permissions.can?(scope, :view, :site) assert Permissions.can?(scope, :list, :site) assert Permissions.can?(scope, :create, :site) assert Permissions.can?(scope, :edit, :site) end test "member can view and edit alerts", %{scope: scope} do assert Permissions.can?(scope, :view, :alert) assert Permissions.can?(scope, :list, :alert) assert Permissions.can?(scope, :create, :alert) assert Permissions.can?(scope, :edit, :alert) end test "member cannot delete anything", %{scope: scope} do refute Permissions.can?(scope, :delete, :device) refute Permissions.can?(scope, :delete, :site) refute Permissions.can?(scope, :delete, :alert) refute Permissions.can?(scope, :delete, :backup) refute Permissions.can?(scope, :delete, :organization) end test "member cannot manage memberships", %{scope: scope} do refute Permissions.can?(scope, :create, :membership) refute Permissions.can?(scope, :edit, :membership) end test "member cannot manage invitations", %{scope: scope} do refute Permissions.can?(scope, :create, :invitation) refute Permissions.can?(scope, :delete, :invitation) end test "member can view organization", %{scope: scope} do assert Permissions.can?(scope, :view, :organization) assert Permissions.can?(scope, :list, :organization) end end describe "can?/3 with viewer role" do setup do owner = user_fixture() organization = organization_fixture(owner.id) viewer_user = user_fixture() membership_fixture(organization.id, viewer_user.id, :viewer) organization = Repo.preload(organization, :memberships, force: true) scope = viewer_user |> Scope.for_user() |> Scope.put_organization(organization) %{scope: scope, user: viewer_user, organization: organization} end test "viewer can only view resources", %{scope: scope} do assert Permissions.can?(scope, :view, :device) assert Permissions.can?(scope, :list, :device) assert Permissions.can?(scope, :view, :site) assert Permissions.can?(scope, :list, :site) assert Permissions.can?(scope, :view, :organization) end test "viewer cannot perform any write actions", %{scope: scope} do refute Permissions.can?(scope, :create, :device) refute Permissions.can?(scope, :edit, :device) refute Permissions.can?(scope, :delete, :device) refute Permissions.can?(scope, :create, :site) refute Permissions.can?(scope, :edit, :site) refute Permissions.can?(scope, :delete, :site) end end describe "can?/3 with no organization context" do test "returns false when scope has no organization" do user = user_fixture() scope = Scope.for_user(user) refute Permissions.can?(scope, :view, :device) refute Permissions.can?(scope, :edit, :device) refute Permissions.can?(scope, :delete, :device) end end describe "can?/3 with nil scope" do test "returns false for nil scope" do refute Permissions.can?(nil, :view, :device) refute Permissions.can?(nil, :edit, :device) refute Permissions.can?(nil, :delete, :device) end end describe "owner?/1 with various roles" do test "returns true for superuser" do user = user_fixture(%{is_superuser: true}) organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) assert Permissions.owner?(scope) end test "returns true for owner role" do user = user_fixture() organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) assert Permissions.owner?(scope) end test "returns false for admin role" do owner = user_fixture() organization = organization_fixture(owner.id) admin_user = user_fixture() membership_fixture(organization.id, admin_user.id, :admin) organization = Repo.preload(organization, :memberships, force: true) scope = admin_user |> Scope.for_user() |> Scope.put_organization(organization) refute Permissions.owner?(scope) end test "returns false for member role" do owner = user_fixture() organization = organization_fixture(owner.id) member_user = user_fixture() membership_fixture(organization.id, member_user.id, :member) organization = Repo.preload(organization, :memberships, force: true) scope = member_user |> Scope.for_user() |> Scope.put_organization(organization) refute Permissions.owner?(scope) end test "returns false for viewer role" do owner = user_fixture() organization = organization_fixture(owner.id) viewer_user = user_fixture() membership_fixture(organization.id, viewer_user.id, :viewer) organization = Repo.preload(organization, :memberships, force: true) scope = viewer_user |> Scope.for_user() |> Scope.put_organization(organization) refute Permissions.owner?(scope) end test "returns false when no organization context" do user = user_fixture() scope = Scope.for_user(user) refute Permissions.owner?(scope) end test "returns false for nil scope" do refute Permissions.owner?(nil) end test "works with Socket" do user = user_fixture() organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) socket = %Socket{assigns: %{current_scope: scope}} assert Permissions.owner?(socket) end end describe "admin?/1 with various roles" do test "returns true for superuser" do user = user_fixture(%{is_superuser: true}) organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) assert Permissions.admin?(scope) end test "returns true for owner role" do user = user_fixture() organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) assert Permissions.admin?(scope) end test "returns true for admin role" do owner = user_fixture() organization = organization_fixture(owner.id) admin_user = user_fixture() membership_fixture(organization.id, admin_user.id, :admin) organization = Repo.preload(organization, :memberships, force: true) scope = admin_user |> Scope.for_user() |> Scope.put_organization(organization) assert Permissions.admin?(scope) end test "returns false for member role" do owner = user_fixture() organization = organization_fixture(owner.id) member_user = user_fixture() membership_fixture(organization.id, member_user.id, :member) organization = Repo.preload(organization, :memberships, force: true) scope = member_user |> Scope.for_user() |> Scope.put_organization(organization) refute Permissions.admin?(scope) end test "returns false for viewer role" do owner = user_fixture() organization = organization_fixture(owner.id) viewer_user = user_fixture() membership_fixture(organization.id, viewer_user.id, :viewer) organization = Repo.preload(organization, :memberships, force: true) scope = viewer_user |> Scope.for_user() |> Scope.put_organization(organization) refute Permissions.admin?(scope) end test "returns false when no organization context" do user = user_fixture() scope = Scope.for_user(user) refute Permissions.admin?(scope) end test "returns false for nil scope" do refute Permissions.admin?(nil) end test "works with Socket" do user = user_fixture() organization = organization_fixture(user.id) organization = Repo.preload(organization, :memberships) scope = user |> Scope.for_user() |> Scope.put_organization(organization) socket = %Socket{assigns: %{current_scope: scope}} assert Permissions.admin?(socket) end end end