mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-05-15 17:17:02 +02:00
Lint
This commit is contained in:
parent
4b82f5e131
commit
91d1b9c1cc
10 changed files with 218 additions and 155 deletions
|
@ -4,43 +4,12 @@ from django.contrib.auth.admin import UserAdmin as BaseUserAdmin
|
||||||
from django.contrib.contenttypes.models import ContentType
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.http.response import HttpResponseRedirect
|
from django.http.response import HttpResponseRedirect
|
||||||
from django.urls import reverse
|
from django.urls import reverse
|
||||||
# from django.forms.widgets import CheckboxSelectMultiple
|
|
||||||
# from django import forms
|
|
||||||
from . import models
|
from . import models
|
||||||
|
|
||||||
logger = logging.getLogger(__name__)
|
logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
# class TextDisplayWidget(forms.Widget):
|
|
||||||
# def render(self, name, value, attrs=None, renderer=None):
|
|
||||||
# if value:
|
|
||||||
# choices_dict = dict(self.choices)
|
|
||||||
# selected_values = set(value)
|
|
||||||
# display_values = [choices_dict[val] for val in selected_values]
|
|
||||||
# return ', '.join(display_values)
|
|
||||||
# return ''
|
|
||||||
|
|
||||||
|
|
||||||
# class DomainApplicationForm(forms.ModelForm):
|
|
||||||
# class Meta:
|
|
||||||
# model = models.DomainApplication
|
|
||||||
# fields = '__all__'
|
|
||||||
|
|
||||||
# def __init__(self, *args, **kwargs):
|
|
||||||
# super().__init__(*args, **kwargs)
|
|
||||||
|
|
||||||
# # Replace the current_websites field with text if a condition is met
|
|
||||||
# if self.instance and self.instance.creator.status == 'ineligible':
|
|
||||||
# self.fields['current_websites'].widget = TextDisplayWidget()
|
|
||||||
# self.fields['current_websites'].widget.choices = self.fields['current_websites'].choices
|
|
||||||
|
|
||||||
# self.fields['other_contacts'].widget = TextDisplayWidget()
|
|
||||||
# self.fields['other_contacts'].widget.choices = self.fields['other_contacts'].choices
|
|
||||||
|
|
||||||
# self.fields['alternative_domains'].widget = TextDisplayWidget()
|
|
||||||
# self.fields['alternative_domains'].widget.choices = self.fields['alternative_domains'].choices
|
|
||||||
|
|
||||||
|
|
||||||
class AuditedAdmin(admin.ModelAdmin):
|
class AuditedAdmin(admin.ModelAdmin):
|
||||||
|
|
||||||
"""Custom admin to make auditing easier."""
|
"""Custom admin to make auditing easier."""
|
||||||
|
@ -131,13 +100,34 @@ class MyUserAdmin(BaseUserAdmin):
|
||||||
|
|
||||||
inlines = [UserContactInline]
|
inlines = [UserContactInline]
|
||||||
|
|
||||||
list_display = ("email", "first_name", "last_name", "is_staff", "is_superuser", "status")
|
list_display = (
|
||||||
|
"email",
|
||||||
|
"first_name",
|
||||||
|
"last_name",
|
||||||
|
"is_staff",
|
||||||
|
"is_superuser",
|
||||||
|
"status",
|
||||||
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
(None, {'fields': ('username', 'password', 'status')}), # Add the 'status' field here
|
(
|
||||||
('Personal Info', {'fields': ('first_name', 'last_name', 'email')}),
|
None,
|
||||||
('Permissions', {'fields': ('is_active', 'is_staff', 'is_superuser', 'groups', 'user_permissions')}),
|
{"fields": ("username", "password", "status")},
|
||||||
('Important dates', {'fields': ('last_login', 'date_joined')}),
|
), # Add the 'status' field here
|
||||||
|
("Personal Info", {"fields": ("first_name", "last_name", "email")}),
|
||||||
|
(
|
||||||
|
"Permissions",
|
||||||
|
{
|
||||||
|
"fields": (
|
||||||
|
"is_active",
|
||||||
|
"is_staff",
|
||||||
|
"is_superuser",
|
||||||
|
"groups",
|
||||||
|
"user_permissions",
|
||||||
|
)
|
||||||
|
},
|
||||||
|
),
|
||||||
|
("Important dates", {"fields": ("last_login", "date_joined")}),
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_list_display(self, request):
|
def get_list_display(self, request):
|
||||||
|
@ -216,7 +206,7 @@ class DomainApplicationAdmin(ListHeaderAdmin):
|
||||||
|
|
||||||
# Set multi-selects 'read-only' (hide selects and show data)
|
# Set multi-selects 'read-only' (hide selects and show data)
|
||||||
# based on user perms and application creator's status
|
# based on user perms and application creator's status
|
||||||
#form = DomainApplicationForm
|
# form = DomainApplicationForm
|
||||||
|
|
||||||
# Columns
|
# Columns
|
||||||
list_display = [
|
list_display = [
|
||||||
|
@ -314,45 +304,66 @@ class DomainApplicationAdmin(ListHeaderAdmin):
|
||||||
# Get the original application from the database
|
# Get the original application from the database
|
||||||
original_obj = models.DomainApplication.objects.get(pk=obj.pk)
|
original_obj = models.DomainApplication.objects.get(pk=obj.pk)
|
||||||
|
|
||||||
|
# if obj.status != original_obj.status:
|
||||||
|
# if obj.status == models.DomainApplication.STARTED:
|
||||||
|
# # No conditions
|
||||||
|
# pass
|
||||||
|
# elif obj.status == models.DomainApplication.SUBMITTED:
|
||||||
|
# # This is an fsm in model which will throw an error if the
|
||||||
|
# # transition condition is violated, so we roll back the
|
||||||
|
# # status to what it was before the admin user changed it and
|
||||||
|
# # let the fsm method set it. Same comment applies to
|
||||||
|
# # transition method calls below.
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.submit()
|
||||||
|
# elif obj.status == models.DomainApplication.IN_REVIEW:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.in_review()
|
||||||
|
# elif obj.status == models.DomainApplication.ACTION_NEEDED:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.action_needed()
|
||||||
|
# elif obj.status == models.DomainApplication.APPROVED:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.approve()
|
||||||
|
# elif obj.status == models.DomainApplication.WITHDRAWN:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.withdraw()
|
||||||
|
# elif obj.status == models.DomainApplication.REJECTED:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.reject()
|
||||||
|
# elif obj.status == models.DomainApplication.INELIGIBLE:
|
||||||
|
# obj.status = original_obj.status
|
||||||
|
# obj.reject_with_prejudice()
|
||||||
|
# else:
|
||||||
|
# logger.warning("Unknown status selected in django admin")
|
||||||
|
|
||||||
if obj.status != original_obj.status:
|
if obj.status != original_obj.status:
|
||||||
if obj.status == models.DomainApplication.STARTED:
|
status_method_mapping = {
|
||||||
# No conditions
|
models.DomainApplication.STARTED: None,
|
||||||
pass
|
models.DomainApplication.SUBMITTED: obj.submit,
|
||||||
elif obj.status == models.DomainApplication.SUBMITTED:
|
models.DomainApplication.IN_REVIEW: obj.in_review,
|
||||||
# This is an fsm in model which will throw an error if the
|
models.DomainApplication.ACTION_NEEDED: obj.action_needed,
|
||||||
# transition condition is violated, so we roll back the
|
models.DomainApplication.APPROVED: obj.approve,
|
||||||
# status to what it was before the admin user changed it and
|
models.DomainApplication.WITHDRAWN: obj.withdraw,
|
||||||
# let the fsm method set it. Same comment applies to
|
models.DomainApplication.REJECTED: obj.reject,
|
||||||
# transition method calls below.
|
models.DomainApplication.INELIGIBLE: obj.reject_with_prejudice,
|
||||||
obj.status = original_obj.status
|
}
|
||||||
obj.submit()
|
selected_method = status_method_mapping.get(obj.status)
|
||||||
elif obj.status == models.DomainApplication.IN_REVIEW:
|
if selected_method is None:
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.in_review()
|
|
||||||
elif obj.status == models.DomainApplication.ACTION_NEEDED:
|
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.action_needed()
|
|
||||||
elif obj.status == models.DomainApplication.APPROVED:
|
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.approve()
|
|
||||||
elif obj.status == models.DomainApplication.WITHDRAWN:
|
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.withdraw()
|
|
||||||
elif obj.status == models.DomainApplication.REJECTED:
|
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.reject()
|
|
||||||
elif obj.status == models.DomainApplication.INELIGIBLE:
|
|
||||||
obj.status = original_obj.status
|
|
||||||
obj.reject_with_prejudice()
|
|
||||||
else:
|
|
||||||
logger.warning("Unknown status selected in django admin")
|
logger.warning("Unknown status selected in django admin")
|
||||||
|
else:
|
||||||
|
obj.status = original_obj.status
|
||||||
|
selected_method()
|
||||||
|
|
||||||
super().save_model(request, obj, form, change)
|
super().save_model(request, obj, form, change)
|
||||||
else:
|
else:
|
||||||
messages.error(request, "This action is not permitted for applications with an ineligible creator.")
|
messages.error(
|
||||||
|
request,
|
||||||
|
"This action is not permitted for applications "
|
||||||
|
+ "with an ineligible creator.",
|
||||||
|
)
|
||||||
|
|
||||||
def get_readonly_fields(self, request, obj=None):
|
def get_readonly_fields(self, request, obj=None):
|
||||||
|
|
||||||
"""Set the read-only state on form elements.
|
"""Set the read-only state on form elements.
|
||||||
We have 2 conditions that determine which fields are read-only:
|
We have 2 conditions that determine which fields are read-only:
|
||||||
admin user permissions and the application creator's status, so
|
admin user permissions and the application creator's status, so
|
||||||
|
@ -363,12 +374,14 @@ class DomainApplicationAdmin(ListHeaderAdmin):
|
||||||
|
|
||||||
# Check if the creator is ineligible
|
# Check if the creator is ineligible
|
||||||
if obj and obj.creator.status == "ineligible":
|
if obj and obj.creator.status == "ineligible":
|
||||||
# For fields like CharField, IntegerField, etc., the widget used is straightforward,
|
# For fields like CharField, IntegerField, etc., the widget used is
|
||||||
# and the readonly_fields list can control their behavior
|
# straightforward and the readonly_fields list can control their behavior
|
||||||
readonly_fields.extend([field.name for field in self.model._meta.fields])
|
readonly_fields.extend([field.name for field in self.model._meta.fields])
|
||||||
# Add the multi-select fields to readonly_fields:
|
# Add the multi-select fields to readonly_fields:
|
||||||
# Complex fields like ManyToManyField require special handling
|
# Complex fields like ManyToManyField require special handling
|
||||||
readonly_fields.extend(["current_websites", "other_contacts", "alternative_domains"])
|
readonly_fields.extend(
|
||||||
|
["current_websites", "other_contacts", "alternative_domains"]
|
||||||
|
)
|
||||||
|
|
||||||
if request.user.is_superuser:
|
if request.user.is_superuser:
|
||||||
return readonly_fields
|
return readonly_fields
|
||||||
|
|
|
@ -35,7 +35,7 @@ class DomainApplication(TimeStampedModel):
|
||||||
(APPROVED, APPROVED),
|
(APPROVED, APPROVED),
|
||||||
(WITHDRAWN, WITHDRAWN),
|
(WITHDRAWN, WITHDRAWN),
|
||||||
(REJECTED, REJECTED),
|
(REJECTED, REJECTED),
|
||||||
(INELIGIBLE, INELIGIBLE)
|
(INELIGIBLE, INELIGIBLE),
|
||||||
]
|
]
|
||||||
|
|
||||||
class StateTerritoryChoices(models.TextChoices):
|
class StateTerritoryChoices(models.TextChoices):
|
||||||
|
@ -556,7 +556,9 @@ class DomainApplication(TimeStampedModel):
|
||||||
)
|
)
|
||||||
|
|
||||||
@transition(
|
@transition(
|
||||||
field="status", source=[SUBMITTED, IN_REVIEW, REJECTED, INELIGIBLE], target=APPROVED
|
field="status",
|
||||||
|
source=[SUBMITTED, IN_REVIEW, REJECTED, INELIGIBLE],
|
||||||
|
target=APPROVED,
|
||||||
)
|
)
|
||||||
def approve(self):
|
def approve(self):
|
||||||
"""Approve an application that has been submitted.
|
"""Approve an application that has been submitted.
|
||||||
|
@ -616,8 +618,6 @@ class DomainApplication(TimeStampedModel):
|
||||||
|
|
||||||
self.creator.block_user()
|
self.creator.block_user()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
# ## Form policies ###
|
# ## Form policies ###
|
||||||
#
|
#
|
||||||
# These methods control what questions need to be answered by applicants
|
# These methods control what questions need to be answered by applicants
|
||||||
|
|
|
@ -18,17 +18,15 @@ class User(AbstractUser):
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# #### Constants for choice fields ####
|
# #### Constants for choice fields ####
|
||||||
INELIGIBLE = 'ineligible'
|
INELIGIBLE = "ineligible"
|
||||||
STATUS_CHOICES = (
|
STATUS_CHOICES = ((INELIGIBLE, INELIGIBLE),)
|
||||||
(INELIGIBLE, INELIGIBLE),
|
|
||||||
)
|
|
||||||
|
|
||||||
status = models.CharField(
|
status = models.CharField(
|
||||||
max_length=10,
|
max_length=10,
|
||||||
choices=STATUS_CHOICES,
|
choices=STATUS_CHOICES,
|
||||||
default=None, # Set the default value to None
|
default=None, # Set the default value to None
|
||||||
null=True, # Allow the field to be null
|
null=True, # Allow the field to be null
|
||||||
blank=True, # Allow the field to be blank
|
blank=True, # Allow the field to be blank
|
||||||
)
|
)
|
||||||
|
|
||||||
domains = models.ManyToManyField(
|
domains = models.ManyToManyField(
|
||||||
|
|
|
@ -15,7 +15,9 @@ class TestDomainApplicationAdmin(TestCase):
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
self.site = AdminSite()
|
self.site = AdminSite()
|
||||||
self.factory = RequestFactory()
|
self.factory = RequestFactory()
|
||||||
self.admin = DomainApplicationAdmin(model=DomainApplication, admin_site=self.site)
|
self.admin = DomainApplicationAdmin(
|
||||||
|
model=DomainApplication, admin_site=self.site
|
||||||
|
)
|
||||||
self.superuser = create_superuser()
|
self.superuser = create_superuser()
|
||||||
self.staffuser = create_user()
|
self.staffuser = create_user()
|
||||||
|
|
||||||
|
@ -281,36 +283,82 @@ class TestDomainApplicationAdmin(TestCase):
|
||||||
self.admin.save_model(request, application, form=None, change=True)
|
self.admin.save_model(request, application, form=None, change=True)
|
||||||
|
|
||||||
# Test that approved domain exists and equals requested domain
|
# Test that approved domain exists and equals requested domain
|
||||||
self.assertEqual(
|
self.assertEqual(application.creator.status, "ineligible")
|
||||||
application.creator.status, "ineligible"
|
|
||||||
)
|
|
||||||
|
|
||||||
def test_readonly_when_ineligible_creator(self):
|
def test_readonly_when_ineligible_creator(self):
|
||||||
application = completed_application(status=DomainApplication.IN_REVIEW)
|
application = completed_application(status=DomainApplication.IN_REVIEW)
|
||||||
application.creator.status = 'ineligible'
|
application.creator.status = "ineligible"
|
||||||
application.creator.save()
|
application.creator.save()
|
||||||
|
|
||||||
request = self.factory.get('/')
|
request = self.factory.get("/")
|
||||||
request.user = self.superuser
|
request.user = self.superuser
|
||||||
|
|
||||||
readonly_fields = self.admin.get_readonly_fields(request, application)
|
readonly_fields = self.admin.get_readonly_fields(request, application)
|
||||||
|
|
||||||
expected_fields = ['id', 'created_at', 'updated_at', 'status', 'creator', 'investigator', 'organization_type', 'federally_recognized_tribe', 'state_recognized_tribe', 'tribe_name', 'federal_agency', 'federal_type', 'is_election_board', 'organization_name', 'address_line1', 'address_line2', 'city', 'state_territory', 'zipcode', 'urbanization', 'type_of_work', 'more_organization_information', 'authorizing_official', 'approved_domain', 'requested_domain', 'submitter', 'purpose', 'no_other_contacts_rationale', 'anything_else', 'is_policy_acknowledged', 'current_websites', 'other_contacts', 'alternative_domains']
|
expected_fields = [
|
||||||
|
"id",
|
||||||
|
"created_at",
|
||||||
|
"updated_at",
|
||||||
|
"status",
|
||||||
|
"creator",
|
||||||
|
"investigator",
|
||||||
|
"organization_type",
|
||||||
|
"federally_recognized_tribe",
|
||||||
|
"state_recognized_tribe",
|
||||||
|
"tribe_name",
|
||||||
|
"federal_agency",
|
||||||
|
"federal_type",
|
||||||
|
"is_election_board",
|
||||||
|
"organization_name",
|
||||||
|
"address_line1",
|
||||||
|
"address_line2",
|
||||||
|
"city",
|
||||||
|
"state_territory",
|
||||||
|
"zipcode",
|
||||||
|
"urbanization",
|
||||||
|
"type_of_work",
|
||||||
|
"more_organization_information",
|
||||||
|
"authorizing_official",
|
||||||
|
"approved_domain",
|
||||||
|
"requested_domain",
|
||||||
|
"submitter",
|
||||||
|
"purpose",
|
||||||
|
"no_other_contacts_rationale",
|
||||||
|
"anything_else",
|
||||||
|
"is_policy_acknowledged",
|
||||||
|
"current_websites",
|
||||||
|
"other_contacts",
|
||||||
|
"alternative_domains",
|
||||||
|
]
|
||||||
|
|
||||||
self.assertEqual(readonly_fields, expected_fields)
|
self.assertEqual(readonly_fields, expected_fields)
|
||||||
|
|
||||||
def test_readonly_fields_for_analyst(self):
|
def test_readonly_fields_for_analyst(self):
|
||||||
request = self.factory.get('/') # Use the correct method and path
|
request = self.factory.get("/") # Use the correct method and path
|
||||||
request.user = self.staffuser
|
request.user = self.staffuser
|
||||||
|
|
||||||
readonly_fields = self.admin.get_readonly_fields(request)
|
readonly_fields = self.admin.get_readonly_fields(request)
|
||||||
|
|
||||||
expected_fields = ['creator', 'type_of_work', 'more_organization_information', 'address_line1', 'address_line2', 'zipcode', 'requested_domain', 'alternative_domains', 'purpose', 'submitter', 'no_other_contacts_rationale', 'anything_else', 'is_policy_acknowledged']
|
expected_fields = [
|
||||||
|
"creator",
|
||||||
|
"type_of_work",
|
||||||
|
"more_organization_information",
|
||||||
|
"address_line1",
|
||||||
|
"address_line2",
|
||||||
|
"zipcode",
|
||||||
|
"requested_domain",
|
||||||
|
"alternative_domains",
|
||||||
|
"purpose",
|
||||||
|
"submitter",
|
||||||
|
"no_other_contacts_rationale",
|
||||||
|
"anything_else",
|
||||||
|
"is_policy_acknowledged",
|
||||||
|
]
|
||||||
|
|
||||||
self.assertEqual(readonly_fields, expected_fields)
|
self.assertEqual(readonly_fields, expected_fields)
|
||||||
|
|
||||||
def test_readonly_fields_for_superuser(self):
|
def test_readonly_fields_for_superuser(self):
|
||||||
request = self.factory.get('/') # Use the correct method and path
|
request = self.factory.get("/") # Use the correct method and path
|
||||||
request.user = self.superuser
|
request.user = self.superuser
|
||||||
|
|
||||||
readonly_fields = self.admin.get_readonly_fields(request)
|
readonly_fields = self.admin.get_readonly_fields(request)
|
||||||
|
@ -322,19 +370,23 @@ class TestDomainApplicationAdmin(TestCase):
|
||||||
def test_saving_when_ineligible_creator(self):
|
def test_saving_when_ineligible_creator(self):
|
||||||
# Create an instance of the model
|
# Create an instance of the model
|
||||||
application = completed_application(status=DomainApplication.IN_REVIEW)
|
application = completed_application(status=DomainApplication.IN_REVIEW)
|
||||||
application.creator.status = 'ineligible'
|
application.creator.status = "ineligible"
|
||||||
application.creator.save()
|
application.creator.save()
|
||||||
|
|
||||||
# Create a request object with a superuser
|
# Create a request object with a superuser
|
||||||
request = self.factory.get('/')
|
request = self.factory.get("/")
|
||||||
request.user = self.superuser
|
request.user = self.superuser
|
||||||
|
|
||||||
with patch('django.contrib.messages.error') as mock_error:
|
with patch("django.contrib.messages.error") as mock_error:
|
||||||
# Simulate saving the model
|
# Simulate saving the model
|
||||||
self.admin.save_model(request, application, None, False)
|
self.admin.save_model(request, application, None, False)
|
||||||
|
|
||||||
# Assert that the error message was called with the correct argument
|
# Assert that the error message was called with the correct argument
|
||||||
mock_error.assert_called_once_with(request, "This action is not permitted for applications with an ineligible creator.")
|
mock_error.assert_called_once_with(
|
||||||
|
request,
|
||||||
|
"This action is not permitted for applications with "
|
||||||
|
+ "an ineligible creator.",
|
||||||
|
)
|
||||||
|
|
||||||
# Assert that the status has not changed
|
# Assert that the status has not changed
|
||||||
self.assertEqual(application.status, DomainApplication.IN_REVIEW)
|
self.assertEqual(application.status, DomainApplication.IN_REVIEW)
|
||||||
|
|
|
@ -1444,9 +1444,7 @@ class TestDomainDetail(TestWithDomainPermissions, WebTest):
|
||||||
home_page = self.app.get("/")
|
home_page = self.app.get("/")
|
||||||
self.assertContains(home_page, "igorville.gov")
|
self.assertContains(home_page, "igorville.gov")
|
||||||
with less_console_noise():
|
with less_console_noise():
|
||||||
response = self.client.get(
|
response = self.client.get(reverse("domain", kwargs={"pk": self.domain.id}))
|
||||||
reverse("domain", kwargs={"pk": self.domain.id})
|
|
||||||
)
|
|
||||||
self.assertEqual(response.status_code, 403)
|
self.assertEqual(response.status_code, 403)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -5,5 +5,5 @@ from .permission_views import (
|
||||||
DomainPermissionView,
|
DomainPermissionView,
|
||||||
DomainApplicationPermissionView,
|
DomainApplicationPermissionView,
|
||||||
DomainInvitationPermissionDeleteView,
|
DomainInvitationPermissionDeleteView,
|
||||||
ApplicationWizardPermissionView
|
ApplicationWizardPermissionView,
|
||||||
)
|
)
|
||||||
|
|
|
@ -10,7 +10,7 @@ from .mixins import (
|
||||||
DomainPermission,
|
DomainPermission,
|
||||||
DomainApplicationPermission,
|
DomainApplicationPermission,
|
||||||
DomainInvitationPermission,
|
DomainInvitationPermission,
|
||||||
ApplicationWizardPermission
|
ApplicationWizardPermission,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -54,7 +54,9 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a
|
||||||
raise NotImplementedError
|
raise NotImplementedError
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView, abc.ABC):
|
class ApplicationWizardPermissionView(
|
||||||
|
ApplicationWizardPermission, TemplateView, abc.ABC
|
||||||
|
):
|
||||||
|
|
||||||
"""Abstract base view for the application form that enforces permissions
|
"""Abstract base view for the application form that enforces permissions
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue