towerops/test/towerops_web/permissions_test.exs
2026-06-13 18:20:20 -05:00

429 lines
13 KiB
Elixir

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