mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-19 19:09:22 +02:00
Merge pull request #1981 from cisagov/za/1948-remove-draft-domain-and-websites
(on getgov-bob) Ticket #1948: Remove draft domain and websites for analysts
This commit is contained in:
commit
21638ad364
6 changed files with 258 additions and 15 deletions
|
@ -779,6 +779,46 @@ class WebsiteAdmin(ListHeaderAdmin):
|
||||||
]
|
]
|
||||||
search_help_text = "Search by website."
|
search_help_text = "Search by website."
|
||||||
|
|
||||||
|
def get_model_perms(self, request):
|
||||||
|
"""
|
||||||
|
Return empty perms dict thus hiding the model from admin index.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if analyst_perm and not superuser_perm:
|
||||||
|
return {}
|
||||||
|
return super().get_model_perms(request)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
"""
|
||||||
|
Allow analysts to access the change form directly via URL.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if analyst_perm and not superuser_perm:
|
||||||
|
return True
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
def response_change(self, request, obj):
|
||||||
|
"""
|
||||||
|
Override to redirect users back to the previous page after saving.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
return_path = request.GET.get("return_path")
|
||||||
|
|
||||||
|
# First, call the super method to perform the standard operations and capture the response
|
||||||
|
response = super().response_change(request, obj)
|
||||||
|
|
||||||
|
# Don't redirect to the website page on save if the user is an analyst.
|
||||||
|
# Rather, just redirect back to the originating page.
|
||||||
|
if (analyst_perm and not superuser_perm) and return_path:
|
||||||
|
# Redirect to the return path if it exists
|
||||||
|
return HttpResponseRedirect(return_path)
|
||||||
|
|
||||||
|
# If no redirection is needed, return the original response
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class UserDomainRoleAdmin(ListHeaderAdmin):
|
class UserDomainRoleAdmin(ListHeaderAdmin):
|
||||||
"""Custom user domain role admin class."""
|
"""Custom user domain role admin class."""
|
||||||
|
@ -1466,7 +1506,10 @@ class DomainInformationInline(admin.StackedInline):
|
||||||
def has_change_permission(self, request, obj=None):
|
def has_change_permission(self, request, obj=None):
|
||||||
"""Custom has_change_permission override so that we can specify that
|
"""Custom has_change_permission override so that we can specify that
|
||||||
analysts can edit this through this inline, but not through the model normally"""
|
analysts can edit this through this inline, but not through the model normally"""
|
||||||
if request.user.has_perm("registrar.analyst_access_permission"):
|
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if analyst_perm and not superuser_perm:
|
||||||
return True
|
return True
|
||||||
return super().has_change_permission(request, obj)
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
@ -1892,6 +1935,46 @@ class DraftDomainAdmin(ListHeaderAdmin):
|
||||||
# in autocomplete_fields for user
|
# in autocomplete_fields for user
|
||||||
ordering = ["name"]
|
ordering = ["name"]
|
||||||
|
|
||||||
|
def get_model_perms(self, request):
|
||||||
|
"""
|
||||||
|
Return empty perms dict thus hiding the model from admin index.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if analyst_perm and not superuser_perm:
|
||||||
|
return {}
|
||||||
|
return super().get_model_perms(request)
|
||||||
|
|
||||||
|
def has_change_permission(self, request, obj=None):
|
||||||
|
"""
|
||||||
|
Allow analysts to access the change form directly via URL.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
if analyst_perm and not superuser_perm:
|
||||||
|
return True
|
||||||
|
return super().has_change_permission(request, obj)
|
||||||
|
|
||||||
|
def response_change(self, request, obj):
|
||||||
|
"""
|
||||||
|
Override to redirect users back to the previous page after saving.
|
||||||
|
"""
|
||||||
|
superuser_perm = request.user.has_perm("registrar.full_access_permission")
|
||||||
|
analyst_perm = request.user.has_perm("registrar.analyst_access_permission")
|
||||||
|
return_path = request.GET.get("return_path")
|
||||||
|
|
||||||
|
# First, call the super method to perform the standard operations and capture the response
|
||||||
|
response = super().response_change(request, obj)
|
||||||
|
|
||||||
|
# Don't redirect to the website page on save if the user is an analyst.
|
||||||
|
# Rather, just redirect back to the originating page.
|
||||||
|
if (analyst_perm and not superuser_perm) and return_path:
|
||||||
|
# Redirect to the return path if it exists
|
||||||
|
return HttpResponseRedirect(return_path)
|
||||||
|
|
||||||
|
# If no redirection is needed, return the original response
|
||||||
|
return response
|
||||||
|
|
||||||
|
|
||||||
class PublicContactAdmin(ListHeaderAdmin):
|
class PublicContactAdmin(ListHeaderAdmin):
|
||||||
"""Custom PublicContact admin class."""
|
"""Custom PublicContact admin class."""
|
||||||
|
|
37
src/registrar/migrations/0084_create_groups_v11.py
Normal file
37
src/registrar/migrations/0084_create_groups_v11.py
Normal 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", "0083_alter_contact_email_alter_publiccontact_email"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.RunPython(
|
||||||
|
create_groups,
|
||||||
|
reverse_code=migrations.RunPython.noop,
|
||||||
|
atomic=True,
|
||||||
|
),
|
||||||
|
]
|
|
@ -41,11 +41,6 @@ class UserGroup(Group):
|
||||||
"model": "domain",
|
"model": "domain",
|
||||||
"permissions": ["view_domain"],
|
"permissions": ["view_domain"],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"app_label": "registrar",
|
|
||||||
"model": "draftdomain",
|
|
||||||
"permissions": ["change_draftdomain"],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"app_label": "registrar",
|
"app_label": "registrar",
|
||||||
"model": "user",
|
"model": "user",
|
||||||
|
@ -56,11 +51,6 @@ class UserGroup(Group):
|
||||||
"model": "domaininvitation",
|
"model": "domaininvitation",
|
||||||
"permissions": ["add_domaininvitation", "view_domaininvitation"],
|
"permissions": ["add_domaininvitation", "view_domaininvitation"],
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"app_label": "registrar",
|
|
||||||
"model": "website",
|
|
||||||
"permissions": ["change_website"],
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"app_label": "registrar",
|
"app_label": "registrar",
|
||||||
"model": "userdomainrole",
|
"model": "userdomainrole",
|
||||||
|
|
|
@ -27,6 +27,10 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
</dl>
|
</dl>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% elif field.field.name == "requested_domain" %}
|
||||||
|
{% with current_path=request.get_full_path %}
|
||||||
|
<a class="margin-top-05 padding-top-05" href="{% url 'admin:registrar_draftdomain_change' original.requested_domain.id %}?{{ 'return_path='|add:current_path }}">{{ original.requested_domain }}</a>
|
||||||
|
{% endwith%}
|
||||||
{% elif field.field.name == "current_websites" %}
|
{% elif field.field.name == "current_websites" %}
|
||||||
{% comment %}
|
{% comment %}
|
||||||
The "website" model is essentially just a text field.
|
The "website" model is essentially just a text field.
|
||||||
|
@ -49,9 +53,11 @@ This is using a custom implementation fieldset.html (see admin/fieldset.html)
|
||||||
</div>
|
</div>
|
||||||
{% elif field.field.name == "alternative_domains" %}
|
{% elif field.field.name == "alternative_domains" %}
|
||||||
<div class="readonly">
|
<div class="readonly">
|
||||||
|
{% with current_path=request.get_full_path %}
|
||||||
{% for alt_domain in original.alternative_domains.all %}
|
{% for alt_domain in original.alternative_domains.all %}
|
||||||
<a href="{% url 'admin:registrar_website_change' alt_domain.id %}">{{ alt_domain }}</a>{% if not forloop.last %}, {% endif %}
|
<a href="{% url 'admin:registrar_website_change' alt_domain.id %}?{{ 'return_path='|add:current_path }}">{{ alt_domain }}</a>{% if not forloop.last %}, {% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
|
{% endwith %}
|
||||||
</div>
|
</div>
|
||||||
{% else %}
|
{% else %}
|
||||||
<div class="readonly">{{ field.contents }}</div>
|
<div class="readonly">{{ field.contents }}</div>
|
||||||
|
|
|
@ -21,7 +21,16 @@ from registrar.admin import (
|
||||||
UserDomainRoleAdmin,
|
UserDomainRoleAdmin,
|
||||||
VerifiedByStaffAdmin,
|
VerifiedByStaffAdmin,
|
||||||
)
|
)
|
||||||
from registrar.models import Domain, DomainRequest, DomainInformation, User, DomainInvitation, Contact, Website
|
from registrar.models import (
|
||||||
|
Domain,
|
||||||
|
DomainRequest,
|
||||||
|
DomainInformation,
|
||||||
|
User,
|
||||||
|
DomainInvitation,
|
||||||
|
Contact,
|
||||||
|
Website,
|
||||||
|
DraftDomain,
|
||||||
|
)
|
||||||
from registrar.models.user_domain_role import UserDomainRole
|
from registrar.models.user_domain_role import UserDomainRole
|
||||||
from registrar.models.verified_by_staff import VerifiedByStaff
|
from registrar.models.verified_by_staff import VerifiedByStaff
|
||||||
from .common import (
|
from .common import (
|
||||||
|
@ -697,6 +706,126 @@ class TestDomainRequestAdmin(MockEppLib):
|
||||||
)
|
)
|
||||||
self.mock_client = MockSESClient()
|
self.mock_client = MockSESClient()
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_analyst_can_see_and_edit_alternative_domain(self):
|
||||||
|
"""Tests if an analyst can still see and edit the alternative domain field"""
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
fake_website = Website.objects.create(website="thisisatest.gov")
|
||||||
|
_domain_request.alternative_domains.add(fake_website)
|
||||||
|
_domain_request.save()
|
||||||
|
|
||||||
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/domainrequest/{}/change/".format(_domain_request.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_request.requested_domain.name)
|
||||||
|
|
||||||
|
# Test if the page has the alternative domain
|
||||||
|
self.assertContains(response, "thisisatest.gov")
|
||||||
|
|
||||||
|
# Check that the page contains the url we expect
|
||||||
|
expected_href = reverse("admin:registrar_website_change", args=[fake_website.id])
|
||||||
|
self.assertContains(response, expected_href)
|
||||||
|
|
||||||
|
# Navigate to the website to ensure that we can still edit it
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/website/{}/change/".format(fake_website.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, "thisisatest.gov")
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_analyst_can_see_and_edit_requested_domain(self):
|
||||||
|
"""Tests if an analyst can still see and edit the requested domain field"""
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/domainrequest/{}/change/".format(_domain_request.pk),
|
||||||
|
follow=True,
|
||||||
|
)
|
||||||
|
|
||||||
|
# Filter to get the latest from the DB (rather than direct assignment)
|
||||||
|
requested_domain = DraftDomain.objects.filter(name=_domain_request.requested_domain.name).get()
|
||||||
|
|
||||||
|
# Make sure the page loaded, and that we're on the right page
|
||||||
|
self.assertEqual(response.status_code, 200)
|
||||||
|
self.assertContains(response, requested_domain.name)
|
||||||
|
|
||||||
|
# Check that the page contains the url we expect
|
||||||
|
expected_href = reverse("admin:registrar_draftdomain_change", args=[requested_domain.id])
|
||||||
|
self.assertContains(response, expected_href)
|
||||||
|
|
||||||
|
# Navigate to the website to ensure that we can still edit it
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/draftdomain/{}/change/".format(requested_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, "city.gov")
|
||||||
|
|
||||||
|
@less_console_noise_decorator
|
||||||
|
def test_analyst_can_see_current_websites(self):
|
||||||
|
"""Tests if an analyst can still see current website field"""
|
||||||
|
|
||||||
|
# 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)
|
||||||
|
|
||||||
|
fake_website = Website.objects.create(website="thisisatest.gov")
|
||||||
|
_domain_request.current_websites.add(fake_website)
|
||||||
|
_domain_request.save()
|
||||||
|
|
||||||
|
p = "userpass"
|
||||||
|
self.client.login(username="staffuser", password=p)
|
||||||
|
response = self.client.get(
|
||||||
|
"/admin/registrar/domainrequest/{}/change/".format(_domain_request.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_request.requested_domain.name)
|
||||||
|
|
||||||
|
# Test if the page has the current website
|
||||||
|
self.assertContains(response, "thisisatest.gov")
|
||||||
|
|
||||||
def test_domain_sortable(self):
|
def test_domain_sortable(self):
|
||||||
"""Tests if the DomainRequest sorts by domain correctly"""
|
"""Tests if the DomainRequest sorts by domain correctly"""
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
|
|
|
@ -37,7 +37,6 @@ class TestGroups(TestCase):
|
||||||
"add_domaininvitation",
|
"add_domaininvitation",
|
||||||
"view_domaininvitation",
|
"view_domaininvitation",
|
||||||
"change_domainrequest",
|
"change_domainrequest",
|
||||||
"change_draftdomain",
|
|
||||||
"add_federalagency",
|
"add_federalagency",
|
||||||
"change_federalagency",
|
"change_federalagency",
|
||||||
"delete_federalagency",
|
"delete_federalagency",
|
||||||
|
@ -48,7 +47,6 @@ class TestGroups(TestCase):
|
||||||
"add_verifiedbystaff",
|
"add_verifiedbystaff",
|
||||||
"change_verifiedbystaff",
|
"change_verifiedbystaff",
|
||||||
"delete_verifiedbystaff",
|
"delete_verifiedbystaff",
|
||||||
"change_website",
|
|
||||||
]
|
]
|
||||||
|
|
||||||
# Get the codenames of actual permissions associated with the group
|
# Get the codenames of actual permissions associated with the group
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue