Merge branch 'za/3622-warn-org-admins' into backup/3622-warn-org-admins

This commit is contained in:
zandercymatics 2025-03-26 12:15:00 -06:00
commit 3bf3c5a8a6
No known key found for this signature in database
GPG key ID: FF4636ABEC9682B7
4 changed files with 32 additions and 35 deletions

View file

@ -418,18 +418,15 @@ class PortfolioMemberForm(BasePortfolioMemberForm):
""" """
super().clean() super().clean()
role = self.cleaned_data.get("role") role = self.cleaned_data.get("role")
if role and self.instance.user.is_only_admin_of_portfolio(self.instance.portfolio): if self.instance and hasattr(self.instance, "user") and hasattr(self.instance, "portfolio"):
# This is how you associate a validation error to a particular field. if role and self.instance.user.is_only_admin_of_portfolio(self.instance.portfolio):
# The alternative is to do this in clean_role, but execution order matters. # This is how you associate a validation error to a particular field.
raise forms.ValidationError( # The alternative is to do this in clean_role, but execution order matters.
{ raise forms.ValidationError({"role": forms.ValidationError(
"role": forms.ValidationError( "You can't change your member access because you're "
"You can't change your member access because you're " "the only admin for this organization. "
"the only admin for this organization. " "To change your access, you'll need to add another admin."
"To change your access, you'll need to add another admin." )})
)
}
)
class PortfolioInvitedMemberForm(BasePortfolioMemberForm): class PortfolioInvitedMemberForm(BasePortfolioMemberForm):

View file

@ -474,7 +474,7 @@ class User(AbstractUser):
admin_count = admins.count() admin_count = admins.count()
# Check if the current user is in the list of admins # Check if the current user is in the list of admins
if admin_count == 1 and admins.first().user == self: if admin_count == 1 and admins.first() and admins.first().user == self:
return True # The user is the only admin return True # The user is the only admin
# If there are other admins or the user is not the only one # If there are other admins or the user is not the only one

View file

@ -477,8 +477,8 @@ class TestBasePortfolioMemberForms(TestCase):
self.assertTrue(form.is_valid(), f"Form {form_class.__name__} failed validation with data: {data}") self.assertTrue(form.is_valid(), f"Form {form_class.__name__} failed validation with data: {data}")
return form return form
def _assert_form_has_error(self, form_class, data, field_name): def _assert_form_has_error(self, form_class, data, field_name, instance=None):
form = form_class(data=data) form = form_class(data=data, instance=instance)
self.assertFalse(form.is_valid()) self.assertFalse(form.is_valid())
self.assertIn(field_name, form.errors) self.assertIn(field_name, form.errors)
@ -504,17 +504,23 @@ class TestBasePortfolioMemberForms(TestCase):
"domain_permissions": "", # Simulate missing field "domain_permissions": "", # Simulate missing field
"member_permissions": "", # Simulate missing field "member_permissions": "", # Simulate missing field
} }
user_portfolio_permission, _ = UserPortfolioPermission.objects.get_or_create(
portfolio=self.portfolio, user=self.user
)
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho")
# Check required fields for all forms # Check required fields for all forms
self._assert_form_has_error(PortfolioMemberForm, data, "domain_request_permissions") self._assert_form_has_error(PortfolioMemberForm, data, "domain_request_permissions", user_portfolio_permission)
self._assert_form_has_error(PortfolioMemberForm, data, "domain_permissions") self._assert_form_has_error(PortfolioMemberForm, data, "domain_permissions", user_portfolio_permission)
self._assert_form_has_error(PortfolioMemberForm, data, "member_permissions") self._assert_form_has_error(PortfolioMemberForm, data, "member_permissions", user_portfolio_permission)
self._assert_form_has_error(PortfolioInvitedMemberForm, data, "domain_request_permissions") self._assert_form_has_error(
self._assert_form_has_error(PortfolioInvitedMemberForm, data, "domain_permissions") PortfolioInvitedMemberForm, data, "domain_request_permissions", portfolio_invitation
self._assert_form_has_error(PortfolioInvitedMemberForm, data, "member_permissions") )
self._assert_form_has_error(PortfolioNewMemberForm, data, "domain_request_permissions") self._assert_form_has_error(PortfolioInvitedMemberForm, data, "domain_permissions", portfolio_invitation)
self._assert_form_has_error(PortfolioNewMemberForm, data, "domain_permissions") self._assert_form_has_error(PortfolioInvitedMemberForm, data, "member_permissions", portfolio_invitation)
self._assert_form_has_error(PortfolioNewMemberForm, data, "member_permissions") self._assert_form_has_error(PortfolioNewMemberForm, data, "domain_request_permissions", portfolio_invitation)
self._assert_form_has_error(PortfolioNewMemberForm, data, "domain_permissions", portfolio_invitation)
self._assert_form_has_error(PortfolioNewMemberForm, data, "member_permissions", portfolio_invitation)
@less_console_noise_decorator @less_console_noise_decorator
def test_clean_validates_required_fields_for_admin_role(self): def test_clean_validates_required_fields_for_admin_role(self):
@ -529,7 +535,6 @@ class TestBasePortfolioMemberForms(TestCase):
portfolio=self.portfolio, user=self.user portfolio=self.portfolio, user=self.user
) )
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho") portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho")
data = { data = {
"role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value, "role": UserPortfolioRoleChoices.ORGANIZATION_ADMIN.value,
} }
@ -677,6 +682,7 @@ class TestBasePortfolioMemberForms(TestCase):
@less_console_noise_decorator @less_console_noise_decorator
def test_invalid_data_for_member(self): def test_invalid_data_for_member(self):
"""Test invalid form submission for a member role with missing permissions.""" """Test invalid form submission for a member role with missing permissions."""
portfolio_invitation, _ = PortfolioInvitation.objects.get_or_create(portfolio=self.portfolio, email="hi@ho")
data = { data = {
"email": "hi@ho.com", "email": "hi@ho.com",
"portfolio": self.portfolio.id, "portfolio": self.portfolio.id,
@ -685,5 +691,5 @@ class TestBasePortfolioMemberForms(TestCase):
"member_permissions": "", # Missing field "member_permissions": "", # Missing field
"domain_permissions": "", # Missing field "domain_permissions": "", # Missing field
} }
self._assert_form_has_error(PortfolioMemberForm, data, "domain_request_permissions") self._assert_form_has_error(PortfolioMemberForm, data, "domain_request_permissions", portfolio_invitation)
self._assert_form_has_error(PortfolioInvitedMemberForm, data, "member_permissions") self._assert_form_has_error(PortfolioInvitedMemberForm, data, "member_permissions", portfolio_invitation)

View file

@ -1826,10 +1826,7 @@ class TestPortfolioMemberDeleteView(WebTest):
) )
self.assertEqual(response.status_code, 400) self.assertEqual(response.status_code, 400)
expected_error_message = ( expected_error_message = "the only admin for this organization"
"There must be at least one admin in your organization. Give another member admin "
"permissions, make sure they log into the registrar, and then remove this member."
)
self.assertContains(response, expected_error_message, status_code=400) self.assertContains(response, expected_error_message, status_code=400)
# assert that send_portfolio_admin_removal_emails is not called # assert that send_portfolio_admin_removal_emails is not called
@ -2155,10 +2152,7 @@ class TestPortfolioMemberDeleteView(WebTest):
self.assertEqual(response.status_code, 302) self.assertEqual(response.status_code, 302)
expected_error_message = ( expected_error_message = "the only admin for this organization."
"There must be at least one admin in your organization. Give another member admin "
"permissions, make sure they log into the registrar, and then remove this member."
)
args, kwargs = mock_error.call_args args, kwargs = mock_error.call_args
# Check if first arg is a WSGIRequest, confirms request object passed correctly # Check if first arg is a WSGIRequest, confirms request object passed correctly