mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-19 19:09:22 +02:00
filter requests based on permissions, updated actions based on permissions
This commit is contained in:
parent
ec7202b47c
commit
faf57902f0
11 changed files with 92 additions and 94 deletions
|
@ -66,20 +66,20 @@ def portfolio_permissions(request):
|
|||
return {
|
||||
"has_base_portfolio_permission": request.user.has_base_portfolio_permission(portfolio),
|
||||
"has_domains_portfolio_permission": request.user.has_domains_portfolio_permission(portfolio),
|
||||
"has_domain_requests_portfolio_permission": request.user.has_domain_requests_portfolio_permission(
|
||||
"has_requests_portfolio_permission": request.user.has_requests_portfolio_permission(
|
||||
portfolio
|
||||
),
|
||||
"has_view_suborganization": request.user.has_view_suborganization(portfolio),
|
||||
"has_edit_suborganization": request.user.has_edit_suborganization(portfolio),
|
||||
"has_view_suborganization_portfolio_permission": request.user.has_view_suborganization_portfolio_permission(portfolio),
|
||||
"has_edit_suborganization_portfolio_permission": request.user.has_edit_suborganization_portfolio_permission(portfolio),
|
||||
"portfolio": portfolio,
|
||||
"has_organization_feature_flag": True,
|
||||
}
|
||||
return {
|
||||
"has_base_portfolio_permission": False,
|
||||
"has_domains_portfolio_permission": False,
|
||||
"has_domain_requests_portfolio_permission": False,
|
||||
"has_view_suborganization": False,
|
||||
"has_edit_suborganization": False,
|
||||
"has_requests_portfolio_permission": False,
|
||||
"has_view_suborganization_portfolio_permission": False,
|
||||
"has_edit_suborganization_portfolio_permission": False,
|
||||
"portfolio": None,
|
||||
"has_organization_feature_flag": False,
|
||||
}
|
||||
|
@ -89,9 +89,9 @@ def portfolio_permissions(request):
|
|||
return {
|
||||
"has_base_portfolio_permission": False,
|
||||
"has_domains_portfolio_permission": False,
|
||||
"has_domain_requests_portfolio_permission": False,
|
||||
"has_view_suborganization": False,
|
||||
"has_edit_suborganization": False,
|
||||
"has_requests_portfolio_permission": False,
|
||||
"has_view_suborganization_portfolio_permission": False,
|
||||
"has_edit_suborganization_portfolio_permission": False,
|
||||
"portfolio": None,
|
||||
"has_organization_feature_flag": False,
|
||||
}
|
||||
|
|
|
@ -223,20 +223,27 @@ class User(AbstractUser):
|
|||
portfolio, UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
|
||||
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
|
||||
|
||||
def has_domain_requests_portfolio_permission(self, portfolio):
|
||||
return self._has_portfolio_permission(
|
||||
portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
|
||||
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
|
||||
|
||||
def has_view_all_domains_permission(self, portfolio):
|
||||
def has_view_all_domains_portfolio_permission(self, portfolio):
|
||||
"""Determines if the current user can view all available domains in a given portfolio"""
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS)
|
||||
|
||||
def has_requests_portfolio_permission(self, portfolio):
|
||||
return self._has_portfolio_permission(
|
||||
portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
|
||||
) or self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
|
||||
|
||||
def has_view_all_requests_portfolio_permission(self, portfolio):
|
||||
"""Determines if the current user can view all available domain requests in a given portfolio"""
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS)
|
||||
|
||||
def has_edit_request_portfolio_permission(self, portfolio):
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
|
||||
|
||||
# Field specific permission checks
|
||||
def has_view_suborganization(self, portfolio):
|
||||
def has_view_suborganization_portfolio_permission(self, portfolio):
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.VIEW_SUBORGANIZATION)
|
||||
|
||||
def has_edit_suborganization(self, portfolio):
|
||||
def has_edit_suborganization_portfolio_permission(self, portfolio):
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_SUBORGANIZATION)
|
||||
|
||||
def get_first_portfolio(self):
|
||||
|
@ -245,34 +252,31 @@ class User(AbstractUser):
|
|||
return permission.portfolio
|
||||
return None
|
||||
|
||||
def has_edit_requests(self, portfolio):
|
||||
return self._has_portfolio_permission(portfolio, UserPortfolioPermissionChoices.EDIT_REQUESTS)
|
||||
|
||||
def portfolio_role_summary(self, portfolio):
|
||||
"""Returns a list of roles based on the user's permissions."""
|
||||
roles = []
|
||||
|
||||
# Define the conditions and their corresponding roles
|
||||
conditions_roles = [
|
||||
(self.has_edit_suborganization(portfolio), ["Admin"]),
|
||||
(self.has_edit_suborganization_portfolio_permission(portfolio), ["Admin"]),
|
||||
(
|
||||
self.has_view_all_domains_permission(portfolio)
|
||||
and self.has_domain_requests_portfolio_permission(portfolio)
|
||||
and self.has_edit_requests(portfolio),
|
||||
self.has_view_all_domains_portfolio_permission(portfolio)
|
||||
and self.has_requests_portfolio_permission(portfolio)
|
||||
and self.has_edit_request_portfolio_permission(portfolio),
|
||||
["View-only admin", "Domain requestor"],
|
||||
),
|
||||
(
|
||||
self.has_view_all_domains_permission(portfolio)
|
||||
and self.has_domain_requests_portfolio_permission(portfolio),
|
||||
self.has_view_all_domains_portfolio_permission(portfolio)
|
||||
and self.has_requests_portfolio_permission(portfolio),
|
||||
["View-only admin"],
|
||||
),
|
||||
(
|
||||
self.has_base_portfolio_permission(portfolio)
|
||||
and self.has_edit_requests(portfolio)
|
||||
and self.has_edit_request_portfolio_permission(portfolio)
|
||||
and self.has_domains_portfolio_permission(portfolio),
|
||||
["Domain requestor", "Domain manager"],
|
||||
),
|
||||
(self.has_base_portfolio_permission(portfolio) and self.has_edit_requests(portfolio), ["Domain requestor"]),
|
||||
(self.has_base_portfolio_permission(portfolio) and self.has_edit_request_portfolio_permission(portfolio), ["Domain requestor"]),
|
||||
(
|
||||
self.has_base_portfolio_permission(portfolio) and self.has_domains_portfolio_permission(portfolio),
|
||||
["Domain manager"],
|
||||
|
@ -443,7 +447,7 @@ class User(AbstractUser):
|
|||
def get_user_domain_ids(self, request):
|
||||
"""Returns either the domains ids associated with this user on UserDomainRole or Portfolio"""
|
||||
portfolio = request.session.get("portfolio")
|
||||
if self.is_org_user(request) and self.has_view_all_domains_permission(portfolio):
|
||||
if self.is_org_user(request) and self.has_view_all_domains_portfolio_permission(portfolio):
|
||||
return DomainInformation.objects.filter(portfolio=portfolio).values_list("domain_id", flat=True)
|
||||
else:
|
||||
return UserDomainRole.objects.filter(user=self).values_list("domain_id", flat=True)
|
||||
|
|
|
@ -21,7 +21,6 @@ class UserPortfolioPermissionChoices(models.TextChoices):
|
|||
EDIT_MEMBER = "edit_member", "Create and edit members"
|
||||
|
||||
VIEW_ALL_REQUESTS = "view_all_requests", "View all requests"
|
||||
VIEW_CREATED_REQUESTS = "view_created_requests", "View created requests"
|
||||
EDIT_REQUESTS = "edit_requests", "Create and edit requests"
|
||||
|
||||
VIEW_PORTFOLIO = "view_portfolio", "View organization"
|
||||
|
|
|
@ -72,9 +72,9 @@
|
|||
{% include "includes/summary_item.html" with title='DNSSEC' value='Not Enabled' edit_link=url editable=is_editable %}
|
||||
{% endif %}
|
||||
|
||||
{% if portfolio and has_domains_portfolio_permission and has_view_suborganization %}
|
||||
{% if portfolio and has_domains_portfolio_permission and has_view_suborganization_portfolio_permission %}
|
||||
{% url 'domain-suborganization' pk=domain.id as url %}
|
||||
{% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization %}
|
||||
{% include "includes/summary_item.html" with title='Suborganization' value=domain.domain_info.sub_organization edit_link=url editable=is_editable|and:has_edit_suborganization_portfolio_permission %}
|
||||
{% else %}
|
||||
{% url 'domain-org-name-address' pk=domain.id as url %}
|
||||
{% include "includes/summary_item.html" with title='Organization name and mailing address' value=domain.domain_info address='true' edit_link=url editable=is_editable %}
|
||||
|
|
|
@ -61,7 +61,7 @@
|
|||
|
||||
{% if portfolio %}
|
||||
{% comment %} Only show this menu option if the user has the perms to do so {% endcomment %}
|
||||
{% if has_domains_portfolio_permission and has_view_suborganization %}
|
||||
{% if has_domains_portfolio_permission and has_view_suborganization_portfolio_permission %}
|
||||
{% with url_name="domain-suborganization" %}
|
||||
{% include "includes/domain_sidenav_item.html" with item_text="Suborganization" %}
|
||||
{% endwith %}
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
If you believe there is an error please contact <a href="mailto:help@get.gov" class="usa-link">help@get.gov</a>.
|
||||
</p>
|
||||
|
||||
{% if has_domains_portfolio_permission and has_edit_suborganization %}
|
||||
{% if has_domains_portfolio_permission and has_edit_suborganization_portfolio_permission %}
|
||||
<form class="usa-form usa-form--large" method="post" novalidate id="form-container">
|
||||
{% csrf_token %}
|
||||
{% input_with_errors form.sub_organization %}
|
||||
|
|
|
@ -156,7 +156,7 @@
|
|||
<th data-sortable="name" scope="col" role="columnheader">Domain name</th>
|
||||
<th data-sortable="expiration_date" scope="col" role="columnheader">Expires</th>
|
||||
<th data-sortable="state_display" scope="col" role="columnheader">Status</th>
|
||||
{% if portfolio and has_view_suborganization %}
|
||||
{% if portfolio and has_view_suborganization_portfolio_permission %}
|
||||
<th data-sortable="suborganization" scope="col" role="columnheader">Suborganization</th>
|
||||
{% endif %}
|
||||
<th
|
||||
|
|
|
@ -53,7 +53,7 @@
|
|||
</li>
|
||||
|
||||
<li class="usa-nav__primary-item">
|
||||
{% if has_domain_requests_portfolio_permission %}
|
||||
{% if has_requests_portfolio_permission %}
|
||||
{% url 'domain-requests' as url %}
|
||||
<button
|
||||
type="button"
|
||||
|
|
|
@ -1326,16 +1326,16 @@ class TestUser(TestCase):
|
|||
User.objects.all().delete()
|
||||
UserDomainRole.objects.all().delete()
|
||||
|
||||
@patch.object(User, "has_edit_suborganization", return_value=True)
|
||||
@patch.object(User, "has_edit_suborganization_portfolio_permission", return_value=True)
|
||||
def test_portfolio_role_summary_admin(self, mock_edit_suborganization):
|
||||
# Test if the user is recognized as an Admin
|
||||
self.assertEqual(self.user.portfolio_role_summary(self.portfolio), ["Admin"])
|
||||
|
||||
@patch.multiple(
|
||||
User,
|
||||
has_view_all_domains_permission=lambda self, portfolio: True,
|
||||
has_domain_requests_portfolio_permission=lambda self, portfolio: True,
|
||||
has_edit_requests=lambda self, portfolio: True,
|
||||
has_view_all_domains_portfolio_permission=lambda self, portfolio: True,
|
||||
has_requests_portfolio_permission=lambda self, portfolio: True,
|
||||
has_edit_request_portfolio_permission=lambda self, portfolio: True,
|
||||
)
|
||||
def test_portfolio_role_summary_view_only_admin_and_domain_requestor(self):
|
||||
# Test if the user has both 'View-only admin' and 'Domain requestor' roles
|
||||
|
@ -1343,8 +1343,8 @@ class TestUser(TestCase):
|
|||
|
||||
@patch.multiple(
|
||||
User,
|
||||
has_view_all_domains_permission=lambda self, portfolio: True,
|
||||
has_domain_requests_portfolio_permission=lambda self, portfolio: True,
|
||||
has_view_all_domains_portfolio_permission=lambda self, portfolio: True,
|
||||
has_requests_portfolio_permission=lambda self, portfolio: True,
|
||||
)
|
||||
def test_portfolio_role_summary_view_only_admin(self):
|
||||
# Test if the user is recognized as a View-only admin
|
||||
|
@ -1353,7 +1353,7 @@ class TestUser(TestCase):
|
|||
@patch.multiple(
|
||||
User,
|
||||
has_base_portfolio_permission=lambda self, portfolio: True,
|
||||
has_edit_requests=lambda self, portfolio: True,
|
||||
has_edit_request_portfolio_permission=lambda self, portfolio: True,
|
||||
has_domains_portfolio_permission=lambda self, portfolio: True,
|
||||
)
|
||||
def test_portfolio_role_summary_member_domain_requestor_domain_manager(self):
|
||||
|
@ -1361,7 +1361,7 @@ class TestUser(TestCase):
|
|||
self.assertEqual(self.user.portfolio_role_summary(self.portfolio), ["Domain requestor", "Domain manager"])
|
||||
|
||||
@patch.multiple(
|
||||
User, has_base_portfolio_permission=lambda self, portfolio: True, has_edit_requests=lambda self, portfolio: True
|
||||
User, has_base_portfolio_permission=lambda self, portfolio: True, has_edit_request_portfolio_permission=lambda self, portfolio: True
|
||||
)
|
||||
def test_portfolio_role_summary_member_domain_requestor(self):
|
||||
# Test if the user has 'Member' and 'Domain requestor' roles
|
||||
|
@ -1547,7 +1547,7 @@ class TestUser(TestCase):
|
|||
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
|
||||
|
||||
user_can_view_all_domains = self.user.has_domains_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_requests_portfolio_permission(portfolio)
|
||||
|
||||
self.assertFalse(user_can_view_all_domains)
|
||||
self.assertFalse(user_can_view_all_requests)
|
||||
|
@ -1559,7 +1559,7 @@ class TestUser(TestCase):
|
|||
)
|
||||
|
||||
user_can_view_all_domains = self.user.has_domains_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_requests_portfolio_permission(portfolio)
|
||||
|
||||
self.assertTrue(user_can_view_all_domains)
|
||||
self.assertFalse(user_can_view_all_requests)
|
||||
|
@ -1569,7 +1569,7 @@ class TestUser(TestCase):
|
|||
portfolio_permission.refresh_from_db()
|
||||
|
||||
user_can_view_all_domains = self.user.has_domains_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_requests_portfolio_permission(portfolio)
|
||||
|
||||
self.assertTrue(user_can_view_all_domains)
|
||||
self.assertTrue(user_can_view_all_requests)
|
||||
|
@ -1577,7 +1577,7 @@ class TestUser(TestCase):
|
|||
UserDomainRole.objects.get_or_create(user=self.user, domain=self.domain, role=UserDomainRole.Roles.MANAGER)
|
||||
|
||||
user_can_view_all_domains = self.user.has_domains_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_domain_requests_portfolio_permission(portfolio)
|
||||
user_can_view_all_requests = self.user.has_requests_portfolio_permission(portfolio)
|
||||
|
||||
self.assertTrue(user_can_view_all_domains)
|
||||
self.assertTrue(user_can_view_all_requests)
|
||||
|
|
|
@ -12,7 +12,7 @@ def get_domain_requests_json(request):
|
|||
"""Given the current request,
|
||||
get all domain requests that are associated with the request user and exclude the APPROVED ones"""
|
||||
|
||||
domain_request_ids = get_domain_requests_ids_from_request(request)
|
||||
domain_request_ids = get_domain_request_ids_from_request(request)
|
||||
|
||||
objects = DomainRequest.objects.filter(id__in=domain_request_ids)
|
||||
unfiltered_total = objects.count()
|
||||
|
@ -24,7 +24,7 @@ def get_domain_requests_json(request):
|
|||
page_number = request.GET.get("page", 1)
|
||||
page_obj = paginator.get_page(page_number)
|
||||
|
||||
domain_requests = [serialize_domain_request(domain_request) for domain_request in page_obj.object_list]
|
||||
domain_requests = [serialize_domain_request(domain_request, request.user) for domain_request in page_obj.object_list]
|
||||
|
||||
return JsonResponse(
|
||||
{
|
||||
|
@ -39,22 +39,20 @@ def get_domain_requests_json(request):
|
|||
)
|
||||
|
||||
|
||||
def get_domain_requests_ids_from_request(request):
|
||||
def get_domain_request_ids_from_request(request):
|
||||
"""Get domain request ids from request.
|
||||
|
||||
If portfolio specified, return domain request ids associated with portfolio.
|
||||
Otherwise, return domain request ids associated with request.user.
|
||||
"""
|
||||
portfolio = request.GET.get("portfolio")
|
||||
filter_condition = Q(creator=request.user)
|
||||
if portfolio:
|
||||
domain_requests = DomainRequest.objects.filter(portfolio=portfolio).exclude(
|
||||
status=DomainRequest.DomainRequestStatus.APPROVED
|
||||
)
|
||||
else:
|
||||
domain_requests = DomainRequest.objects.filter(creator=request.user).exclude(
|
||||
status=DomainRequest.DomainRequestStatus.APPROVED
|
||||
)
|
||||
|
||||
if request.user.is_org_user(request) and request.user.has_view_all_requests_portfolio_permission(portfolio):
|
||||
filter_condition = Q(portfolio=portfolio)
|
||||
else:
|
||||
filter_condition = Q(portfolio=portfolio, creator=request.user)
|
||||
domain_requests = DomainRequest.objects.filter(filter_condition).exclude(status=DomainRequest.DomainRequestStatus.APPROVED)
|
||||
return domain_requests.values_list("id", flat=True)
|
||||
|
||||
|
||||
|
@ -86,41 +84,38 @@ def apply_sorting(queryset, request):
|
|||
return queryset.order_by(sort_by)
|
||||
|
||||
|
||||
def serialize_domain_request(domain_request):
|
||||
def serialize_domain_request(domain_request, user):
|
||||
# Determine if the request is deletable
|
||||
is_deletable = domain_request.status in [
|
||||
DomainRequest.DomainRequestStatus.STARTED,
|
||||
DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||
]
|
||||
action_url = (
|
||||
reverse("edit-domain-request", kwargs={"id": domain_request.id})
|
||||
if domain_request.status
|
||||
in [
|
||||
DomainRequest.DomainRequestStatus.STARTED,
|
||||
DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||
DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||
]
|
||||
else reverse("domain-request-status", kwargs={"pk": domain_request.id})
|
||||
)
|
||||
action_label = (
|
||||
"Edit"
|
||||
if domain_request.status
|
||||
in [
|
||||
DomainRequest.DomainRequestStatus.STARTED,
|
||||
DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||
DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||
]
|
||||
else "Manage"
|
||||
)
|
||||
svg_icon = (
|
||||
"edit"
|
||||
if domain_request.status
|
||||
in [
|
||||
DomainRequest.DomainRequestStatus.STARTED,
|
||||
DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||
DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||
]
|
||||
else "settings"
|
||||
)
|
||||
|
||||
# Determine action label based on user permissions and request status
|
||||
editable_statuses = [
|
||||
DomainRequest.DomainRequestStatus.STARTED,
|
||||
DomainRequest.DomainRequestStatus.ACTION_NEEDED,
|
||||
DomainRequest.DomainRequestStatus.WITHDRAWN,
|
||||
]
|
||||
|
||||
if user.has_edit_request_portfolio_permission and domain_request.creator == user:
|
||||
action_label = "Edit" if domain_request.status in editable_statuses else "Manage"
|
||||
else:
|
||||
action_label = "View"
|
||||
|
||||
# Map the action label to corresponding URLs and icons
|
||||
action_url_map = {
|
||||
"Edit": reverse("edit-domain-request", kwargs={"id": domain_request.id}),
|
||||
"Manage": reverse("domain-request-status", kwargs={"pk": domain_request.id}),
|
||||
"View": "#"
|
||||
}
|
||||
|
||||
svg_icon_map = {
|
||||
"Edit": "edit",
|
||||
"Manage": "settings",
|
||||
"View": "visibility"
|
||||
}
|
||||
|
||||
return {
|
||||
"requested_domain": domain_request.requested_domain.name if domain_request.requested_domain else None,
|
||||
"last_submitted_date": domain_request.last_submitted_date,
|
||||
|
@ -128,7 +123,7 @@ def serialize_domain_request(domain_request):
|
|||
"created_at": format(domain_request.created_at, "c"), # Serialize to ISO 8601
|
||||
"id": domain_request.id,
|
||||
"is_deletable": is_deletable,
|
||||
"action_url": action_url,
|
||||
"action_url": action_url_map.get(action_label),
|
||||
"action_label": action_label,
|
||||
"svg_icon": svg_icon,
|
||||
}
|
||||
"svg_icon": svg_icon_map.get(action_label),
|
||||
}
|
||||
|
|
|
@ -450,7 +450,7 @@ class PortfolioDomainRequestsPermission(PortfolioBasePermission):
|
|||
up from the portfolio's primary key in self.kwargs["pk"]"""
|
||||
|
||||
portfolio = self.request.session.get("portfolio")
|
||||
if not self.request.user.has_domain_requests_portfolio_permission(portfolio):
|
||||
if not self.request.user.has_requests_portfolio_permission(portfolio):
|
||||
return False
|
||||
|
||||
return super().has_permission()
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue