mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-08-05 17:28:31 +02:00
Changed permission flow for mixins / Made logging a bit more detailed
This commit is contained in:
parent
c94458dcd7
commit
3cfa7f8b03
3 changed files with 82 additions and 55 deletions
|
@ -83,10 +83,10 @@ class DomainOrgNameAddressView(DomainPermissionView, FormMixin):
|
|||
# Q: Is there a more efficent way to do this?
|
||||
# It would be ideal if we didn't have to repeat this.
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info, changes
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
# superclass has the redirect
|
||||
|
@ -134,8 +134,9 @@ class DomainAuthorizingOfficialView(DomainPermissionView, FormMixin):
|
|||
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
# superclass has the redirect
|
||||
|
@ -207,8 +208,9 @@ class DomainNameserversView(DomainPermissionView, FormMixin):
|
|||
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: formset.cleaned_data[field] for field in formset.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
# superclass has the redirect
|
||||
|
@ -254,8 +256,9 @@ class DomainYourContactInformationView(DomainPermissionView, FormMixin):
|
|||
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
# superclass has the redirect
|
||||
|
@ -306,8 +309,9 @@ class DomainSecurityEmailView(DomainPermissionView, FormMixin):
|
|||
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
# superclass has the redirect
|
||||
|
@ -388,7 +392,7 @@ class DomainAddUserView(DomainPermissionView, FormMixin):
|
|||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, obj=self.get_object()
|
||||
)
|
||||
return redirect(self.get_success_url())
|
||||
|
||||
|
@ -414,8 +418,9 @@ class DomainAddUserView(DomainPermissionView, FormMixin):
|
|||
|
||||
if self.request.user.is_staff or self.request.user.is_superuser:
|
||||
# if they are editing from an '/admin' redirect, log their actions
|
||||
changes = {field: form.cleaned_data[field] for field in form.changed_data}
|
||||
self.log_analyst_form_actions(
|
||||
self.form_class.__name__, self.get_object().domain_info
|
||||
self.form_class.__name__, self.get_object().domain_info, changes, obj=self.get_object()
|
||||
)
|
||||
|
||||
return redirect(self.get_success_url())
|
||||
|
|
|
@ -36,27 +36,55 @@ class DomainPermission(PermissionsLoginMixin):
|
|||
if not self.request.user.is_authenticated:
|
||||
return False
|
||||
|
||||
if self.request.user.is_restricted():
|
||||
return False
|
||||
|
||||
pk = self.kwargs["pk"]
|
||||
# If pk is none then something went very wrong...
|
||||
if pk is None:
|
||||
raise ValueError("Primary key is None")
|
||||
|
||||
# ticket 806
|
||||
if self.can_access_other_user_domains(pk):
|
||||
return True
|
||||
|
||||
# user needs to have a role on the domain,
|
||||
# and user cannot be restricted
|
||||
if (
|
||||
UserDomainRole.objects.filter(
|
||||
user=self.request.user, domain__id=pk
|
||||
).exists()
|
||||
and not self.request.user.is_restricted()
|
||||
):
|
||||
return True
|
||||
elif self.request.user.is_restricted():
|
||||
if not UserDomainRole.objects.filter(
|
||||
user=self.request.user, domain__id=pk
|
||||
).exists():
|
||||
return False
|
||||
|
||||
# ticket 806
|
||||
requested_domain = None
|
||||
if DomainInformation.objects.filter(id=pk).exists():
|
||||
requested_domain = DomainInformation.objects.get(id=pk)
|
||||
# if we need to check more about the nature of role, do it here.
|
||||
return True
|
||||
|
||||
def can_access_other_user_domains(self, pk):
|
||||
"""Checks to see if an authorized user (staff or superuser)
|
||||
can access a domain that they did not create or was invited to.
|
||||
"""
|
||||
|
||||
# Check if the user is permissioned...
|
||||
user_is_analyst_or_superuser = (
|
||||
self.request.user.is_staff or self.request.user.is_superuser
|
||||
)
|
||||
logger.debug(f"is auth {user_is_analyst_or_superuser}")
|
||||
|
||||
if not user_is_analyst_or_superuser:
|
||||
return False
|
||||
|
||||
# Check if the user is attempting a valid edit action.
|
||||
# In other words, if the analyst/admin did not click
|
||||
# the 'Manage Domain' button in /admin,
|
||||
# then they cannot access this page.
|
||||
session = self.request.session
|
||||
can_do_action = (
|
||||
"analyst_action" in session
|
||||
and "analyst_action_location" in session
|
||||
and session["analyst_action_location"] == pk
|
||||
)
|
||||
logger.debug(f"can do {can_do_action}")
|
||||
if not can_do_action:
|
||||
return False
|
||||
|
||||
# Analysts may manage domains, when they are in these statuses:
|
||||
valid_domain_statuses = [
|
||||
|
@ -64,37 +92,23 @@ class DomainPermission(PermissionsLoginMixin):
|
|||
DomainApplication.IN_REVIEW,
|
||||
DomainApplication.REJECTED,
|
||||
DomainApplication.ACTION_NEEDED,
|
||||
# Edge case - some domains do not have
|
||||
# a status or DomainInformation... aka a status of 'None'.
|
||||
# It is necessary to access those to correct errors.
|
||||
None,
|
||||
]
|
||||
|
||||
# Check if the user is permissioned...
|
||||
user_is_analyst_or_superuser = (
|
||||
self.request.user.is_staff or self.request.user.is_superuser
|
||||
)
|
||||
requested_domain = None
|
||||
if DomainInformation.objects.filter(id=pk).exists():
|
||||
requested_domain = DomainInformation.objects.get(id=pk)
|
||||
|
||||
session = self.request.session
|
||||
# Check if the user is attempting a valid edit action.
|
||||
can_do_action = (
|
||||
"analyst_action" in session
|
||||
and "analyst_action_location" in session
|
||||
and session["analyst_action_location"] == pk
|
||||
)
|
||||
if not requested_domain.domain_application.status in valid_domain_statuses:
|
||||
return False
|
||||
|
||||
# Edge case - some domains do not have
|
||||
# a status or DomainInformation... aka a status of 'None'
|
||||
# This checks that it has a status, before checking if it does
|
||||
# Otherwise, analysts can edit these domains
|
||||
if requested_domain is not None:
|
||||
can_do_action = (
|
||||
can_do_action
|
||||
and requested_domain.domain_application.status in valid_domain_statuses
|
||||
)
|
||||
# If the valid session keys exist, if the user is permissioned,
|
||||
# and if its in a valid status
|
||||
if can_do_action and user_is_analyst_or_superuser:
|
||||
return True
|
||||
|
||||
# if we need to check more about the nature of role, do it here.
|
||||
return False
|
||||
# Valid session keys exist,
|
||||
# the user is permissioned,
|
||||
# and it is in a valid status
|
||||
return True
|
||||
|
||||
|
||||
class DomainApplicationPermission(PermissionsLoginMixin):
|
||||
|
|
|
@ -3,9 +3,9 @@
|
|||
import abc # abstract base class
|
||||
|
||||
from django.views.generic import DetailView, DeleteView, TemplateView
|
||||
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from registrar.models import Domain, DomainApplication, DomainInvitation
|
||||
|
||||
from django.contrib.admin.models import LogEntry, CHANGE
|
||||
|
||||
from .mixins import (
|
||||
DomainPermission,
|
||||
|
@ -48,7 +48,7 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
|||
return context
|
||||
|
||||
def log_analyst_form_actions(
|
||||
self, form_class_name, printable_object_info, changes=None
|
||||
self, form_class_name, printable_object_info, changes=None, obj=None
|
||||
):
|
||||
"""Generates a log for when key 'analyst_action' exists on the session.
|
||||
Follows this format:
|
||||
|
@ -72,12 +72,20 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
|||
# or 'copy', for instance.
|
||||
match action:
|
||||
case "edit":
|
||||
# Q: do we want to be logging on every changed field?
|
||||
# I could see that becoming spammy log-wise,
|
||||
# but it may also be important.
|
||||
if obj is not None:
|
||||
content_type = ContentType.objects.get_for_model(obj)
|
||||
LogEntry.objects.log_action(
|
||||
user_id=self.request.user.id,
|
||||
content_type_id=content_type.pk,
|
||||
object_id=obj.id,
|
||||
object_repr=str(obj),
|
||||
action_flag=CHANGE,
|
||||
)
|
||||
|
||||
if changes is not None:
|
||||
# Logs every change made to the domain field
|
||||
# noqa for readability/format
|
||||
# Logs every change made to the domain field.
|
||||
# noqa for readability/format.
|
||||
# Used to manually capture changes, if need be.
|
||||
for field, new_value in changes.items():
|
||||
logger.info(
|
||||
f"""
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue