mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-06 03:03:25 +02:00
Merge pull request #1550 from cisagov/es/993-restrict-withdrawing-request
#993 Prevent restricted users from withdrawing domain application
This commit is contained in:
commit
c22aff5531
6 changed files with 88 additions and 8 deletions
|
@ -114,7 +114,7 @@ class UserGroup(Group):
|
|||
)
|
||||
|
||||
cisa_analysts_group.save()
|
||||
logger.debug("CISA Analyt permissions added to group " + cisa_analysts_group.name)
|
||||
logger.debug("CISA Analyst permissions added to group " + cisa_analysts_group.name)
|
||||
except Exception as e:
|
||||
logger.error(f"Error creating analyst permissions group: {e}")
|
||||
|
||||
|
|
|
@ -2225,6 +2225,33 @@ class TestApplicationStatus(TestWithUser, WebTest):
|
|||
home_page = self.app.get("/")
|
||||
self.assertContains(home_page, "Withdrawn")
|
||||
|
||||
def test_application_withdraw_no_permissions(self):
|
||||
"""Can't withdraw applications as a restricted user."""
|
||||
self.user.status = User.RESTRICTED
|
||||
self.user.save()
|
||||
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
|
||||
application.save()
|
||||
|
||||
home_page = self.app.get("/")
|
||||
self.assertContains(home_page, "city.gov")
|
||||
# click the "Manage" link
|
||||
detail_page = home_page.click("Manage", index=0)
|
||||
self.assertContains(detail_page, "city.gov")
|
||||
self.assertContains(detail_page, "city1.gov")
|
||||
self.assertContains(detail_page, "Chief Tester")
|
||||
self.assertContains(detail_page, "testy@town.com")
|
||||
self.assertContains(detail_page, "Admin Tester")
|
||||
self.assertContains(detail_page, "Status:")
|
||||
# Restricted user trying to withdraw results in 403 error
|
||||
with less_console_noise():
|
||||
for url_name in [
|
||||
"application-withdraw-confirmation",
|
||||
"application-withdrawn",
|
||||
]:
|
||||
with self.subTest(url_name=url_name):
|
||||
page = self.client.get(reverse(url_name, kwargs={"pk": application.pk}))
|
||||
self.assertEqual(page.status_code, 403)
|
||||
|
||||
def test_application_status_no_permissions(self):
|
||||
"""Can't access applications without being the creator."""
|
||||
application = completed_application(status=DomainApplication.ApplicationStatus.SUBMITTED, user=self.user)
|
||||
|
|
|
@ -13,7 +13,11 @@ from registrar.models import DomainApplication
|
|||
from registrar.utility import StrEnum
|
||||
from registrar.views.utility import StepsHelper
|
||||
|
||||
from .utility import DomainApplicationPermissionView, ApplicationWizardPermissionView
|
||||
from .utility import (
|
||||
DomainApplicationPermissionView,
|
||||
DomainApplicationPermissionWithdrawView,
|
||||
ApplicationWizardPermissionView,
|
||||
)
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
@ -544,7 +548,7 @@ class ApplicationStatus(DomainApplicationPermissionView):
|
|||
template_name = "application_status.html"
|
||||
|
||||
|
||||
class ApplicationWithdrawConfirmation(DomainApplicationPermissionView):
|
||||
class ApplicationWithdrawConfirmation(DomainApplicationPermissionWithdrawView):
|
||||
"""This page will ask user to confirm if they want to withdraw
|
||||
|
||||
The DomainApplicationPermissionView restricts access so that only the
|
||||
|
@ -554,7 +558,7 @@ class ApplicationWithdrawConfirmation(DomainApplicationPermissionView):
|
|||
template_name = "application_withdraw_confirmation.html"
|
||||
|
||||
|
||||
class ApplicationWithdrawn(DomainApplicationPermissionView):
|
||||
class ApplicationWithdrawn(DomainApplicationPermissionWithdrawView):
|
||||
# this view renders no template
|
||||
template_name = ""
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ from .always_404 import always_404
|
|||
from .permission_views import (
|
||||
DomainPermissionView,
|
||||
DomainApplicationPermissionView,
|
||||
DomainApplicationPermissionWithdrawView,
|
||||
DomainInvitationPermissionDeleteView,
|
||||
ApplicationWizardPermissionView,
|
||||
)
|
||||
|
|
|
@ -26,7 +26,8 @@ class PermissionsLoginMixin(PermissionRequiredMixin):
|
|||
|
||||
class DomainPermission(PermissionsLoginMixin):
|
||||
|
||||
"""Does the logged-in user have access to this domain?"""
|
||||
"""Permission mixin that redirects to domain if user has access,
|
||||
otherwise 403"""
|
||||
|
||||
def has_permission(self):
|
||||
"""Check if this user has access to this domain.
|
||||
|
@ -134,7 +135,8 @@ class DomainPermission(PermissionsLoginMixin):
|
|||
|
||||
class DomainApplicationPermission(PermissionsLoginMixin):
|
||||
|
||||
"""Does the logged-in user have access to this domain application?"""
|
||||
"""Permission mixin that redirects to domain application if user
|
||||
has access, otherwise 403"""
|
||||
|
||||
def has_permission(self):
|
||||
"""Check if this user has access to this domain application.
|
||||
|
@ -154,9 +156,33 @@ class DomainApplicationPermission(PermissionsLoginMixin):
|
|||
return True
|
||||
|
||||
|
||||
class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
|
||||
|
||||
"""Permission mixin that redirects to withdraw action on domain application
|
||||
if user has access, otherwise 403"""
|
||||
|
||||
def has_permission(self):
|
||||
"""Check if this user has access to withdraw this domain application."""
|
||||
if not self.request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
# user needs to be the creator of the application
|
||||
# this query is empty if there isn't a domain application with this
|
||||
# id and this user as creator
|
||||
if not DomainApplication.objects.filter(creator=self.request.user, id=self.kwargs["pk"]).exists():
|
||||
return False
|
||||
|
||||
# Restricted users should not be able to withdraw domain requests
|
||||
if self.request.user.is_restricted():
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
class ApplicationWizardPermission(PermissionsLoginMixin):
|
||||
|
||||
"""Does the logged-in user have permission to start or edit an application?"""
|
||||
"""Permission mixin that redirects to start or edit domain application if
|
||||
user has access, otherwise 403"""
|
||||
|
||||
def has_permission(self):
|
||||
"""Check if this user has permission to start or edit an application.
|
||||
|
@ -173,7 +199,8 @@ class ApplicationWizardPermission(PermissionsLoginMixin):
|
|||
|
||||
class DomainInvitationPermission(PermissionsLoginMixin):
|
||||
|
||||
"""Does the logged-in user have access to this domain invitation?
|
||||
"""Permission mixin that redirects to domain invitation if user has
|
||||
access, otherwise 403"
|
||||
|
||||
A user has access to a domain invitation if they have a role on the
|
||||
associated domain.
|
||||
|
|
|
@ -8,6 +8,7 @@ from registrar.models import Domain, DomainApplication, DomainInvitation
|
|||
from .mixins import (
|
||||
DomainPermission,
|
||||
DomainApplicationPermission,
|
||||
DomainApplicationPermissionWithdraw,
|
||||
DomainInvitationPermission,
|
||||
ApplicationWizardPermission,
|
||||
)
|
||||
|
@ -74,6 +75,26 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a
|
|||
raise NotImplementedError
|
||||
|
||||
|
||||
class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC):
|
||||
|
||||
"""Abstract base view for domain application withdraw function
|
||||
|
||||
This abstract view cannot be instantiated. Actual views must specify
|
||||
`template_name`.
|
||||
"""
|
||||
|
||||
# DetailView property for what model this is viewing
|
||||
model = DomainApplication
|
||||
# variable name in template context for the model object
|
||||
context_object_name = "domainapplication"
|
||||
|
||||
# Abstract property enforces NotImplementedError on an attribute.
|
||||
@property
|
||||
@abc.abstractmethod
|
||||
def template_name(self):
|
||||
raise NotImplementedError
|
||||
|
||||
|
||||
class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC):
|
||||
|
||||
"""Abstract base view for the application form that enforces permissions
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue