Merge pull request #1977 from cisagov/za/1924-remove-domain-info-for-analysts

Ticket #1924: Remove domain info for analysts
This commit is contained in:
zandercymatics 2024-04-03 10:39:34 -06:00 committed by GitHub
commit 07f0fd9b93
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 163 additions and 10 deletions

View file

@ -1436,6 +1436,13 @@ class DomainInformationInline(admin.StackedInline):
"submitter",
]
def has_change_permission(self, request, obj=None):
"""Custom has_change_permission override so that we can specify that
analysts can edit this through this inline, but not through the model normally"""
if request.user.has_perm("registrar.analyst_access_permission"):
return True
return super().has_change_permission(request, obj)
def formfield_for_manytomany(self, db_field, request, **kwargs):
"""customize the behavior of formfields with manytomany relationships. the customized
behavior includes sorting of objects in lists as well as customizing helper text"""

View file

@ -0,0 +1,37 @@
# This migration creates the create_full_access_group and create_cisa_analyst_group groups
# It is dependent on 0079 (which populates federal agencies)
# If permissions on the groups need changing, edit CISA_ANALYST_GROUP_PERMISSIONS
# in the user_group model then:
# [NOT RECOMMENDED]
# step 1: docker-compose exec app ./manage.py migrate --fake registrar 0035_contenttypes_permissions
# step 2: docker-compose exec app ./manage.py migrate registrar 0036_create_groups
# step 3: fake run the latest migration in the migrations list
# [RECOMMENDED]
# Alternatively:
# step 1: duplicate the migration that loads data
# step 2: docker-compose exec app ./manage.py migrate
from django.db import migrations
from registrar.models import UserGroup
from typing import Any
# For linting: RunPython expects a function reference,
# so let's give it one
def create_groups(apps, schema_editor) -> Any:
UserGroup.create_cisa_analyst_group(apps, schema_editor)
UserGroup.create_full_access_group(apps, schema_editor)
class Migration(migrations.Migration):
dependencies = [
("registrar", "0080_create_groups_v09"),
]
operations = [
migrations.RunPython(
create_groups,
reverse_code=migrations.RunPython.noop,
atomic=True,
),
]

View file

@ -26,11 +26,6 @@ class UserGroup(Group):
"model": "contact",
"permissions": ["change_contact"],
},
{
"app_label": "registrar",
"model": "domaininformation",
"permissions": ["change_domaininformation"],
},
{
"app_label": "registrar",
"model": "domainrequest",

View file

@ -129,6 +129,83 @@ class TestDomainAdmin(MockEppLib, WebTest):
)
mock_add_message.assert_has_calls([expected_call], 1)
@less_console_noise_decorator
def test_analyst_can_see_inline_domain_information_in_domain_change_form(self):
"""Tests if an analyst can still see the inline domain information form"""
# Create fake creator
_creator = User.objects.create(
username="MrMeoward",
first_name="Meoward",
last_name="Jones",
)
# Create a fake domain request
_domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
# Creates a Domain and DomainInformation object
_domain_request.approve()
domain_information = DomainInformation.objects.filter(domain_request=_domain_request).get()
domain_information.organization_name = "MonkeySeeMonkeyDo"
domain_information.save()
# We use filter here rather than just domain_information.domain just to get the latest data.
domain = Domain.objects.filter(domain_info=domain_information).get()
p = "userpass"
self.client.login(username="staffuser", password=p)
response = self.client.get(
"/admin/registrar/domain/{}/change/".format(domain.pk),
follow=True,
)
# Make sure the page loaded, and that we're on the right page
self.assertEqual(response.status_code, 200)
self.assertContains(response, domain.name)
# Test for data. We only need to test one since its all interconnected.
expected_organization_name = "MonkeySeeMonkeyDo"
self.assertContains(response, expected_organization_name)
@less_console_noise_decorator
def test_admin_can_see_inline_domain_information_in_domain_change_form(self):
"""Tests if an admin can still see the inline domain information form"""
# Create fake creator
_creator = User.objects.create(
username="MrMeoward",
first_name="Meoward",
last_name="Jones",
)
# Create a fake domain request
_domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
# Creates a Domain and DomainInformation object
_domain_request.approve()
domain_information = DomainInformation.objects.filter(domain_request=_domain_request).get()
domain_information.organization_name = "MonkeySeeMonkeyDo"
domain_information.save()
# We use filter here rather than just domain_information.domain just to get the latest data.
domain = Domain.objects.filter(domain_info=domain_information).get()
p = "adminpass"
self.client.login(username="superuser", password=p)
response = self.client.get(
"/admin/registrar/domain/{}/change/".format(domain.pk),
follow=True,
)
# Make sure the page loaded, and that we're on the right page
self.assertEqual(response.status_code, 200)
self.assertContains(response, domain.name)
# Test for data. We only need to test one since its all interconnected.
expected_organization_name = "MonkeySeeMonkeyDo"
self.assertContains(response, expected_organization_name)
@patch("registrar.admin.DomainAdmin._get_current_date", return_value=date(2024, 1, 1))
def test_extend_expiration_date_button_epp(self, mock_date_today):
"""
@ -2026,8 +2103,8 @@ class TestDomainInformationAdmin(TestCase):
# Get the other contact
other_contact = domain_info.other_contacts.all().first()
p = "userpass"
self.client.login(username="staffuser", password=p)
p = "adminpass"
self.client.login(username="superuser", password=p)
response = self.client.get(
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
@ -2048,6 +2125,44 @@ class TestDomainInformationAdmin(TestCase):
expected_url = "Testy Tester</a>"
self.assertContains(response, expected_url)
@less_console_noise_decorator
def test_analyst_cant_access_domain_information(self):
"""Ensures that analysts can't directly access the DomainInformation page through /admin"""
# Create fake creator
_creator = User.objects.create(
username="MrMeoward",
first_name="Meoward",
last_name="Jones",
)
# Create a fake domain request
domain_request = completed_domain_request(status=DomainRequest.DomainRequestStatus.IN_REVIEW, user=_creator)
domain_request.approve()
domain_info = DomainInformation.objects.filter(domain=domain_request.approved_domain).get()
p = "userpass"
self.client.login(username="staffuser", password=p)
response = self.client.get(
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
follow=True,
)
# Make sure that we're denied access
self.assertEqual(response.status_code, 403)
# To make sure that its not a fluke, swap to an admin user
# and try to access the same page. This should succeed.
p = "adminpass"
self.client.login(username="superuser", password=p)
response = self.client.get(
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
follow=True,
)
# Make sure the page loaded, and that we're on the right page
self.assertEqual(response.status_code, 200)
self.assertContains(response, domain_info.domain.name)
@less_console_noise_decorator
def test_contact_fields_have_detail_table(self):
"""Tests if the contact fields have the detail table which displays title, email, and phone"""
@ -2071,8 +2186,8 @@ class TestDomainInformationAdmin(TestCase):
domain_request.approve()
domain_info = DomainInformation.objects.filter(domain=domain_request.approved_domain).get()
p = "userpass"
self.client.login(username="staffuser", password=p)
p = "adminpass"
self.client.login(username="superuser", password=p)
response = self.client.get(
"/admin/registrar/domaininformation/{}/change/".format(domain_info.pk),
follow=True,

View file

@ -34,7 +34,6 @@ class TestGroups(TestCase):
"view_logentry",
"change_contact",
"view_domain",
"change_domaininformation",
"add_domaininvitation",
"view_domaininvitation",
"change_domainrequest",