mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-25 03:58:39 +02:00
Add Unit tests
This commit is contained in:
parent
24480ec434
commit
c551a60e3a
5 changed files with 174 additions and 6 deletions
|
@ -274,9 +274,9 @@ class BasePortfolioMemberForm(forms.Form):
|
||||||
# Build form data based on role.
|
# Build form data based on role.
|
||||||
form_data = {
|
form_data = {
|
||||||
"role": role,
|
"role": role,
|
||||||
"member_permission_admin": member_permission.value if is_admin else None,
|
"member_permission_admin": getattr(member_permission, "value", None) if is_admin else None,
|
||||||
"domain_request_permission_admin": domain_request_permission.value if is_admin else None,
|
"domain_request_permission_admin": getattr(domain_request_permission, "value", None) if is_admin else None,
|
||||||
"domain_request_permission_member": domain_request_permission.value if not is_admin else None,
|
"domain_request_permission_member": getattr(domain_request_permission, "value", None) if not is_admin else None,
|
||||||
}
|
}
|
||||||
|
|
||||||
# Edgecase: Member uses a special form value for None called "no_access". This ensures a form selection.
|
# Edgecase: Member uses a special form value for None called "no_access". This ensures a form selection.
|
||||||
|
|
|
@ -8,6 +8,7 @@ import logging
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class UserPortfolioRoleChoices(models.TextChoices):
|
class UserPortfolioRoleChoices(models.TextChoices):
|
||||||
"""
|
"""
|
||||||
Roles make it easier for admins to look at
|
Roles make it easier for admins to look at
|
||||||
|
@ -23,7 +24,7 @@ class UserPortfolioRoleChoices(models.TextChoices):
|
||||||
except ValueError:
|
except ValueError:
|
||||||
logger.warning(f"Invalid portfolio role: {user_portfolio_role}")
|
logger.warning(f"Invalid portfolio role: {user_portfolio_role}")
|
||||||
return f"Unknown ({user_portfolio_role})"
|
return f"Unknown ({user_portfolio_role})"
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_role_description(cls, user_portfolio_role):
|
def get_role_description(cls, user_portfolio_role):
|
||||||
"""Returns a detailed description for a given role."""
|
"""Returns a detailed description for a given role."""
|
||||||
|
@ -37,7 +38,7 @@ class UserPortfolioRoleChoices(models.TextChoices):
|
||||||
"organization domain requests and submit domain requests on behalf of the organization. Basic access "
|
"organization domain requests and submit domain requests on behalf of the organization. Basic access "
|
||||||
"members can’t view all members of an organization or manage them. "
|
"members can’t view all members of an organization or manage them. "
|
||||||
"Domain management can be assigned separately."
|
"Domain management can be assigned separately."
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
return descriptions.get(user_portfolio_role)
|
return descriptions.get(user_portfolio_role)
|
||||||
|
|
||||||
|
|
|
@ -2642,3 +2642,170 @@ class TestPortfolioInviteNewMemberView(TestWithUser, WebTest):
|
||||||
# Validate Database has not changed
|
# Validate Database has not changed
|
||||||
invite_count_after = PortfolioInvitation.objects.count()
|
invite_count_after = PortfolioInvitation.objects.count()
|
||||||
self.assertEqual(invite_count_after, invite_count_before)
|
self.assertEqual(invite_count_after, invite_count_before)
|
||||||
|
|
||||||
|
|
||||||
|
class TestEditPortfolioMemberView(WebTest):
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
self.user = create_user()
|
||||||
|
# Create Portfolio
|
||||||
|
self.portfolio = Portfolio.objects.create(creator=self.user, organization_name="Test Portfolio")
|
||||||
|
|
||||||
|
# Add an invited member who has been invited to manage domains
|
||||||
|
self.invited_member_email = "invited@example.com"
|
||||||
|
self.invitation = PortfolioInvitation.objects.create(
|
||||||
|
email=self.invited_member_email,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
|
||||||
|
additional_permissions=[
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBERS,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
# Assign permissions to the user making requests
|
||||||
|
UserPortfolioPermission.objects.create(
|
||||||
|
user=self.user,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_ADMIN],
|
||||||
|
additional_permissions=[
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBERS,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_MEMBERS,
|
||||||
|
],
|
||||||
|
)
|
||||||
|
|
||||||
|
def tearDown(self):
|
||||||
|
PortfolioInvitation.objects.all().delete()
|
||||||
|
UserPortfolioPermission.objects.all().delete()
|
||||||
|
Portfolio.objects.all().delete()
|
||||||
|
User.objects.all().delete()
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_members", active=True)
|
||||||
|
def test_edit_member_permissions_basic_to_admin(self):
|
||||||
|
"""Tests converting a basic member to admin with full permissions."""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
# Create a basic member to edit
|
||||||
|
basic_member = create_test_user()
|
||||||
|
basic_permission = UserPortfolioPermission.objects.create(
|
||||||
|
user=basic_member,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER],
|
||||||
|
additional_permissions=[UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS]
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("member-permissions", kwargs={"pk": basic_permission.id}),
|
||||||
|
{
|
||||||
|
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN,
|
||||||
|
"domain_request_permission_admin": UserPortfolioPermissionChoices.EDIT_REQUESTS,
|
||||||
|
"member_permission_admin": UserPortfolioPermissionChoices.EDIT_MEMBERS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
# Verify redirect and success message
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
# Verify database changes
|
||||||
|
basic_permission.refresh_from_db()
|
||||||
|
self.assertEqual(basic_permission.roles, [UserPortfolioRoleChoices.ORGANIZATION_ADMIN])
|
||||||
|
# We expect view permissions to be added automagically
|
||||||
|
self.assertEqual(
|
||||||
|
set(basic_permission.additional_permissions),
|
||||||
|
{
|
||||||
|
UserPortfolioPermissionChoices.EDIT_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_MEMBERS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBERS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_members", active=True)
|
||||||
|
def test_edit_member_permissions_validation(self):
|
||||||
|
"""Tests form validation for required fields based on role."""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
member = create_test_user()
|
||||||
|
permission = UserPortfolioPermission.objects.create(
|
||||||
|
user=member,
|
||||||
|
portfolio=self.portfolio,
|
||||||
|
roles=[UserPortfolioRoleChoices.ORGANIZATION_MEMBER]
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test missing required admin permissions
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("member-permissions", kwargs={"pk": permission.id}),
|
||||||
|
{
|
||||||
|
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN,
|
||||||
|
# Missing required admin fields
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertEqual(
|
||||||
|
response.context["form"].errors["domain_request_permission_admin"][0],
|
||||||
|
"Admin domain request permission is required"
|
||||||
|
)
|
||||||
|
self.assertEqual(
|
||||||
|
response.context["form"].errors["member_permission_admin"][0],
|
||||||
|
"Admin member permission is required"
|
||||||
|
)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_members", active=True)
|
||||||
|
def test_edit_invited_member_permissions(self):
|
||||||
|
"""Tests editing permissions for an invited (but not yet joined) member."""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
# Test updating invitation permissions
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("invitedmember-permissions", kwargs={"pk": self.invitation.id}),
|
||||||
|
{
|
||||||
|
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN,
|
||||||
|
"domain_request_permission_admin": UserPortfolioPermissionChoices.EDIT_REQUESTS,
|
||||||
|
"member_permission_admin": UserPortfolioPermissionChoices.EDIT_MEMBERS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
|
||||||
|
# Verify invitation was updated
|
||||||
|
self.invitation.refresh_from_db()
|
||||||
|
self.assertEqual(self.invitation.roles, [UserPortfolioRoleChoices.ORGANIZATION_ADMIN])
|
||||||
|
self.assertEqual(
|
||||||
|
set(self.invitation.additional_permissions),
|
||||||
|
{
|
||||||
|
UserPortfolioPermissionChoices.EDIT_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
|
||||||
|
UserPortfolioPermissionChoices.EDIT_MEMBERS,
|
||||||
|
UserPortfolioPermissionChoices.VIEW_MEMBERS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
@override_flag("organization_feature", active=True)
|
||||||
|
@override_flag("organization_members", active=True)
|
||||||
|
def test_admin_removing_own_admin_role(self):
|
||||||
|
"""Tests an admin removing their own admin role redirects to home."""
|
||||||
|
self.client.force_login(self.user)
|
||||||
|
|
||||||
|
# Get the user's admin permission
|
||||||
|
admin_permission = UserPortfolioPermission.objects.get(
|
||||||
|
user=self.user,
|
||||||
|
portfolio=self.portfolio
|
||||||
|
)
|
||||||
|
|
||||||
|
response = self.client.post(
|
||||||
|
reverse("member-permissions", kwargs={"pk": admin_permission.id}),
|
||||||
|
{
|
||||||
|
"role": UserPortfolioRoleChoices.ORGANIZATION_MEMBER,
|
||||||
|
"domain_request_permission_member": UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(response["Location"], reverse("home"))
|
||||||
|
|
|
@ -10,7 +10,6 @@ from registrar.models import Portfolio, User
|
||||||
from registrar.models.portfolio_invitation import PortfolioInvitation
|
from registrar.models.portfolio_invitation import PortfolioInvitation
|
||||||
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
from registrar.models.user_portfolio_permission import UserPortfolioPermission
|
||||||
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
|
||||||
from registrar.utility.email import EmailSendingError
|
|
||||||
from registrar.views.utility.mixins import PortfolioMemberPermission
|
from registrar.views.utility.mixins import PortfolioMemberPermission
|
||||||
from registrar.views.utility.permission_views import (
|
from registrar.views.utility.permission_views import (
|
||||||
PortfolioDomainRequestsPermissionView,
|
PortfolioDomainRequestsPermissionView,
|
||||||
|
|
|
@ -70,6 +70,7 @@
|
||||||
10038 OUTOFSCOPE http://app:8080/org-name-address
|
10038 OUTOFSCOPE http://app:8080/org-name-address
|
||||||
10038 OUTOFSCOPE http://app:8080/domain_requests/
|
10038 OUTOFSCOPE http://app:8080/domain_requests/
|
||||||
10038 OUTOFSCOPE http://app:8080/domains/
|
10038 OUTOFSCOPE http://app:8080/domains/
|
||||||
|
10038 OUTOFSCOPE http://app:8080/domains/edit
|
||||||
10038 OUTOFSCOPE http://app:8080/organization/
|
10038 OUTOFSCOPE http://app:8080/organization/
|
||||||
10038 OUTOFSCOPE http://app:8080/permissions
|
10038 OUTOFSCOPE http://app:8080/permissions
|
||||||
10038 OUTOFSCOPE http://app:8080/suborganization/
|
10038 OUTOFSCOPE http://app:8080/suborganization/
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue