mirror of
https://github.com/cisagov/manage.get.gov.git
synced 2025-07-21 10:16:13 +02:00
Merge branch 'main' into za/1753-improve-admin-load-performance
This commit is contained in:
commit
227083462d
37 changed files with 671 additions and 660 deletions
8
.github/workflows/deploy-stable.yaml
vendored
8
.github/workflows/deploy-stable.yaml
vendored
|
@ -37,3 +37,11 @@ jobs:
|
||||||
cf_org: cisa-dotgov
|
cf_org: cisa-dotgov
|
||||||
cf_space: stable
|
cf_space: stable
|
||||||
cf_manifest: "ops/manifests/manifest-stable.yaml"
|
cf_manifest: "ops/manifests/manifest-stable.yaml"
|
||||||
|
- name: Run Django migrations
|
||||||
|
uses: cloud-gov/cg-cli-tools@main
|
||||||
|
with:
|
||||||
|
cf_username: ${{ secrets.CF_STABLE_USERNAME }}
|
||||||
|
cf_password: ${{ secrets.CF_STABLE_PASSWORD }}
|
||||||
|
cf_org: cisa-dotgov
|
||||||
|
cf_space: stable
|
||||||
|
cf_command: "run-task getgov-stable --command 'python manage.py migrate' --name migrate"
|
8
.github/workflows/deploy-staging.yaml
vendored
8
.github/workflows/deploy-staging.yaml
vendored
|
@ -37,3 +37,11 @@ jobs:
|
||||||
cf_org: cisa-dotgov
|
cf_org: cisa-dotgov
|
||||||
cf_space: staging
|
cf_space: staging
|
||||||
cf_manifest: "ops/manifests/manifest-staging.yaml"
|
cf_manifest: "ops/manifests/manifest-staging.yaml"
|
||||||
|
- name: Run Django migrations
|
||||||
|
uses: cloud-gov/cg-cli-tools@main
|
||||||
|
with:
|
||||||
|
cf_username: ${{ secrets.CF_STAGING_USERNAME }}
|
||||||
|
cf_password: ${{ secrets.CF_STAGING_PASSWORD }}
|
||||||
|
cf_org: cisa-dotgov
|
||||||
|
cf_space: staging
|
||||||
|
cf_command: "run-task getgov-staging --command 'python manage.py migrate' --name migrate"
|
||||||
|
|
|
@ -4,7 +4,7 @@ verify_ssl = true
|
||||||
name = "pypi"
|
name = "pypi"
|
||||||
|
|
||||||
[packages]
|
[packages]
|
||||||
django = "*"
|
django = "4.2.10"
|
||||||
cfenv = "*"
|
cfenv = "*"
|
||||||
django-cors-headers = "*"
|
django-cors-headers = "*"
|
||||||
pycryptodomex = "*"
|
pycryptodomex = "*"
|
||||||
|
|
1137
src/Pipfile.lock
generated
1137
src/Pipfile.lock
generated
File diff suppressed because it is too large
Load diff
|
@ -19,7 +19,6 @@ API_BASE_PATH = "/api/v1/available/?domain="
|
||||||
|
|
||||||
|
|
||||||
class AvailableViewTest(MockEppLib):
|
class AvailableViewTest(MockEppLib):
|
||||||
|
|
||||||
"""Test that the view function works as expected."""
|
"""Test that the view function works as expected."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -123,7 +122,6 @@ class AvailableViewTest(MockEppLib):
|
||||||
|
|
||||||
|
|
||||||
class AvailableAPITest(MockEppLib):
|
class AvailableAPITest(MockEppLib):
|
||||||
|
|
||||||
"""Test that the API can be called as expected."""
|
"""Test that the API can be called as expected."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Internal API views"""
|
"""Internal API views"""
|
||||||
|
|
||||||
from django.apps import apps
|
from django.apps import apps
|
||||||
from django.views.decorators.http import require_http_methods
|
from django.views.decorators.http import require_http_methods
|
||||||
from django.http import HttpResponse
|
from django.http import HttpResponse
|
||||||
|
|
|
@ -327,6 +327,27 @@ class ViewsTest(TestCase):
|
||||||
self.assertEqual(response.status_code, 302)
|
self.assertEqual(response.status_code, 302)
|
||||||
self.assertEqual(actual, expected)
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
|
def test_logout_redirect_url_with_no_session_state(self, mock_client):
|
||||||
|
"""Test that logout redirects to the configured post_logout_redirect_uris."""
|
||||||
|
with less_console_noise():
|
||||||
|
# MOCK
|
||||||
|
mock_client.callback.side_effect = self.user_info
|
||||||
|
mock_client.registration_response = {"post_logout_redirect_uris": ["http://example.com/back"]}
|
||||||
|
mock_client.provider_info = {"end_session_endpoint": "http://example.com/log_me_out"}
|
||||||
|
mock_client.client_id = "TEST"
|
||||||
|
# TEST
|
||||||
|
with less_console_noise():
|
||||||
|
response = self.client.get(reverse("logout"))
|
||||||
|
# ASSERTIONS
|
||||||
|
# Assert redirect code and url are accurate
|
||||||
|
expected = (
|
||||||
|
"http://example.com/log_me_out?client_id=TEST"
|
||||||
|
"&post_logout_redirect_uri=http%3A%2F%2Fexample.com%2Fback"
|
||||||
|
)
|
||||||
|
actual = response.url
|
||||||
|
self.assertEqual(response.status_code, 302)
|
||||||
|
self.assertEqual(actual, expected)
|
||||||
|
|
||||||
@patch("djangooidc.views.auth_logout")
|
@patch("djangooidc.views.auth_logout")
|
||||||
def test_logout_always_logs_out(self, mock_logout, _):
|
def test_logout_always_logs_out(self, mock_logout, _):
|
||||||
"""Without additional mocking, logout will always fail.
|
"""Without additional mocking, logout will always fail.
|
||||||
|
|
|
@ -145,8 +145,12 @@ def logout(request, next_page=None):
|
||||||
user = request.user
|
user = request.user
|
||||||
request_args = {
|
request_args = {
|
||||||
"client_id": CLIENT.client_id,
|
"client_id": CLIENT.client_id,
|
||||||
"state": request.session["state"],
|
|
||||||
}
|
}
|
||||||
|
# if state is not in request session, still redirect to the identity
|
||||||
|
# provider's logout url, but don't include the state in the url; this
|
||||||
|
# will successfully log out of the identity provider
|
||||||
|
if "state" in request.session:
|
||||||
|
request_args["state"] = request.session["state"]
|
||||||
if (
|
if (
|
||||||
"post_logout_redirect_uris" in CLIENT.registration_response.keys()
|
"post_logout_redirect_uris" in CLIENT.registration_response.keys()
|
||||||
and len(CLIENT.registration_response["post_logout_redirect_uris"]) > 0
|
and len(CLIENT.registration_response["post_logout_redirect_uris"]) > 0
|
||||||
|
|
|
@ -809,7 +809,6 @@ class DomainApplicationAdminForm(forms.ModelForm):
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationAdmin(ListHeaderAdmin):
|
class DomainApplicationAdmin(ListHeaderAdmin):
|
||||||
|
|
||||||
"""Custom domain applications admin class."""
|
"""Custom domain applications admin class."""
|
||||||
|
|
||||||
class InvestigatorFilter(admin.SimpleListFilter):
|
class InvestigatorFilter(admin.SimpleListFilter):
|
||||||
|
|
|
@ -2,7 +2,6 @@ from django.apps import AppConfig
|
||||||
|
|
||||||
|
|
||||||
class RegistrarConfig(AppConfig):
|
class RegistrarConfig(AppConfig):
|
||||||
|
|
||||||
"""Configure signal handling for our registrar Django application."""
|
"""Configure signal handling for our registrar Django application."""
|
||||||
|
|
||||||
name = "registrar"
|
name = "registrar"
|
||||||
|
|
|
@ -16,6 +16,7 @@ $ docker-compose exec app python manage.py shell
|
||||||
```
|
```
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import environs
|
import environs
|
||||||
from base64 import b64decode
|
from base64 import b64decode
|
||||||
from cfenv import AppEnv # type: ignore
|
from cfenv import AppEnv # type: ignore
|
||||||
|
|
|
@ -201,7 +201,6 @@ class DomainApplicationFixture:
|
||||||
|
|
||||||
|
|
||||||
class DomainFixture(DomainApplicationFixture):
|
class DomainFixture(DomainApplicationFixture):
|
||||||
|
|
||||||
"""Create one domain and permissions on it for each user."""
|
"""Create one domain and permissions on it for each user."""
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Loads files from /tmp into our sandboxes"""
|
"""Loads files from /tmp into our sandboxes"""
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
import logging
|
import logging
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL."""
|
"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL."""
|
"""Generates current-full.csv and current-federal.csv then uploads them to the desired URL."""
|
||||||
|
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Loops through each valid DomainInformation object and updates its agency value"""
|
"""Loops through each valid DomainInformation object and updates its agency value"""
|
||||||
|
|
||||||
import argparse
|
import argparse
|
||||||
import csv
|
import csv
|
||||||
import logging
|
import logging
|
||||||
|
|
|
@ -5,6 +5,7 @@ Regarding our dataclasses:
|
||||||
Not intended to be used as models but rather as an alternative to storing as a dictionary.
|
Not intended to be used as models but rather as an alternative to storing as a dictionary.
|
||||||
By keeping it as a dataclass instead of a dictionary, we can maintain data consistency.
|
By keeping it as a dataclass instead of a dictionary, we can maintain data consistency.
|
||||||
""" # noqa
|
""" # noqa
|
||||||
|
|
||||||
from dataclasses import dataclass, field
|
from dataclasses import dataclass, field
|
||||||
from datetime import date
|
from datetime import date
|
||||||
from enum import Enum
|
from enum import Enum
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
""""""
|
""""""
|
||||||
|
|
||||||
import csv
|
import csv
|
||||||
from dataclasses import dataclass
|
from dataclasses import dataclass
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
|
@ -0,0 +1,45 @@
|
||||||
|
# Generated by Django 4.2.7 on 2024-02-14 21:45
|
||||||
|
|
||||||
|
from django.db import migrations, models
|
||||||
|
import phonenumber_field.modelfields
|
||||||
|
|
||||||
|
|
||||||
|
class Migration(migrations.Migration):
|
||||||
|
dependencies = [
|
||||||
|
("registrar", "0068_domainapplication_notes_domaininformation_notes"),
|
||||||
|
]
|
||||||
|
|
||||||
|
operations = [
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="email",
|
||||||
|
field=models.EmailField(blank=True, db_index=True, max_length=254, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="first_name",
|
||||||
|
field=models.TextField(blank=True, db_index=True, null=True, verbose_name="first name / given name"),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="last_name",
|
||||||
|
field=models.TextField(blank=True, db_index=True, null=True, verbose_name="last name / family name"),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="middle_name",
|
||||||
|
field=models.TextField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="phone",
|
||||||
|
field=phonenumber_field.modelfields.PhoneNumberField(
|
||||||
|
blank=True, db_index=True, max_length=128, null=True, region=None
|
||||||
|
),
|
||||||
|
),
|
||||||
|
migrations.AlterField(
|
||||||
|
model_name="contact",
|
||||||
|
name="title",
|
||||||
|
field=models.TextField(blank=True, null=True, verbose_name="title or role in your organization"),
|
||||||
|
),
|
||||||
|
]
|
|
@ -6,7 +6,6 @@ from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
|
||||||
class Contact(TimeStampedModel):
|
class Contact(TimeStampedModel):
|
||||||
|
|
||||||
"""Contact information follows a similar pattern for each contact."""
|
"""Contact information follows a similar pattern for each contact."""
|
||||||
|
|
||||||
user = models.OneToOneField(
|
user = models.OneToOneField(
|
||||||
|
@ -19,38 +18,32 @@ class Contact(TimeStampedModel):
|
||||||
first_name = models.TextField(
|
first_name = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="First name",
|
|
||||||
verbose_name="first name / given name",
|
verbose_name="first name / given name",
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
middle_name = models.TextField(
|
middle_name = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Middle name (optional)",
|
|
||||||
)
|
)
|
||||||
last_name = models.TextField(
|
last_name = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Last name",
|
|
||||||
verbose_name="last name / family name",
|
verbose_name="last name / family name",
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
title = models.TextField(
|
title = models.TextField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Title",
|
|
||||||
verbose_name="title or role in your organization",
|
verbose_name="title or role in your organization",
|
||||||
)
|
)
|
||||||
email = models.EmailField(
|
email = models.EmailField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Email",
|
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
phone = PhoneNumberField(
|
phone = PhoneNumberField(
|
||||||
null=True,
|
null=True,
|
||||||
blank=True,
|
blank=True,
|
||||||
help_text="Phone",
|
|
||||||
db_index=True,
|
db_index=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
@ -17,7 +17,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainApplication(TimeStampedModel):
|
class DomainApplication(TimeStampedModel):
|
||||||
|
|
||||||
"""A registrant's application for a new domain."""
|
"""A registrant's application for a new domain."""
|
||||||
|
|
||||||
# Constants for choice fields
|
# Constants for choice fields
|
||||||
|
@ -97,7 +96,6 @@ class DomainApplication(TimeStampedModel):
|
||||||
ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)"
|
ARMED_FORCES_AP = "AP", "Armed Forces Pacific (AP)"
|
||||||
|
|
||||||
class OrganizationChoices(models.TextChoices):
|
class OrganizationChoices(models.TextChoices):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Primary organization choices:
|
Primary organization choices:
|
||||||
For use in django admin
|
For use in django admin
|
||||||
|
@ -114,7 +112,6 @@ class DomainApplication(TimeStampedModel):
|
||||||
SCHOOL_DISTRICT = "school_district", "School district"
|
SCHOOL_DISTRICT = "school_district", "School district"
|
||||||
|
|
||||||
class OrganizationChoicesVerbose(models.TextChoices):
|
class OrganizationChoicesVerbose(models.TextChoices):
|
||||||
|
|
||||||
"""
|
"""
|
||||||
Secondary organization choices
|
Secondary organization choices
|
||||||
For use in the application form and on the templates
|
For use in the application form and on the templates
|
||||||
|
|
|
@ -14,7 +14,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainInformation(TimeStampedModel):
|
class DomainInformation(TimeStampedModel):
|
||||||
|
|
||||||
"""A registrant's domain information for that domain, exported from
|
"""A registrant's domain information for that domain, exported from
|
||||||
DomainApplication. We use these field from DomainApplication with few exceptions
|
DomainApplication. We use these field from DomainApplication with few exceptions
|
||||||
which are 'removed' via pop at the bottom of this file. Most of design for domain
|
which are 'removed' via pop at the bottom of this file. Most of design for domain
|
||||||
|
|
|
@ -4,11 +4,9 @@ from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
|
||||||
class UserDomainRole(TimeStampedModel):
|
class UserDomainRole(TimeStampedModel):
|
||||||
|
|
||||||
"""This is a linking table that connects a user with a role on a domain."""
|
"""This is a linking table that connects a user with a role on a domain."""
|
||||||
|
|
||||||
class Roles(models.TextChoices):
|
class Roles(models.TextChoices):
|
||||||
|
|
||||||
"""The possible roles are listed here.
|
"""The possible roles are listed here.
|
||||||
|
|
||||||
Implementation of the named roles for allowing particular operations happens
|
Implementation of the named roles for allowing particular operations happens
|
||||||
|
|
|
@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
|
||||||
class VerifiedByStaff(TimeStampedModel):
|
class VerifiedByStaff(TimeStampedModel):
|
||||||
|
|
||||||
"""emails that get added to this table will bypass ial2 on login."""
|
"""emails that get added to this table will bypass ial2 on login."""
|
||||||
|
|
||||||
email = models.EmailField(
|
email = models.EmailField(
|
||||||
|
|
|
@ -4,7 +4,6 @@ from .utility.time_stamped_model import TimeStampedModel
|
||||||
|
|
||||||
|
|
||||||
class Website(TimeStampedModel):
|
class Website(TimeStampedModel):
|
||||||
|
|
||||||
"""Keep domain names in their own table so that applications can refer to
|
"""Keep domain names in their own table so that applications can refer to
|
||||||
many of them."""
|
many of them."""
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,6 @@ better caching responses.
|
||||||
|
|
||||||
|
|
||||||
class NoCacheMiddleware:
|
class NoCacheMiddleware:
|
||||||
|
|
||||||
"""Middleware to add a single header to every response."""
|
"""Middleware to add a single header to every response."""
|
||||||
|
|
||||||
def __init__(self, get_response):
|
def __init__(self, get_response):
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
class="usa-button"
|
class="usa-button"
|
||||||
>Add a domain manager</button>
|
>Add domain manager</button>
|
||||||
</form>
|
</form>
|
||||||
|
|
||||||
{% endblock %} {# domain_content #}
|
{% endblock %} {# domain_content #}
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
"""Custom field helpers for our inputs."""
|
"""Custom field helpers for our inputs."""
|
||||||
|
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from django import template
|
from django import template
|
||||||
|
|
|
@ -630,7 +630,6 @@ class TestPermissions(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestDomainInformation(TestCase):
|
class TestDomainInformation(TestCase):
|
||||||
|
|
||||||
"""Test the DomainInformation model, when approved or otherwise"""
|
"""Test the DomainInformation model, when approved or otherwise"""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -683,7 +682,6 @@ class TestDomainInformation(TestCase):
|
||||||
|
|
||||||
|
|
||||||
class TestInvitations(TestCase):
|
class TestInvitations(TestCase):
|
||||||
|
|
||||||
"""Test the retrieval of invitations."""
|
"""Test the retrieval of invitations."""
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
|
|
@ -3,6 +3,7 @@ Feature being tested: Registry Integration
|
||||||
|
|
||||||
This file tests the various ways in which the registrar interacts with the registry.
|
This file tests the various ways in which the registrar interacts with the registry.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
from django.test import TestCase
|
from django.test import TestCase
|
||||||
from django.db.utils import IntegrityError
|
from django.db.utils import IntegrityError
|
||||||
from unittest.mock import MagicMock, patch, call
|
from unittest.mock import MagicMock, patch, call
|
||||||
|
|
|
@ -30,7 +30,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationTests(TestWithUser, WebTest):
|
class DomainApplicationTests(TestWithUser, WebTest):
|
||||||
|
|
||||||
"""Webtests for domain application to test filling and submitting."""
|
"""Webtests for domain application to test filling and submitting."""
|
||||||
|
|
||||||
# Doesn't work with CSRF checking
|
# Doesn't work with CSRF checking
|
||||||
|
|
|
@ -1236,7 +1236,6 @@ class TestDomainSecurityEmail(TestDomainOverview):
|
||||||
|
|
||||||
|
|
||||||
class TestDomainDNSSEC(TestDomainOverview):
|
class TestDomainDNSSEC(TestDomainOverview):
|
||||||
|
|
||||||
"""MockEPPLib is already inherited."""
|
"""MockEPPLib is already inherited."""
|
||||||
|
|
||||||
def test_dnssec_page_refreshes_enable_button(self):
|
def test_dnssec_page_refreshes_enable_button(self):
|
||||||
|
|
|
@ -10,7 +10,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class EmailSendingError(RuntimeError):
|
class EmailSendingError(RuntimeError):
|
||||||
|
|
||||||
"""Local error for handling all failures when sending email."""
|
"""Local error for handling all failures when sending email."""
|
||||||
|
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -135,7 +135,6 @@ class DomainFormBaseView(DomainBaseView, FormMixin):
|
||||||
|
|
||||||
|
|
||||||
class DomainView(DomainBaseView):
|
class DomainView(DomainBaseView):
|
||||||
|
|
||||||
"""Domain detail overview page."""
|
"""Domain detail overview page."""
|
||||||
|
|
||||||
template_name = "domain_detail.html"
|
template_name = "domain_detail.html"
|
||||||
|
@ -787,14 +786,17 @@ class DomainAddUserView(DomainFormBaseView):
|
||||||
return redirect(self.get_success_url())
|
return redirect(self.get_success_url())
|
||||||
|
|
||||||
|
|
||||||
class DomainInvitationDeleteView(DomainInvitationPermissionDeleteView, SuccessMessageMixin):
|
# The order of the superclasses matters here. BaseDeleteView has a bug where the
|
||||||
|
# "form_valid" function does not call super, so it cannot use SuccessMessageMixin.
|
||||||
|
# The workaround is to use SuccessMessageMixin first.
|
||||||
|
class DomainInvitationDeleteView(SuccessMessageMixin, DomainInvitationPermissionDeleteView):
|
||||||
object: DomainInvitation # workaround for type mismatch in DeleteView
|
object: DomainInvitation # workaround for type mismatch in DeleteView
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
return reverse("domain-users", kwargs={"pk": self.object.domain.id})
|
return reverse("domain-users", kwargs={"pk": self.object.domain.id})
|
||||||
|
|
||||||
def get_success_message(self, cleaned_data):
|
def get_success_message(self, cleaned_data):
|
||||||
return f"Successfully canceled invitation for {self.object.email}."
|
return f"Canceled invitation to {self.object.email}."
|
||||||
|
|
||||||
|
|
||||||
class DomainDeleteUserView(UserDomainRolePermissionDeleteView):
|
class DomainDeleteUserView(UserDomainRolePermissionDeleteView):
|
||||||
|
|
|
@ -146,7 +146,6 @@ class OrderableFieldsMixin:
|
||||||
|
|
||||||
|
|
||||||
class PermissionsLoginMixin(PermissionRequiredMixin):
|
class PermissionsLoginMixin(PermissionRequiredMixin):
|
||||||
|
|
||||||
"""Mixin that redirects to login page if not logged in, otherwise 403."""
|
"""Mixin that redirects to login page if not logged in, otherwise 403."""
|
||||||
|
|
||||||
def handle_no_permission(self):
|
def handle_no_permission(self):
|
||||||
|
@ -155,7 +154,6 @@ class PermissionsLoginMixin(PermissionRequiredMixin):
|
||||||
|
|
||||||
|
|
||||||
class DomainPermission(PermissionsLoginMixin):
|
class DomainPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin that redirects to domain if user has access,
|
"""Permission mixin that redirects to domain if user has access,
|
||||||
otherwise 403"""
|
otherwise 403"""
|
||||||
|
|
||||||
|
@ -264,7 +262,6 @@ class DomainPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationPermission(PermissionsLoginMixin):
|
class DomainApplicationPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin that redirects to domain application if user
|
"""Permission mixin that redirects to domain application if user
|
||||||
has access, otherwise 403"""
|
has access, otherwise 403"""
|
||||||
|
|
||||||
|
@ -287,7 +284,6 @@ class DomainApplicationPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
|
||||||
class UserDeleteDomainRolePermission(PermissionsLoginMixin):
|
class UserDeleteDomainRolePermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin for UserDomainRole if user
|
"""Permission mixin for UserDomainRole if user
|
||||||
has access, otherwise 403"""
|
has access, otherwise 403"""
|
||||||
|
|
||||||
|
@ -324,7 +320,6 @@ class UserDeleteDomainRolePermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
|
class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin that redirects to withdraw action on domain application
|
"""Permission mixin that redirects to withdraw action on domain application
|
||||||
if user has access, otherwise 403"""
|
if user has access, otherwise 403"""
|
||||||
|
|
||||||
|
@ -347,7 +342,6 @@ class DomainApplicationPermissionWithdraw(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
|
||||||
class ApplicationWizardPermission(PermissionsLoginMixin):
|
class ApplicationWizardPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin that redirects to start or edit domain application if
|
"""Permission mixin that redirects to start or edit domain application if
|
||||||
user has access, otherwise 403"""
|
user has access, otherwise 403"""
|
||||||
|
|
||||||
|
@ -365,7 +359,6 @@ class ApplicationWizardPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
|
|
||||||
class DomainInvitationPermission(PermissionsLoginMixin):
|
class DomainInvitationPermission(PermissionsLoginMixin):
|
||||||
|
|
||||||
"""Permission mixin that redirects to domain invitation if user has
|
"""Permission mixin that redirects to domain invitation if user has
|
||||||
access, otherwise 403"
|
access, otherwise 403"
|
||||||
|
|
||||||
|
|
|
@ -20,7 +20,6 @@ logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract base view for domains that enforces permissions.
|
"""Abstract base view for domains that enforces permissions.
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
@ -58,7 +57,6 @@ class DomainPermissionView(DomainPermission, DetailView, abc.ABC):
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, abc.ABC):
|
class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract base view for domain applications that enforces permissions
|
"""Abstract base view for domain applications that enforces permissions
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
@ -78,7 +76,6 @@ class DomainApplicationPermissionView(DomainApplicationPermission, DetailView, a
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC):
|
class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdraw, DetailView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract base view for domain application withdraw function
|
"""Abstract base view for domain application withdraw function
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
@ -98,7 +95,6 @@ class DomainApplicationPermissionWithdrawView(DomainApplicationPermissionWithdra
|
||||||
|
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
@ -113,7 +109,6 @@ class ApplicationWizardPermissionView(ApplicationWizardPermission, TemplateView,
|
||||||
|
|
||||||
|
|
||||||
class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteView, abc.ABC):
|
class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract view for deleting a domain invitation.
|
"""Abstract view for deleting a domain invitation.
|
||||||
|
|
||||||
This one is fairly specialized, but this is the only thing that we do
|
This one is fairly specialized, but this is the only thing that we do
|
||||||
|
@ -127,7 +122,6 @@ class DomainInvitationPermissionDeleteView(DomainInvitationPermission, DeleteVie
|
||||||
|
|
||||||
|
|
||||||
class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteView, abc.ABC):
|
class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract view for deleting a DomainApplication."""
|
"""Abstract view for deleting a DomainApplication."""
|
||||||
|
|
||||||
model = DomainApplication
|
model = DomainApplication
|
||||||
|
@ -135,7 +129,6 @@ class DomainApplicationPermissionDeleteView(DomainApplicationPermission, DeleteV
|
||||||
|
|
||||||
|
|
||||||
class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC):
|
class UserDomainRolePermissionDeleteView(UserDeleteDomainRolePermission, DeleteView, abc.ABC):
|
||||||
|
|
||||||
"""Abstract base view for deleting a UserDomainRole.
|
"""Abstract base view for deleting a UserDomainRole.
|
||||||
|
|
||||||
This abstract view cannot be instantiated. Actual views must specify
|
This abstract view cannot be instantiated. Actual views must specify
|
||||||
|
|
|
@ -1,18 +1,18 @@
|
||||||
-i https://pypi.python.org/simple
|
-i https://pypi.python.org/simple
|
||||||
annotated-types==0.6.0; python_version >= '3.8'
|
annotated-types==0.6.0; python_version >= '3.8'
|
||||||
asgiref==3.7.2; python_version >= '3.7'
|
asgiref==3.7.2; python_version >= '3.7'
|
||||||
boto3==1.33.7; python_version >= '3.7'
|
boto3==1.34.37; python_version >= '3.8'
|
||||||
botocore==1.33.7; python_version >= '3.7'
|
botocore==1.34.37; python_version >= '3.8'
|
||||||
cachetools==5.3.2; python_version >= '3.7'
|
cachetools==5.3.2; python_version >= '3.7'
|
||||||
certifi==2023.11.17; python_version >= '3.6'
|
certifi==2024.2.2; python_version >= '3.6'
|
||||||
cfenv==0.5.3
|
cfenv==0.5.3
|
||||||
cffi==1.16.0; python_version >= '3.8'
|
cffi==1.16.0; platform_python_implementation != 'PyPy'
|
||||||
charset-normalizer==3.3.2; python_full_version >= '3.7.0'
|
charset-normalizer==3.3.2; python_full_version >= '3.7.0'
|
||||||
cryptography==41.0.7; python_version >= '3.7'
|
cryptography==42.0.2; python_version >= '3.7'
|
||||||
defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
defusedxml==0.7.1; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
dj-database-url==2.1.0
|
dj-database-url==2.1.0
|
||||||
dj-email-url==1.0.6
|
dj-email-url==1.0.6
|
||||||
django==4.2.7; python_version >= '3.8'
|
django==4.2.10; python_version >= '3.8'
|
||||||
django-allow-cidr==0.7.1
|
django-allow-cidr==0.7.1
|
||||||
django-auditlog==2.3.0; python_version >= '3.7'
|
django-auditlog==2.3.0; python_version >= '3.7'
|
||||||
django-cache-url==3.4.5
|
django-cache-url==3.4.5
|
||||||
|
@ -20,42 +20,42 @@ django-cors-headers==4.3.1; python_version >= '3.8'
|
||||||
django-csp==3.7
|
django-csp==3.7
|
||||||
django-fsm==2.8.1
|
django-fsm==2.8.1
|
||||||
django-login-required-middleware==0.9.0
|
django-login-required-middleware==0.9.0
|
||||||
django-phonenumber-field[phonenumberslite]==7.2.0; python_version >= '3.8'
|
django-phonenumber-field[phonenumberslite]==7.3.0; python_version >= '3.8'
|
||||||
django-widget-tweaks==1.5.0; python_version >= '3.8'
|
django-widget-tweaks==1.5.0; python_version >= '3.8'
|
||||||
environs[django]==9.5.0; python_version >= '3.6'
|
environs[django]==10.3.0; python_version >= '3.8'
|
||||||
faker==20.1.0; python_version >= '3.8'
|
faker==23.1.0; python_version >= '3.8'
|
||||||
fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a3a9a345f0ef561c
|
fred-epplib@ git+https://github.com/cisagov/epplib.git@d56d183f1664f34c40ca9716a3a9a345f0ef561c
|
||||||
furl==2.1.3
|
furl==2.1.3
|
||||||
future==0.18.3; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
future==0.18.3; python_version >= '2.6' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
gevent==23.9.1; python_version >= '3.8'
|
gevent==23.9.1; python_version >= '3.8'
|
||||||
geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4
|
geventconnpool@ git+https://github.com/rasky/geventconnpool.git@1bbb93a714a331a069adf27265fe582d9ba7ecd4
|
||||||
greenlet==3.0.1; python_version >= '3.7'
|
greenlet==3.0.3; python_version >= '3.7'
|
||||||
gunicorn==21.2.0; python_version >= '3.5'
|
gunicorn==21.2.0; python_version >= '3.5'
|
||||||
idna==3.6; python_version >= '3.5'
|
idna==3.6; python_version >= '3.5'
|
||||||
jmespath==1.0.1; python_version >= '3.7'
|
jmespath==1.0.1; python_version >= '3.7'
|
||||||
lxml==4.9.3; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
lxml==5.1.0; python_version >= '3.6'
|
||||||
mako==1.3.0; python_version >= '3.8'
|
mako==1.3.2; python_version >= '3.8'
|
||||||
markupsafe==2.1.3; python_version >= '3.7'
|
markupsafe==2.1.5; python_version >= '3.7'
|
||||||
marshmallow==3.20.1; python_version >= '3.8'
|
marshmallow==3.20.2; python_version >= '3.8'
|
||||||
oic==1.6.1; python_version ~= '3.7'
|
oic==1.6.1; python_version ~= '3.7'
|
||||||
orderedmultidict==1.0.1
|
orderedmultidict==1.0.1
|
||||||
packaging==23.2; python_version >= '3.7'
|
packaging==23.2; python_version >= '3.7'
|
||||||
phonenumberslite==8.13.26
|
phonenumberslite==8.13.29
|
||||||
psycopg2-binary==2.9.9; python_version >= '3.7'
|
psycopg2-binary==2.9.9; python_version >= '3.7'
|
||||||
pycparser==2.21
|
pycparser==2.21
|
||||||
pycryptodomex==3.19.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
pycryptodomex==3.20.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3, 3.4'
|
||||||
pydantic==2.5.2; python_version >= '3.7'
|
pydantic==2.6.1; python_version >= '3.8'
|
||||||
pydantic-core==2.14.5; python_version >= '3.7'
|
pydantic-core==2.16.2; python_version >= '3.8'
|
||||||
pydantic-settings==2.1.0; python_version >= '3.8'
|
pydantic-settings==2.1.0; python_version >= '3.8'
|
||||||
pyjwkest==1.4.2
|
pyjwkest==1.4.2
|
||||||
python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
python-dateutil==2.8.2; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
python-dotenv==1.0.0; python_version >= '3.8'
|
python-dotenv==1.0.1; python_version >= '3.8'
|
||||||
requests==2.31.0; python_version >= '3.7'
|
requests==2.31.0; python_version >= '3.7'
|
||||||
s3transfer==0.8.2; python_version >= '3.7'
|
s3transfer==0.10.0; python_version >= '3.8'
|
||||||
setuptools==69.0.2; python_version >= '3.8'
|
setuptools==69.0.3; python_version >= '3.8'
|
||||||
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
six==1.16.0; python_version >= '2.7' and python_version not in '3.0, 3.1, 3.2, 3.3'
|
||||||
sqlparse==0.4.4; python_version >= '3.5'
|
sqlparse==0.4.4; python_version >= '3.5'
|
||||||
typing-extensions==4.8.0; python_version >= '3.8'
|
typing-extensions==4.9.0; python_version >= '3.8'
|
||||||
urllib3==2.0.7; python_version >= '3.7'
|
urllib3==2.0.7; python_version >= '3.7'
|
||||||
whitenoise==6.6.0; python_version >= '3.8'
|
whitenoise==6.6.0; python_version >= '3.8'
|
||||||
zope.event==5.0; python_version >= '3.7'
|
zope.event==5.0; python_version >= '3.7'
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue