mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-16 22:44:11 +02:00
wip
This commit is contained in:
parent
6269cc56e3
commit
40737cbcf7
8 changed files with 49 additions and 56 deletions
|
@ -10,8 +10,10 @@ IS_STAFF = "is_staff"
|
||||||
IS_DOMAIN_MANAGER = "is_domain_manager"
|
IS_DOMAIN_MANAGER = "is_domain_manager"
|
||||||
IS_DOMAIN_REQUEST_CREATOR = "is_domain_request_creator"
|
IS_DOMAIN_REQUEST_CREATOR = "is_domain_request_creator"
|
||||||
IS_STAFF_MANAGING_DOMAIN = "is_staff_managing_domain"
|
IS_STAFF_MANAGING_DOMAIN = "is_staff_managing_domain"
|
||||||
|
IS_PORTFOLIO_MEMBER = "is_portfolio_member"
|
||||||
IS_PORTFOLIO_MEMBER_AND_DOMAIN_MANAGER = "is_portfolio_member_and_domain_manager"
|
IS_PORTFOLIO_MEMBER_AND_DOMAIN_MANAGER = "is_portfolio_member_and_domain_manager"
|
||||||
IS_DOMAIN_MANAGER_AND_NOT_PORTFOLIO_MEMBER = "is_domain_manager_and_not_portfolio_member"
|
IS_DOMAIN_MANAGER_AND_NOT_PORTFOLIO_MEMBER = "is_domain_manager_and_not_portfolio_member"
|
||||||
|
HAS_PORTFOLIO_DOMAINS_ANY_PERM = "has_portfolio_domains_any_perm"
|
||||||
HAS_PORTFOLIO_DOMAINS_VIEW_ALL = "has_portfolio_domains_view_all"
|
HAS_PORTFOLIO_DOMAINS_VIEW_ALL = "has_portfolio_domains_view_all"
|
||||||
HAS_PORTFOLIO_DOMAIN_REQUESTS_ANY_PERM = "has_portfolio_domain_requests_any_perm"
|
HAS_PORTFOLIO_DOMAIN_REQUESTS_ANY_PERM = "has_portfolio_domain_requests_any_perm"
|
||||||
HAS_PORTFOLIO_DOMAIN_REQUESTS_VIEW_ALL = "has_portfolio_domain_requests_view_all"
|
HAS_PORTFOLIO_DOMAIN_REQUESTS_VIEW_ALL = "has_portfolio_domain_requests_view_all"
|
||||||
|
@ -97,11 +99,21 @@ def _user_has_permission(user, request, rules, **kwargs):
|
||||||
has_permission = _can_access_other_user_domains(request, domain_id)
|
has_permission = _can_access_other_user_domains(request, domain_id)
|
||||||
conditions_met.append(has_permission)
|
conditions_met.append(has_permission)
|
||||||
|
|
||||||
|
if not any(conditions_met) and IS_PORTFOLIO_MEMBER in rules:
|
||||||
|
has_permission = user.is_org_user(request)
|
||||||
|
conditions_met.append(has_permission)
|
||||||
|
|
||||||
if not any(conditions_met) and HAS_PORTFOLIO_DOMAINS_VIEW_ALL in rules:
|
if not any(conditions_met) and HAS_PORTFOLIO_DOMAINS_VIEW_ALL in rules:
|
||||||
domain_id = kwargs.get("domain_pk")
|
domain_id = kwargs.get("domain_pk")
|
||||||
has_permission = _can_access_domain_via_portfolio_view_all_domains(request, domain_id)
|
has_permission = _can_access_domain_via_portfolio_view_all_domains(request, domain_id)
|
||||||
conditions_met.append(has_permission)
|
conditions_met.append(has_permission)
|
||||||
|
|
||||||
|
if not any(conditions_met) and HAS_PORTFOLIO_DOMAINS_ANY_PERM in rules:
|
||||||
|
has_permission = user.is_org_user(request) and user.has_any_domains_portfolio_permission(
|
||||||
|
request.session.get("portfolio")
|
||||||
|
)
|
||||||
|
conditions_met.append(has_permission)
|
||||||
|
|
||||||
if not any(conditions_met) and IS_PORTFOLIO_MEMBER_AND_DOMAIN_MANAGER in rules:
|
if not any(conditions_met) and IS_PORTFOLIO_MEMBER_AND_DOMAIN_MANAGER in rules:
|
||||||
domain_id = kwargs.get("domain_pk")
|
domain_id = kwargs.get("domain_pk")
|
||||||
has_permission = _is_domain_manager(user, domain_id) and _is_portfolio_member(request)
|
has_permission = _is_domain_manager(user, domain_id) and _is_portfolio_member(request)
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<li class="usa-sidenav__item">
|
<li class="usa-sidenav__item">
|
||||||
{% if url_name %}
|
{% if url_name %}
|
||||||
{% url url_name pk=domain.id as url %}
|
{% url url_name domain_pk=domain.id as url %}
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<a href="{{ url }}"
|
<a href="{{ url }}"
|
||||||
{% if request.path == url %}class="usa-current"{% endif %}
|
{% if request.path == url %}class="usa-current"{% endif %}
|
||||||
|
|
|
@ -13,6 +13,7 @@ from django.contrib.messages.views import SuccessMessageMixin
|
||||||
from django.http import HttpResponseRedirect
|
from django.http import HttpResponseRedirect
|
||||||
from django.shortcuts import redirect, render, get_object_or_404
|
from django.shortcuts import redirect, render, get_object_or_404
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
|
from django.views.generic import DeleteView
|
||||||
from django.views.generic.edit import FormMixin
|
from django.views.generic.edit import FormMixin
|
||||||
from django.conf import settings
|
from django.conf import settings
|
||||||
from registrar.decorators import (
|
from registrar.decorators import (
|
||||||
|
@ -1332,10 +1333,12 @@ class DomainInvitationCancelView(SuccessMessageMixin, DomainInvitationPermission
|
||||||
|
|
||||||
|
|
||||||
@grant_access(IS_DOMAIN_MANAGER, IS_STAFF_MANAGING_DOMAIN)
|
@grant_access(IS_DOMAIN_MANAGER, IS_STAFF_MANAGING_DOMAIN)
|
||||||
class DomainDeleteUserView(UserDomainRolePermissionDeleteView):
|
class DomainDeleteUserView(DeleteView):
|
||||||
"""Inside of a domain's user management, a form for deleting users."""
|
"""Inside of a domain's user management, a form for deleting users."""
|
||||||
|
|
||||||
object: UserDomainRole # workaround for type mismatch in DeleteView
|
object: UserDomainRole
|
||||||
|
model = UserDomainRole
|
||||||
|
context_object_name = "userdomainrole"
|
||||||
|
|
||||||
def get_object(self, queryset=None):
|
def get_object(self, queryset=None):
|
||||||
"""Custom get_object definition to grab a UserDomainRole object from a domain_id and user_id"""
|
"""Custom get_object definition to grab a UserDomainRole object from a domain_id and user_id"""
|
||||||
|
|
|
@ -15,20 +15,20 @@ def get_domain_requests_json(request):
|
||||||
If we are on the portfolio requests page, limit the response to only those requests associated with
|
If we are on the portfolio requests page, limit the response to only those requests associated with
|
||||||
the given portfolio."""
|
the given portfolio."""
|
||||||
|
|
||||||
domain_request_ids = get_domain_request_ids_from_request(request)
|
domain_request_ids = _get_domain_request_ids_from_request(request)
|
||||||
|
|
||||||
objects = DomainRequest.objects.filter(id__in=domain_request_ids)
|
objects = DomainRequest.objects.filter(id__in=domain_request_ids)
|
||||||
unfiltered_total = objects.count()
|
unfiltered_total = objects.count()
|
||||||
|
|
||||||
objects = apply_search(objects, request)
|
objects = _apply_search(objects, request)
|
||||||
objects = apply_status_filter(objects, request)
|
objects = _apply_status_filter(objects, request)
|
||||||
objects = apply_sorting(objects, request)
|
objects = _apply_sorting(objects, request)
|
||||||
|
|
||||||
paginator = Paginator(objects, 10)
|
paginator = Paginator(objects, 10)
|
||||||
page_number = request.GET.get("page", 1)
|
page_number = request.GET.get("page", 1)
|
||||||
page_obj = paginator.get_page(page_number)
|
page_obj = paginator.get_page(page_number)
|
||||||
domain_requests = [
|
domain_requests = [
|
||||||
serialize_domain_request(request, domain_request, request.user) for domain_request in page_obj.object_list
|
_serialize_domain_request(request, domain_request, request.user) for domain_request in page_obj.object_list
|
||||||
]
|
]
|
||||||
|
|
||||||
return JsonResponse(
|
return JsonResponse(
|
||||||
|
@ -44,7 +44,7 @@ def get_domain_requests_json(request):
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def get_domain_request_ids_from_request(request):
|
def _get_domain_request_ids_from_request(request):
|
||||||
"""Get domain request ids from request.
|
"""Get domain request ids from request.
|
||||||
|
|
||||||
If portfolio specified, return domain request ids associated with portfolio.
|
If portfolio specified, return domain request ids associated with portfolio.
|
||||||
|
@ -63,7 +63,7 @@ def get_domain_request_ids_from_request(request):
|
||||||
return domain_requests.values_list("id", flat=True)
|
return domain_requests.values_list("id", flat=True)
|
||||||
|
|
||||||
|
|
||||||
def apply_search(queryset, request):
|
def _apply_search(queryset, request):
|
||||||
search_term = request.GET.get("search_term")
|
search_term = request.GET.get("search_term")
|
||||||
is_portfolio = request.GET.get("portfolio")
|
is_portfolio = request.GET.get("portfolio")
|
||||||
|
|
||||||
|
@ -91,7 +91,7 @@ def apply_search(queryset, request):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
def apply_status_filter(queryset, request):
|
def _apply_status_filter(queryset, request):
|
||||||
status_param = request.GET.get("status")
|
status_param = request.GET.get("status")
|
||||||
if status_param:
|
if status_param:
|
||||||
status_list = status_param.split(",")
|
status_list = status_param.split(",")
|
||||||
|
@ -106,7 +106,7 @@ def apply_status_filter(queryset, request):
|
||||||
return queryset
|
return queryset
|
||||||
|
|
||||||
|
|
||||||
def apply_sorting(queryset, request):
|
def _apply_sorting(queryset, request):
|
||||||
sort_by = request.GET.get("sort_by", "id") # Default to 'id'
|
sort_by = request.GET.get("sort_by", "id") # Default to 'id'
|
||||||
order = request.GET.get("order", "asc") # Default to 'asc'
|
order = request.GET.get("order", "asc") # Default to 'asc'
|
||||||
|
|
||||||
|
@ -119,7 +119,7 @@ def apply_sorting(queryset, request):
|
||||||
return queryset.order_by(sort_by)
|
return queryset.order_by(sort_by)
|
||||||
|
|
||||||
|
|
||||||
def serialize_domain_request(request, domain_request, user):
|
def _serialize_domain_request(request, domain_request, user):
|
||||||
|
|
||||||
deletable_statuses = [
|
deletable_statuses = [
|
||||||
DomainRequest.DomainRequestStatus.STARTED,
|
DomainRequest.DomainRequestStatus.STARTED,
|
||||||
|
|
|
@ -6,7 +6,12 @@ from django.shortcuts import get_object_or_404, redirect, render
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
from django.utils.safestring import mark_safe
|
from django.utils.safestring import mark_safe
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
from registrar.decorators import HAS_PORTFOLIO_DOMAIN_REQUESTS_ANY_PERM, grant_access
|
from registrar.decorators import (
|
||||||
|
HAS_PORTFOLIO_DOMAIN_REQUESTS_ANY_PERM,
|
||||||
|
HAS_PORTFOLIO_DOMAINS_ANY_PERM,
|
||||||
|
IS_PORTFOLIO_MEMBER,
|
||||||
|
grant_access,
|
||||||
|
)
|
||||||
from registrar.forms import portfolio as portfolioForms
|
from registrar.forms import portfolio as portfolioForms
|
||||||
from registrar.models import Portfolio, User
|
from registrar.models import Portfolio, User
|
||||||
from registrar.models.domain import Domain
|
from registrar.models.domain import Domain
|
||||||
|
@ -26,9 +31,7 @@ from registrar.utility.errors import MissingEmailError
|
||||||
from registrar.utility.enums import DefaultUserValues
|
from registrar.utility.enums import DefaultUserValues
|
||||||
from registrar.views.utility.mixins import PortfolioMemberPermission
|
from registrar.views.utility.mixins import PortfolioMemberPermission
|
||||||
from registrar.views.utility.permission_views import (
|
from registrar.views.utility.permission_views import (
|
||||||
PortfolioDomainsPermissionView,
|
|
||||||
PortfolioBasePermissionView,
|
PortfolioBasePermissionView,
|
||||||
NoPortfolioDomainsPermissionView,
|
|
||||||
PortfolioMemberDomainsPermissionView,
|
PortfolioMemberDomainsPermissionView,
|
||||||
PortfolioMemberDomainsEditPermissionView,
|
PortfolioMemberDomainsEditPermissionView,
|
||||||
PortfolioMemberEditPermissionView,
|
PortfolioMemberEditPermissionView,
|
||||||
|
@ -45,7 +48,8 @@ from registrar.views.utility.invitation_helper import get_org_membership
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class PortfolioDomainsView(PortfolioDomainsPermissionView, View):
|
@grant_access(HAS_PORTFOLIO_DOMAINS_ANY_PERM)
|
||||||
|
class PortfolioDomainsView(View):
|
||||||
|
|
||||||
template_name = "portfolio_domains.html"
|
template_name = "portfolio_domains.html"
|
||||||
|
|
||||||
|
@ -685,7 +689,8 @@ class PortfolioInvitedMemberDomainsEditView(PortfolioMemberDomainsEditPermission
|
||||||
).update(status=DomainInvitation.DomainInvitationStatus.CANCELED)
|
).update(status=DomainInvitation.DomainInvitationStatus.CANCELED)
|
||||||
|
|
||||||
|
|
||||||
class PortfolioNoDomainsView(NoPortfolioDomainsPermissionView, View):
|
@grant_access(IS_PORTFOLIO_MEMBER)
|
||||||
|
class PortfolioNoDomainsView(View):
|
||||||
"""Some users have access to the underlying portfolio, but not any domains.
|
"""Some users have access to the underlying portfolio, but not any domains.
|
||||||
This is a custom view which explains that to the user - and denotes who to contact.
|
This is a custom view which explains that to the user - and denotes who to contact.
|
||||||
"""
|
"""
|
||||||
|
@ -714,7 +719,8 @@ class PortfolioNoDomainsView(NoPortfolioDomainsPermissionView, View):
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|
||||||
class PortfolioNoDomainRequestsView(NoPortfolioDomainsPermissionView, View):
|
@grant_access(IS_PORTFOLIO_MEMBER)
|
||||||
|
class PortfolioNoDomainRequestsView(View):
|
||||||
"""Some users have access to the underlying portfolio, but not any domain requests.
|
"""Some users have access to the underlying portfolio, but not any domain requests.
|
||||||
This is a custom view which explains that to the user - and denotes who to contact.
|
This is a custom view which explains that to the user - and denotes who to contact.
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -373,23 +373,6 @@ class PortfolioBasePermission(PermissionsLoginMixin):
|
||||||
return self.request.user.is_org_user(self.request)
|
return self.request.user.is_org_user(self.request)
|
||||||
|
|
||||||
|
|
||||||
class PortfolioDomainsPermission(PortfolioBasePermission):
|
|
||||||
"""Permission mixin that allows access to portfolio domain pages if user
|
|
||||||
has access, otherwise 403"""
|
|
||||||
|
|
||||||
def has_permission(self):
|
|
||||||
"""Check if this user has access to domains for this portfolio.
|
|
||||||
|
|
||||||
The user is in self.request.user and the portfolio can be looked
|
|
||||||
up from the portfolio's primary key in self.kwargs["pk"]"""
|
|
||||||
|
|
||||||
portfolio = self.request.session.get("portfolio")
|
|
||||||
if not self.request.user.has_any_domains_portfolio_permission(portfolio):
|
|
||||||
return False
|
|
||||||
|
|
||||||
return super().has_permission()
|
|
||||||
|
|
||||||
|
|
||||||
class PortfolioMembersPermission(PortfolioBasePermission):
|
class PortfolioMembersPermission(PortfolioBasePermission):
|
||||||
"""Permission mixin that allows access to portfolio members pages if user
|
"""Permission mixin that allows access to portfolio members pages if user
|
||||||
has access, otherwise 403"""
|
has access, otherwise 403"""
|
||||||
|
|
|
@ -10,7 +10,6 @@ from registrar.models.user_domain_role import UserDomainRole
|
||||||
from .mixins import (
|
from .mixins import (
|
||||||
DomainPermission,
|
DomainPermission,
|
||||||
DomainInvitationPermission,
|
DomainInvitationPermission,
|
||||||
PortfolioDomainsPermission,
|
|
||||||
PortfolioMemberDomainsPermission,
|
PortfolioMemberDomainsPermission,
|
||||||
PortfolioMemberDomainsEditPermission,
|
PortfolioMemberDomainsEditPermission,
|
||||||
PortfolioMemberEditPermission,
|
PortfolioMemberEditPermission,
|
||||||
|
@ -74,6 +73,13 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
def can_access_domain_via_portfolio(self, pk):
|
||||||
|
"""Most views should not allow permission to portfolio users.
|
||||||
|
If particular views allow access to the domain pages, they will need to override
|
||||||
|
this function.
|
||||||
|
"""
|
||||||
|
return False
|
||||||
|
|
||||||
# Abstract property enforces NotImplementedError on an attribute.
|
# Abstract property enforces NotImplementedError on an attribute.
|
||||||
@property
|
@property
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
|
@ -142,23 +148,6 @@ class PortfolioBasePermissionView(PortfolioBasePermission, DetailView, abc.ABC):
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class PortfolioDomainsPermissionView(PortfolioDomainsPermission, PortfolioBasePermissionView, abc.ABC):
|
|
||||||
"""Abstract base view for portfolio domains views that enforces permissions.
|
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
|
||||||
`template_name`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class NoPortfolioDomainsPermissionView(PortfolioBasePermissionView, abc.ABC):
|
|
||||||
"""Abstract base view for a user without access to the
|
|
||||||
portfolio domains views that enforces permissions.
|
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
|
||||||
`template_name`.
|
|
||||||
"""
|
|
||||||
|
|
||||||
|
|
||||||
class PortfolioMembersPermissionView(PortfolioMembersPermission, PortfolioBasePermissionView, abc.ABC):
|
class PortfolioMembersPermissionView(PortfolioMembersPermission, PortfolioBasePermissionView, abc.ABC):
|
||||||
"""Abstract base view for portfolio members views that enforces permissions.
|
"""Abstract base view for portfolio members views that enforces permissions.
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue