From d84a7890224ca1ec52c2e5097e8c0c1104589cdd Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Thu, 26 Dec 2024 17:10:37 -0800
Subject: [PATCH 01/77] Renewal form
---
src/registrar/config/urls.py | 5 ++
src/registrar/fixtures/fixtures_domains.py | 2 +-
src/registrar/models/domain.py | 5 ++
src/registrar/templates/domain_base.html | 9 +-
src/registrar/templates/domain_detail.html | 4 +-
src/registrar/templates/domain_sidebar.html | 10 ++-
src/registrar/templatetags/custom_filters.py | 1 +
src/registrar/views/__init__.py | 1 +
src/registrar/views/domain.py | 92 ++++++++++++++++++--
9 files changed, 117 insertions(+), 12 deletions(-)
diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py
index 66708c571..2bf7b9e5f 100644
--- a/src/registrar/config/urls.py
+++ b/src/registrar/config/urls.py
@@ -345,6 +345,11 @@ urlpatterns = [
views.DomainSecurityEmailView.as_view(),
name="domain-security-email",
),
+ path(
+ "domain//renewal",
+ views.DomainRenewalView.as_view(),
+ name="domain-renewal",
+ ),
path(
"domain//users/add",
views.DomainAddUserView.as_view(),
diff --git a/src/registrar/fixtures/fixtures_domains.py b/src/registrar/fixtures/fixtures_domains.py
index 4606024d0..4d4115180 100644
--- a/src/registrar/fixtures/fixtures_domains.py
+++ b/src/registrar/fixtures/fixtures_domains.py
@@ -44,7 +44,7 @@ class DomainFixture(DomainRequestFixture):
cls._approve_domain_requests(users)
@staticmethod
- def _generate_fake_expiration_date(days_in_future=365):
+ def _generate_fake_expiration_date(days_in_future=40):
"""Generates a fake expiration date between 1 and 365 days in the future."""
current_date = timezone.now().date() # nosec
return current_date + timedelta(days=random.randint(1, days_in_future)) # nosec
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 6eb2fac07..3fa6a61b2 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -1167,6 +1167,11 @@ class Domain(TimeStampedModel, DomainHelper):
threshold_date = now + timedelta(days=60)
return now < self.expiration_date <= threshold_date
+ ###dummy method for testing for domain renewal form fail or success banner
+
+ def update_expiration(self, success=True):
+ return success
+
def state_display(self, request=None):
"""Return the display status of the domain."""
if self.is_expired() and (self.state != self.State.UNKNOWN):
diff --git a/src/registrar/templates/domain_base.html b/src/registrar/templates/domain_base.html
index 9f7e8d2e6..de8e88791 100644
--- a/src/registrar/templates/domain_base.html
+++ b/src/registrar/templates/domain_base.html
@@ -1,5 +1,7 @@
{% extends "base.html" %}
{% load static %}
+{% load static url_helpers %}
+
{% block title %}{{ domain.name }} | {% endblock %}
@@ -53,8 +55,11 @@
{% endif %}
{% block domain_content %}
-
+ {% if request.path|endswith:"renewal"%}
+
Renew {{domain.name}}
+ {%else%}
Domain Overview
+ {% endif%}
{% endblock %} {# domain_content #}
{% endif %}
@@ -62,4 +67,4 @@
-{% endblock %} {# content #}
+{% endblock %} {# content #}
\ No newline at end of file
diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html
index a5b8e52cb..b168f7e82 100644
--- a/src/registrar/templates/domain_detail.html
+++ b/src/registrar/templates/domain_detail.html
@@ -50,7 +50,9 @@
{% if domain.get_state_help_text %}
{% if has_domain_renewal_flag and domain.is_expiring and is_domain_manager %}
- This domain will expire soon. Renew to maintain access.
+ This domain will expire soon.
+ {% url 'domain-renewal' pk=domain.id as url %}
+ Renew to maintain access.
{% elif has_domain_renewal_flag and domain.is_expiring and is_portfolio_user %}
This domain will expire soon. Contact one of the listed domain managers to renew the domain.
{% else %}
diff --git a/src/registrar/templates/domain_sidebar.html b/src/registrar/templates/domain_sidebar.html
index 289f544ce..dc97f5ca1 100644
--- a/src/registrar/templates/domain_sidebar.html
+++ b/src/registrar/templates/domain_sidebar.html
@@ -79,8 +79,14 @@
{% with url_name="domain-users" %}
{% include "includes/domain_sidenav_item.html" with item_text="Domain managers" %}
{% endwith %}
-
+
+ {% if has_domain_renewal_flag and is_domain_manager and domain.is_expiring %}
+ {% with url_name="domain-renewal" %}
+ {% include "includes/domain_sidenav_item.html" with item_text="Renewal form" %}
+ {% endwith %}
+ {% endif %}
+
{% endif %}
-
+
\ No newline at end of file
diff --git a/src/registrar/templatetags/custom_filters.py b/src/registrar/templatetags/custom_filters.py
index 6140130c8..6f3894ea5 100644
--- a/src/registrar/templatetags/custom_filters.py
+++ b/src/registrar/templatetags/custom_filters.py
@@ -200,6 +200,7 @@ def is_domain_subpage(path):
"domain-users-add",
"domain-request-delete",
"domain-user-delete",
+ "domain-renewal",
"invitation-cancel",
]
return get_url_name(path) in url_names
diff --git a/src/registrar/views/__init__.py b/src/registrar/views/__init__.py
index a80b16b1a..4e3faced1 100644
--- a/src/registrar/views/__init__.py
+++ b/src/registrar/views/__init__.py
@@ -14,6 +14,7 @@ from .domain import (
DomainInvitationCancelView,
DomainDeleteUserView,
PrototypeDomainDNSRecordView,
+ DomainRenewalView,
)
from .user_profile import UserProfileView, FinishProfileSetupView
from .health import *
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index cb3da1f83..99a173517 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -12,7 +12,7 @@ from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.db import IntegrityError
from django.http import HttpResponseRedirect
-from django.shortcuts import redirect
+from django.shortcuts import redirect, render
from django.urls import reverse
from django.views.generic.edit import FormMixin
from django.conf import settings
@@ -307,6 +307,90 @@ class DomainView(DomainBaseView):
self._update_session_with_domain()
+class DomainRenewalView(DomainBaseView):
+ """Domain detail overview page."""
+
+ template_name = "domain_renewal.html"
+
+ def get_context_data(self, **kwargs):
+ context = super().get_context_data(**kwargs)
+
+ default_emails = [DefaultEmail.PUBLIC_CONTACT_DEFAULT.value, DefaultEmail.LEGACY_DEFAULT.value]
+ context["hidden_security_emails"] = default_emails
+
+ security_email = self.object.get_security_email()
+ user = self.request.user
+ if security_email is None or security_email in default_emails:
+ context["security_email"] = None
+ context["user"] = user
+ return context
+
+ def can_access_domain_via_portfolio(self, pk):
+ """Most views should not allow permission to portfolio users.
+ If particular views allow permissions, they will need to override
+ this function."""
+ portfolio = self.request.session.get("portfolio")
+ if self.request.user.has_any_domains_portfolio_permission(portfolio):
+ if Domain.objects.filter(id=pk).exists():
+ domain = Domain.objects.get(id=pk)
+ if domain.domain_info.portfolio == portfolio:
+ return True
+ return False
+
+ def in_editable_state(self, pk):
+ """Override in_editable_state from DomainPermission
+ Allow detail page to be viewable"""
+
+ requested_domain = None
+ if Domain.objects.filter(id=pk).exists():
+ requested_domain = Domain.objects.get(id=pk)
+
+ # return true if the domain exists, this will allow the detail page to load
+ if requested_domain:
+ return True
+ return False
+
+ def _get_domain(self, request):
+ """
+ override get_domain for this view so that domain overview
+ always resets the cache for the domain object
+ """
+ self.session = request.session
+ self.object = self.get_object()
+ self._update_session_with_domain()
+
+ def post(self, request, pk):
+ domain = Domain.objects.filter(id=pk).first()
+
+ # Check if the checkbox is checked
+ is_policy_acknowledged = request.POST.get("is_policy_acknowledged", None)
+ if is_policy_acknowledged != "on":
+ print("!!! Checkbox is NOT acknowledged")
+ messages.error(
+ request, "Check the box if you read and agree to the requirements for operating a .gov domain."
+ )
+ return render(
+ request,
+ "domain_renewal.html",
+ {
+ "domain": domain,
+ "form": request.POST,
+ },
+ )
+
+ print("*** Checkbox is acknowledged")
+ if "submit_button" in request.POST:
+ print("*** Submit button clicked")
+ updated_expiration = domain.update_expiration(success=True)
+ print("*** Updated expiration result:", updated_expiration)
+
+ if updated_expiration is True:
+ messages.success(request, "This domain has been renewed for one year")
+ else:
+ messages.error(request, "This domain has not been renewed")
+ return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
+
+
class DomainOrgNameAddressView(DomainFormBaseView):
"""Organization view"""
@@ -807,11 +891,7 @@ class DomainDNSSECView(DomainFormBaseView):
has_dnssec_records = self.object.dnssecdata is not None
# Create HTML for the modal button
- modal_button = (
- ''
- )
+ modal_button = ''
context["modal_button"] = modal_button
context["has_dnssec_records"] = has_dnssec_records
From b5658a357b6aa9b49c7c37393ae1f8893dbebbeb Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Thu, 26 Dec 2024 17:15:07 -0800
Subject: [PATCH 02/77] Fix linter
---
src/registrar/models/domain.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 3fa6a61b2..715f1b9da 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -1167,7 +1167,7 @@ class Domain(TimeStampedModel, DomainHelper):
threshold_date = now + timedelta(days=60)
return now < self.expiration_date <= threshold_date
- ###dummy method for testing for domain renewal form fail or success banner
+ # Dummy method for testing for domain renewal form fail or success banner
def update_expiration(self, success=True):
return success
From 8b9eb93b682a3f8b714c42558b90db6b94bc7c57 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Mon, 30 Dec 2024 11:07:33 -0500
Subject: [PATCH 03/77] added back domain renewal form
---
src/registrar/templates/domain_renewal.html | 127 ++++++++++++++++++++
1 file changed, 127 insertions(+)
create mode 100644 src/registrar/templates/domain_renewal.html
diff --git a/src/registrar/templates/domain_renewal.html b/src/registrar/templates/domain_renewal.html
new file mode 100644
index 000000000..c179941d6
--- /dev/null
+++ b/src/registrar/templates/domain_renewal.html
@@ -0,0 +1,127 @@
+{% extends "domain_base.html" %}
+{% load static url_helpers %}
+{% load custom_filters %}
+
+{% block domain_content %}
+ {% block breadcrumb %}
+ {% if portfolio %}
+
+
+ {% endif %}
+ {% endblock breadcrumb %}
+
+ {{ block.super }}
+
+
Confirm the following information for accuracy
+
Review these details below. We
+ require that you maintain accurate information for the domain.
+ The details you provide will only be used to support eh administration of .gov and won't be made public.
+
+
If you would like to retire your domain instead, please
+ contact us.
+
Required fields are marked with an asterisk (*).
+
+
+
+ {% url 'user-profile' as url %}
+ {% include "includes/summary_item.html" with title='Your Contact Information' value=user edit_link=url editable=is_editable contact='true' %}
+
+
+
+ {% if analyst_action != 'edit' or analyst_action_location != domain.pk %}
+ {% if is_portfolio_user and not is_domain_manager %}
+
+
+
+ You don't have access to manage {{domain.name}}. If you need to make updates, contact one of the listed domain managers.
+
+
+
+ {% endif %}
+ {% endif %}
+
+ {% url 'domain-security-email' pk=domain.id as url %}
+ {% if security_email is not None and security_email not in hidden_security_emails%}
+ {% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=is_editable %}
+ {% else %}
+ {% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url editable=is_editable %}
+ {% endif %}
+ {% url 'domain-users' pk=domain.id as url %}
+ {% if portfolio %}
+ {% include "includes/summary_item.html" with title='Domain managers' domain_permissions=True value=domain edit_link=url editable=is_editable %}
+ {% else %}
+ {% include "includes/summary_item.html" with title='Domain managers' list=True users=True value=domain.permissions.all edit_link=url editable=is_editable %}
+ {% endif %}
+
+
+
Review these details below. We
+ require that you maintain accurate information for the domain.
+ The details you provide will only be used to support eh administration of .gov and won't be made public.
+
+
If you would like to retire your domain instead, please
+ contact us.
+
Required fields are marked with an asterisk (*).
+
+
+
+ {% url 'user-profile' as url %}
+ {% include "includes/summary_item.html" with title='Your Contact Information' value=user edit_link=url editable=is_editable contact='true' %}
+
+
+
+ {% if analyst_action != 'edit' or analyst_action_location != domain.pk %}
+ {% if is_portfolio_user and not is_domain_manager %}
+
+
+
+ You don't have access to manage {{domain.name}}. If you need to make updates, contact one of the listed domain managers.
+
+
+
+ {% endif %}
+ {% endif %}
+
+ {% url 'domain-security-email' pk=domain.id as url %}
+ {% if security_email is not None and security_email not in hidden_security_emails%}
+ {% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=is_editable %}
+ {% else %}
+ {% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url editable=is_editable %}
+ {% endif %}
+ {% url 'domain-users' pk=domain.id as url %}
+ {% if portfolio %}
+ {% include "includes/summary_item.html" with title='Domain managers' domain_permissions=True value=domain edit_link=url editable=is_editable %}
+ {% else %}
+ {% include "includes/summary_item.html" with title='Domain managers' list=True users=True value=domain.permissions.all edit_link=url editable=is_editable %}
+ {% endif %}
+
+
+
+
+
+
+
+
+
+
+
+{% endblock %} {# domain_content #}
\ No newline at end of file
From e23d81f7e7d4096e76450b0cca84908846484872 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Mon, 30 Dec 2024 12:44:52 -0500
Subject: [PATCH 05/77] added renew method
---
src/registrar/models/domain.py | 6 +++++-
src/registrar/views/domain.py | 11 ++++++-----
2 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 715f1b9da..e170c8668 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -322,28 +322,32 @@ class Domain(TimeStampedModel, DomainHelper):
"""
# If no date is specified, grab the registry_expiration_date
+ print("checking if there is a date")
try:
exp_date = self.registry_expiration_date
except KeyError:
# if no expiration date from registry, set it to today
logger.warning("current expiration date not set; setting to today")
exp_date = date.today()
-
+ print("we got the date", exp_date)
# create RenewDomain request
request = commands.RenewDomain(name=self.name, cur_exp_date=exp_date, period=epp.Period(length, unit))
try:
# update expiration date in registry, and set the updated
# expiration date in the registrar, and in the cache
+ print("we are in the second try")
self._cache["ex_date"] = registry.send(request, cleaned=True).res_data[0].ex_date
self.expiration_date = self._cache["ex_date"]
self.save()
except RegistryError as err:
# if registry error occurs, log the error, and raise it as well
+ print("registry error")
logger.error(f"registry error renewing domain: {err}")
raise (err)
except Exception as e:
# exception raised during the save to registrar
+ print("this is the last error")
logger.error(f"error updating expiration date in registrar: {e}")
raise (e)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 99a173517..1c1996c65 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -381,12 +381,13 @@ class DomainRenewalView(DomainBaseView):
print("*** Checkbox is acknowledged")
if "submit_button" in request.POST:
print("*** Submit button clicked")
- updated_expiration = domain.update_expiration(success=True)
- print("*** Updated expiration result:", updated_expiration)
-
- if updated_expiration is True:
+ # updated_expiration = domain.update_expiration(success=True)
+ # print("*** Updated expiration result:", updated_expiration)
+ try:
+ domain.renew_domain()
messages.success(request, "This domain has been renewed for one year")
- else:
+ except Exception as e:
+ print(f'An error occured: {e}')
messages.error(request, "This domain has not been renewed")
return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
From a128086d6f5e2cf51dda942dfc92c7dceb92a45d Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Tue, 31 Dec 2024 10:13:53 -0800
Subject: [PATCH 06/77] Update print statements and exp timing
---
src/registrar/models/domain.py | 16 +++++++++-------
src/registrar/views/domain.py | 5 +++--
2 files changed, 12 insertions(+), 9 deletions(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index e170c8668..b7145ec0c 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -322,32 +322,34 @@ class Domain(TimeStampedModel, DomainHelper):
"""
# If no date is specified, grab the registry_expiration_date
- print("checking if there is a date")
+ print("*** Checking if there is a date")
try:
exp_date = self.registry_expiration_date
except KeyError:
# if no expiration date from registry, set it to today
- logger.warning("current expiration date not set; setting to today")
- exp_date = date.today()
- print("we got the date", exp_date)
+ logger.warning("*** Current expiration date not set; setting to 35 days ")
+ # exp_date = date.today()
+ exp_date = date.today() - timedelta(days=35)
+ print(exp_date)
+ print("*** The exp_date is", exp_date)
# create RenewDomain request
request = commands.RenewDomain(name=self.name, cur_exp_date=exp_date, period=epp.Period(length, unit))
try:
# update expiration date in registry, and set the updated
# expiration date in the registrar, and in the cache
- print("we are in the second try")
+ print("** In renew_domain in 2nd try statement")
self._cache["ex_date"] = registry.send(request, cleaned=True).res_data[0].ex_date
self.expiration_date = self._cache["ex_date"]
self.save()
except RegistryError as err:
# if registry error occurs, log the error, and raise it as well
- print("registry error")
+ print("*** Registry error")
logger.error(f"registry error renewing domain: {err}")
raise (err)
except Exception as e:
# exception raised during the save to registrar
- print("this is the last error")
+ print("*** In renew_domain, in the last Exception statement")
logger.error(f"error updating expiration date in registrar: {e}")
raise (e)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 1c1996c65..dd8e9928b 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -384,11 +384,12 @@ class DomainRenewalView(DomainBaseView):
# updated_expiration = domain.update_expiration(success=True)
# print("*** Updated expiration result:", updated_expiration)
try:
+ print("*** Did we get into the try statement")
domain.renew_domain()
messages.success(request, "This domain has been renewed for one year")
except Exception as e:
- print(f'An error occured: {e}')
- messages.error(request, "This domain has not been renewed")
+ print(f"An error occured: {e}")
+ messages.error(request, "*** This domain has not been renewed")
return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
From c145ecbfa29d925af2806343eb8d8534677d8ac5 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Tue, 31 Dec 2024 13:55:18 -0500
Subject: [PATCH 07/77] put back the fixtures command
---
src/registrar/fixtures/fixtures_domains.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/fixtures/fixtures_domains.py b/src/registrar/fixtures/fixtures_domains.py
index 4d4115180..4606024d0 100644
--- a/src/registrar/fixtures/fixtures_domains.py
+++ b/src/registrar/fixtures/fixtures_domains.py
@@ -44,7 +44,7 @@ class DomainFixture(DomainRequestFixture):
cls._approve_domain_requests(users)
@staticmethod
- def _generate_fake_expiration_date(days_in_future=40):
+ def _generate_fake_expiration_date(days_in_future=365):
"""Generates a fake expiration date between 1 and 365 days in the future."""
current_date = timezone.now().date() # nosec
return current_date + timedelta(days=random.randint(1, days_in_future)) # nosec
From e5f9696bac942a946c92430ff36dc6eba489b608 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Fri, 3 Jan 2025 10:43:35 -0500
Subject: [PATCH 08/77] added tests
---
src/registrar/tests/test_views_domain.py | 15 +++++++++++++++
1 file changed, 15 insertions(+)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index ba237e1e7..767445810 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -529,6 +529,21 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
)
self.assertContains(detail_page, "Renew to maintain access")
+ @override_flag("domain_renewal", active=True)
+ def test_domain_renewal_sidebar_and_form(self):
+ self.client.force_login(self.user)
+ with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
+ Domain, "is_expired", self.custom_is_expired
+ ):
+ detail_page = self.client.get(
+ reverse("domain", kwargs={"pk": self.expiringdomain.id}),
+ )
+ self.assertContains(detail_page, "Renewal form")
+ response = self.client.get(reverse("domain-renewal",kwargs={"pk": self.expiringdomain.id}))
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, f"Renew {self.expiringdomain.name}")
+
+
class TestDomainManagers(TestDomainOverview):
@classmethod
From 4feb29b269a39417e35fae2589b7026fbee757c3 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Fri, 3 Jan 2025 10:47:42 -0800
Subject: [PATCH 09/77] Add in tests for making edit is clickable and goes to
right route
---
src/registrar/tests/test_views_domain.py | 57 +++++++++++++++++++++++-
1 file changed, 55 insertions(+), 2 deletions(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 767445810..281b7291e 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -539,10 +539,63 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
reverse("domain", kwargs={"pk": self.expiringdomain.id}),
)
self.assertContains(detail_page, "Renewal form")
- response = self.client.get(reverse("domain-renewal",kwargs={"pk": self.expiringdomain.id}))
+ response = self.client.get(reverse("domain-renewal", kwargs={"pk": self.expiringdomain.id}))
self.assertEqual(response.status_code, 200)
self.assertContains(response, f"Renew {self.expiringdomain.name}")
-
+
+ @override_flag("domain_renewal", active=True)
+ def test_domain_renewal_form_your_contact_info_edit(self):
+ with less_console_noise():
+ # Start on the Renewal page for the domain
+ renewal_page = self.app.get(reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id}))
+
+ # Verify we see "Your Contact Information" on the renewal form
+ self.assertContains(renewal_page, "Your Contact Information")
+
+ # Verify that the "Edit" button for Your Contact is there and links to correct URL
+ edit_button_url = reverse("user-profile")
+ self.assertContains(renewal_page, f'href="{edit_button_url}"')
+
+ # Simulate clicking on edit button
+ edit_page = renewal_page.click(href=edit_button_url, index=1)
+ self.assertEqual(edit_page.status_code, 200)
+ self.assertContains(edit_page, "Review the details below and update any required information")
+
+ @override_flag("domain_renewal", active=True)
+ def test_domain_renewal_form_security_contact_edit(self):
+ with less_console_noise():
+ # Start on the Renewal page for the domain
+ renewal_page = self.app.get(reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id}))
+
+ # Verify we see "Security email" on the renewal form
+ self.assertContains(renewal_page, "Security email")
+
+ # Verify that the "Edit" button for Security email is there and links to correct URL
+ edit_button_url = reverse("domain-security-email", kwargs={"pk": self.domain_with_ip.id})
+ self.assertContains(renewal_page, f'href="{edit_button_url}"')
+
+ # Simulate clicking on edit button
+ edit_page = renewal_page.click(href=edit_button_url, index=1)
+ self.assertEqual(edit_page.status_code, 200)
+ self.assertContains(edit_page, "A security contact should be capable of evaluating")
+
+ @override_flag("domain_renewal", active=True)
+ def test_domain_renewal_form_domain_manager_edit(self):
+ with less_console_noise():
+ # Start on the Renewal page for the domain
+ renewal_page = self.app.get(reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id}))
+
+ # Verify we see "Domain managers" on the renewal form
+ self.assertContains(renewal_page, "Domain managers")
+
+ # Verify that the "Edit" button for Domain managers is there and links to correct URL
+ edit_button_url = reverse("domain-users", kwargs={"pk": self.domain_with_ip.id})
+ self.assertContains(renewal_page, f'href="{edit_button_url}"')
+
+ # Simulate clicking on edit button
+ edit_page = renewal_page.click(href=edit_button_url, index=1)
+ self.assertEqual(edit_page.status_code, 200)
+ self.assertContains(edit_page, "Domain managers can update all information related to a domain")
class TestDomainManagers(TestDomainOverview):
From 3f3ba22a119db0568861440f88dc0632d2ae4bfd Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Fri, 3 Jan 2025 11:28:48 -0800
Subject: [PATCH 10/77] Update text to click on link
---
src/registrar/tests/test_views_domain.py | 15 ++++++++++++++-
1 file changed, 14 insertions(+), 1 deletion(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 281b7291e..02d7aa9ac 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -535,11 +535,24 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
Domain, "is_expired", self.custom_is_expired
):
+ # Grab the detail page
detail_page = self.client.get(
reverse("domain", kwargs={"pk": self.expiringdomain.id}),
)
+
+ # Make sure we see the link as a domain manager
+ self.assertContains(detail_page, "Renew to maintain access")
+
+ # Make sure we can see Renewal form on the sidebar since it's expiring
self.assertContains(detail_page, "Renewal form")
- response = self.client.get(reverse("domain-renewal", kwargs={"pk": self.expiringdomain.id}))
+
+ # Grab link to the renewal page
+ renewal_form_url = reverse("domain-renewal", kwargs={"pk": self.expiringdomain.id})
+ self.assertContains(detail_page, f'href="{renewal_form_url}"')
+
+ # Simulate clicking the link
+ response = self.client.get(renewal_form_url)
+
self.assertEqual(response.status_code, 200)
self.assertContains(response, f"Renew {self.expiringdomain.name}")
From dca70f4195237db300508421ecc59b0a43bab908 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Sat, 4 Jan 2025 14:17:55 -0800
Subject: [PATCH 11/77] Unit test for submit and recieving error message
---
src/registrar/tests/test_views_domain.py | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 02d7aa9ac..50b8f31f6 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -9,6 +9,7 @@ from api.tests.common import less_console_noise_decorator
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from .common import MockEppLib, MockSESClient, create_user # type: ignore
from django_webtest import WebTest # type: ignore
+from django.contrib.messages import get_messages
import boto3_mocking # type: ignore
from registrar.utility.errors import (
@@ -610,6 +611,25 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
self.assertEqual(edit_page.status_code, 200)
self.assertContains(edit_page, "Domain managers can update all information related to a domain")
+ @override_flag("domain_renewal", active=True)
+ def test_ack_checkbox_not_checked(self):
+
+ # Grab the renewal URL
+ renewal_url = reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id})
+
+ # Test clicking the checkbox
+ response = self.client.post(renewal_url, data={"submit_button": "next"})
+
+ # Verify the error message is displayed
+ # Retrieves messages obj (used in the post call)
+ messages = list(get_messages(response.wsgi_request))
+ # Check we only get 1 error message
+ self.assertEqual(len(messages), 1)
+ # Check that the 1 error msg also is the right text
+ self.assertEqual(
+ str(messages[0]),
+ "Check the box if you read and agree to the requirements for operating a .gov domain.",
+ )
class TestDomainManagers(TestDomainOverview):
@classmethod
From bad8a8c98a75c1df161321c6a49d4b087d19e291 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Sat, 4 Jan 2025 14:48:21 -0800
Subject: [PATCH 12/77] Fix padding on form and addin subtext for security
email
---
src/registrar/templates/domain_renewal.html | 7 ++++---
src/registrar/templates/includes/summary_item.html | 8 +++++---
src/registrar/tests/test_views_domain.py | 1 +
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/src/registrar/templates/domain_renewal.html b/src/registrar/templates/domain_renewal.html
index eda7a8bdd..4bf69dbca 100644
--- a/src/registrar/templates/domain_renewal.html
+++ b/src/registrar/templates/domain_renewal.html
@@ -26,6 +26,7 @@
{{ block.super }}
Confirm the following information for accuracy
+
HELLO
Review these details below. We
require that you maintain accurate information for the domain.
The details you provide will only be used to support eh administration of .gov and won't be made public.
@@ -55,9 +56,9 @@
{% url 'domain-security-email' pk=domain.id as url %}
{% if security_email is not None and security_email not in hidden_security_emails%}
- {% include "includes/summary_item.html" with title='Security email' value=security_email edit_link=url editable=is_editable %}
+ {% include "includes/summary_item.html" with title='Security email' value=security_email custom_text_for_value_none='We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain.' edit_link=url editable=is_editable %}
{% else %}
- {% include "includes/summary_item.html" with title='Security email' value='None provided' edit_link=url editable=is_editable %}
+ {% include "includes/summary_item.html" with title='Security email' value='None provided' custom_text_for_value_none='We strongly recommend that you provide a security email. This email will allow the public to report observed or suspected security issues on your domain.' edit_link=url editable=is_editable %}
{% endif %}
{% url 'domain-users' pk=domain.id as url %}
{% if portfolio %}
@@ -67,7 +68,7 @@
{% endif %}
-
+
{% url 'user-profile' as url %}
{% include "includes/summary_item.html" with title='Your Contact Information' value=user edit_link=url editable=is_editable contact='true' %}
@@ -66,62 +78,50 @@
{% include "includes/summary_item.html" with title='Domain managers' list=True users=True value=domain.permissions.all edit_link=url editable=is_editable %}
{% endif %}
-
+
+
+
+
+
+
{% endblock %} {# domain_content #}
\ No newline at end of file
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index ee8adf903..0a4096fbf 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -454,7 +454,7 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
self.user.save()
- def todays_expiration_date(self):
+ def expiration_date_one_year_out(self):
todays_date = datetime.today()
new_expiration_date = todays_date.replace(year=todays_date.year + 1)
return new_expiration_date
@@ -466,7 +466,7 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
return True
def custom_renew_domain(self):
- self.domain_with_ip.expiration_date = self.todays_expiration_date()
+ self.domain_with_ip.expiration_date = self.expiration_date_one_year_out()
self.domain_with_ip.save()
@override_flag("domain_renewal", active=True)
@@ -659,7 +659,7 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
self.assertRedirects(response, reverse("domain", kwargs={"pk": self.domain_with_ip.id}))
# Check for the updated expiration
- formatted_new_expiration_date = self.todays_expiration_date().strftime("%b. %-d, %Y")
+ formatted_new_expiration_date = self.expiration_date_one_year_out().strftime("%b. %-d, %Y")
redirect_response = self.client.get(reverse("domain", kwargs={"pk": self.domain_with_ip.id}), follow=True)
self.assertContains(redirect_response, formatted_new_expiration_date)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index b849459f2..593fc9093 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -12,11 +12,11 @@ from django.contrib import messages
from django.contrib.messages.views import SuccessMessageMixin
from django.db import IntegrityError
from django.http import HttpResponseRedirect
-from django.shortcuts import redirect, render
+from django.shortcuts import redirect, render, get_object_or_404
from django.urls import reverse
from django.views.generic.edit import FormMixin
from django.conf import settings
-from registrar.forms.domain import DomainSuborganizationForm
+from registrar.forms.domain import DomainSuborganizationForm, DomainRenewalForm
from registrar.models import (
Domain,
DomainRequest,
@@ -364,30 +364,32 @@ class DomainRenewalView(DomainBaseView):
self._update_session_with_domain()
def post(self, request, pk):
- domain = Domain.objects.filter(id=pk).first()
+ domain = get_object_or_404(Domain, id=pk)
- # Check if the checkbox is checked
- is_policy_acknowledged = request.POST.get("is_policy_acknowledged", None)
- if is_policy_acknowledged != "on":
- messages.error(
- request, "Check the box if you read and agree to the requirements for operating a .gov domain."
- )
- return render(
- request,
- "domain_renewal.html",
- {
- "domain": domain,
- "form": request.POST,
- },
- )
+ form = DomainRenewalForm(request.POST)
- if "submit_button" in request.POST:
- try:
- domain.renew_domain()
- messages.success(request, "This domain has been renewed for one year.")
- except Exception as e:
- messages.error(request, "This domain has not been renewed for one year, error was %s" % e)
- return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
+ if form.is_valid():
+ # check for key in the post request data
+ if "submit_button" in request.POST:
+ try:
+ domain.renew_domain()
+ messages.success(request, "This domain has been renewed for one year.")
+ except Exception as e:
+ messages.error(
+ request,
+ "This domain has not been renewed for one year, please email help@get.gov if this problem persists.",
+ )
+ return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
+
+ # if not valid, render the template with error messages
+ return render(
+ request,
+ "domain_renewal.html",
+ {
+ "domain": domain,
+ "form": form,
+ },
+ )
class DomainOrgNameAddressView(DomainFormBaseView):
From e196e02d9284c55057ec1dc6ce4736c6b0f3e0ba Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Tue, 7 Jan 2025 17:28:35 -0800
Subject: [PATCH 44/77] Address linter errors
---
src/registrar/views/domain.py | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 593fc9093..4b26caa5f 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -374,10 +374,11 @@ class DomainRenewalView(DomainBaseView):
try:
domain.renew_domain()
messages.success(request, "This domain has been renewed for one year.")
- except Exception as e:
+ except Exception:
messages.error(
request,
- "This domain has not been renewed for one year, please email help@get.gov if this problem persists.",
+ "This domain has not been renewed for one year, "
+ "please email help@get.gov if this problem persists.",
)
return HttpResponseRedirect(reverse("domain", kwargs={"pk": pk}))
From aad1ee976b5735633d93caa1a1b9724a46206206 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Tue, 7 Jan 2025 17:40:37 -0800
Subject: [PATCH 45/77] Fix checkbox unchecked test
---
src/registrar/tests/test_views_domain.py | 14 +++-----------
1 file changed, 3 insertions(+), 11 deletions(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 0a4096fbf..ef4d415df 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -631,19 +631,11 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
# Grab the renewal URL
renewal_url = reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id})
- # Test clicking the checkbox
+ # Test that the checkbox is not checked
response = self.client.post(renewal_url, data={"submit_button": "next"})
- # Verify the error message is displayed
- # Retrieves messages obj (used in the post call)
- messages = list(get_messages(response.wsgi_request))
- # Check we only get 1 error message
- self.assertEqual(len(messages), 1)
- # Check that the 1 error msg also is the right text
- self.assertEqual(
- str(messages[0]),
- "Check the box if you read and agree to the requirements for operating a .gov domain.",
- )
+ error_message = "Check the box if you read and agree to the requirements for operating a .gov domain."
+ self.assertContains(response, error_message)
@override_flag("domain_renewal", active=True)
def test_ack_checkbox_checked(self):
From 33e36590a4e0ff9b21836d22848618bc456b0533 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Tue, 7 Jan 2025 17:43:54 -0800
Subject: [PATCH 46/77] Remove unused import for linter
---
src/registrar/tests/test_views_domain.py | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index ef4d415df..79240286a 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -11,7 +11,6 @@ from api.tests.common import less_console_noise_decorator
from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from .common import MockEppLib, MockSESClient, create_user # type: ignore
from django_webtest import WebTest # type: ignore
-from django.contrib.messages import get_messages
import boto3_mocking # type: ignore
from registrar.utility.errors import (
From 5ca74fdc5374b864db3aa6e32b6d2c5ebed3882c Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Wed, 8 Jan 2025 10:38:50 -0700
Subject: [PATCH 47/77] Finish unit tests
---
.../commands/create_federal_portfolio.py | 32 ++++++++----
.../tests/test_management_scripts.py | 50 +++++++++++++++++--
2 files changed, 68 insertions(+), 14 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index 8ff32824b..ddcb5a4a9 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -79,7 +79,7 @@ class Command(BaseCommand):
else:
raise CommandError(f"Cannot find '{branch}' federal agencies in our database.")
- portfolio_set = set()
+ portfolios = []
for federal_agency in agencies:
message = f"Processing federal agency '{federal_agency.agency}'..."
TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message)
@@ -87,7 +87,7 @@ class Command(BaseCommand):
# C901 'Command.handle' is too complex (12)
# We currently only grab the list of changed domain requests, but we may want to grab the domains too
portfolio = self.handle_populate_portfolio(federal_agency, parse_domains, parse_requests, both)
- portfolio_set.add(portfolio)
+ portfolios.append(portfolio)
except Exception as exec:
self.failed_portfolios.add(federal_agency)
logger.error(exec)
@@ -106,9 +106,14 @@ class Command(BaseCommand):
# POST PROCESSING STEP: Remove the federal agency if it matches the portfolio name.
# We only do this for started domain requests.
if parse_requests:
- self.post_process_started_domain_requests(portfolio_set)
+ TerminalHelper.prompt_for_execution(
+ system_exit_on_terminate=True,
+ prompt_message="This action will update domain requests even if they aren't on a portfolio.",
+ prompt_title="Do you want to clear federal agency on started domain requests?",
+ )
+ self.post_process_started_domain_requests(agencies, portfolios)
- def post_process_started_domain_requests(self, portfolio_set):
+ def post_process_started_domain_requests(self, agencies, portfolios):
"""
Removes duplicate organization data by clearing federal_agency when it matches the portfolio name.
Only processes domain requests in STARTED status.
@@ -116,15 +121,24 @@ class Command(BaseCommand):
message = "Removing duplicate portfolio and federal_agency values from domain requests..."
TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message)
+ # For each request, clear the federal agency under these conditions:
+ # 1. A portfolio *already exists* with the same name as the federal agency.
+ # 2. Said portfolio (or portfolios) are only the ones specified at the start of the script.
+ # 3. The domain request is in status "started".
+ # Note: Both names are normalized so excess spaces are stripped and the string is lowercased.
domain_requests_to_update = DomainRequest.objects.filter(
- portfolio__in=portfolio_set,
- status=DomainRequest.DomainRequestStatus.STARTED,
+ federal_agency__in=agencies,
federal_agency__agency__isnull=False,
- portfolio__organization_name__isnull=False,
+ status=DomainRequest.DomainRequestStatus.STARTED,
+ organization_name__isnull=False,
)
+ portfolio_set = {normalize_string(portfolio.organization_name) for portfolio in portfolios if portfolio}
+
+ # Update the request, assuming the given agency name matches the portfolio name
updated_requests = []
for req in domain_requests_to_update:
- if normalize_string(req.federal_agency.agency) == normalize_string(req.portfolio.organization_name):
+ agency_name = normalize_string(req.federal_agency.agency)
+ if agency_name in portfolio_set:
req.federal_agency = None
updated_requests.append(req)
DomainRequest.objects.bulk_update(updated_requests, ["federal_agency"])
@@ -140,8 +154,6 @@ class Command(BaseCommand):
def handle_populate_portfolio(self, federal_agency, parse_domains, parse_requests, both):
"""Attempts to create a portfolio. If successful, this function will
also create new suborganizations.
-
- Returns the processed portfolio
"""
portfolio, created = self.create_portfolio(federal_agency)
if created:
diff --git a/src/registrar/tests/test_management_scripts.py b/src/registrar/tests/test_management_scripts.py
index 882396f1e..8ecb7cbea 100644
--- a/src/registrar/tests/test_management_scripts.py
+++ b/src/registrar/tests/test_management_scripts.py
@@ -1424,7 +1424,6 @@ class TestCreateFederalPortfolio(TestCase):
# Create an agency wih no federal type (can only be created via specifiying it manually)
self.federal_agency = FederalAgency.objects.create(agency="Test Federal Agency")
- self.federal_agency_2 = FederalAgency.objects.create(agency="Sugarcane")
# And create some with federal_type ones with creative names
self.executive_agency_1 = FederalAgency.objects.create(
@@ -1518,8 +1517,13 @@ class TestCreateFederalPortfolio(TestCase):
call_command("create_federal_portfolio", **kwargs)
@less_console_noise_decorator
- def test_handle_portfolio_requests_sync_federal_agency(self):
- """Test that federal agency is cleared when org name matches portfolio name"""
+ def test_post_process_started_domain_requests_existing_portfolio(self):
+ """Ensures that federal agency is cleared when agency name matches portfolio name.
+ As the name implies, this implicitly tests the "post_process_started_domain_requests" function.
+ """
+ federal_agency_2 = FederalAgency.objects.create(agency="Sugarcane", federal_type=BranchChoices.EXECUTIVE)
+
+ # Test records with portfolios and no org names
# Create a portfolio. This script skips over "started"
portfolio = Portfolio.objects.create(organization_name="Sugarcane", creator=self.user)
# Create a domain request with matching org name
@@ -1527,7 +1531,7 @@ class TestCreateFederalPortfolio(TestCase):
name="matching.gov",
status=DomainRequest.DomainRequestStatus.STARTED,
generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
- federal_agency=self.federal_agency_2,
+ federal_agency=federal_agency_2,
user=self.user,
portfolio=portfolio,
)
@@ -1558,6 +1562,44 @@ class TestCreateFederalPortfolio(TestCase):
self.assertIsNotNone(matching_request_in_wrong_status.portfolio)
self.assertEqual(matching_request_in_wrong_status.portfolio.organization_name, "Test Federal Agency")
+ @less_console_noise_decorator
+ def test_post_process_started_domain_requests(self):
+ """Tests that federal agency is cleared when agency name
+ matches an existing portfolio's name, even if the domain request isn't
+ directly on that portfolio."""
+
+ federal_agency_2 = FederalAgency.objects.create(agency="Sugarcane", federal_type=BranchChoices.EXECUTIVE)
+
+ # Create a request with matching federal_agency name but no direct portfolio association
+ matching_agency_request = completed_domain_request(
+ name="agency-match.gov",
+ status=DomainRequest.DomainRequestStatus.STARTED,
+ generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
+ federal_agency=federal_agency_2,
+ user=self.user,
+ )
+
+ # Create a control request that shouldn't match
+ non_matching_request = completed_domain_request(
+ name="no-match.gov",
+ status=DomainRequest.DomainRequestStatus.STARTED,
+ generic_org_type=DomainRequest.OrganizationChoices.FEDERAL,
+ federal_agency=self.federal_agency,
+ user=self.user,
+ )
+
+ # We expect the matching agency to have its fed agency cleared.
+ self.run_create_federal_portfolio(agency_name="Sugarcane", parse_requests=True)
+ matching_agency_request.refresh_from_db()
+ non_matching_request.refresh_from_db()
+
+ # Request with matching agency name should have federal_agency cleared
+ self.assertIsNone(matching_agency_request.federal_agency)
+
+ # Non-matching request should keep its federal_agency
+ self.assertIsNotNone(non_matching_request.federal_agency)
+ self.assertEqual(non_matching_request.federal_agency, self.federal_agency)
+
@less_console_noise_decorator
def test_create_single_portfolio(self):
"""Test portfolio creation with suborg and senior official."""
From bc92270897cfc8967894e874f3cdddb39c8e78c6 Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Wed, 8 Jan 2025 10:49:04 -0700
Subject: [PATCH 48/77] Update create_federal_portfolio.py
---
.../commands/create_federal_portfolio.py | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index ddcb5a4a9..72548aa08 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -85,7 +85,6 @@ class Command(BaseCommand):
TerminalHelper.colorful_logger(logger.info, TerminalColors.MAGENTA, message)
try:
# C901 'Command.handle' is too complex (12)
- # We currently only grab the list of changed domain requests, but we may want to grab the domains too
portfolio = self.handle_populate_portfolio(federal_agency, parse_domains, parse_requests, both)
portfolios.append(portfolio)
except Exception as exec:
@@ -105,11 +104,12 @@ class Command(BaseCommand):
# POST PROCESSING STEP: Remove the federal agency if it matches the portfolio name.
# We only do this for started domain requests.
- if parse_requests:
+ if parse_requests or both:
TerminalHelper.prompt_for_execution(
system_exit_on_terminate=True,
prompt_message="This action will update domain requests even if they aren't on a portfolio.",
- prompt_title="Do you want to clear federal agency on started domain requests?",
+ prompt_title="Do you want to clear federal agency on (related) started domain requests?",
+ verify_message=None
)
self.post_process_started_domain_requests(agencies, portfolios)
@@ -141,15 +141,18 @@ class Command(BaseCommand):
if agency_name in portfolio_set:
req.federal_agency = None
updated_requests.append(req)
- DomainRequest.objects.bulk_update(updated_requests, ["federal_agency"])
- # Log the results
+ # Execute the update and Log the results
if TerminalHelper.prompt_for_execution(
system_exit_on_terminate=False,
- prompt_message=f"Updated {len(updated_requests)} domain requests successfully.",
- prompt_title="Do you want to see a list of all changed domain requests?",
+ prompt_message=(
+ f"{len(domain_requests_to_update)} domain requests will be updated. "
+ f"These records will be changed: {[str(req) for req in updated_requests]}"
+ ),
+ prompt_title="Do wish to commit this update to the database?",
):
- logger.info(f"Federal agency set to none on: {[str(request) for request in updated_requests]}")
+ DomainRequest.objects.bulk_update(updated_requests, ["federal_agency"])
+ TerminalHelper.colorful_logger(logger.info, TerminalColors.OKBLUE, "Action completed successfully.")
def handle_populate_portfolio(self, federal_agency, parse_domains, parse_requests, both):
"""Attempts to create a portfolio. If successful, this function will
From b9dc92808440a5b124e6d146193302156920ee8c Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Wed, 8 Jan 2025 10:56:06 -0700
Subject: [PATCH 49/77] lint
---
src/registrar/management/commands/create_federal_portfolio.py | 4 ++--
src/registrar/models/utility/generic_helper.py | 2 +-
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index 72548aa08..d0fb14a9f 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -109,7 +109,7 @@ class Command(BaseCommand):
system_exit_on_terminate=True,
prompt_message="This action will update domain requests even if they aren't on a portfolio.",
prompt_title="Do you want to clear federal agency on (related) started domain requests?",
- verify_message=None
+ verify_message=None,
)
self.post_process_started_domain_requests(agencies, portfolios)
@@ -248,7 +248,7 @@ class Command(BaseCommand):
TerminalHelper.colorful_logger(logger.warning, TerminalColors.YELLOW, message)
else:
new_suborgs.append(
- Suborganization(name=normalize_string(name, lowercase=False), portfolio=portfolio)
+ Suborganization(name=name, portfolio=portfolio)
) # type: ignore
if new_suborgs:
diff --git a/src/registrar/models/utility/generic_helper.py b/src/registrar/models/utility/generic_helper.py
index 3a8da508e..e8992acc2 100644
--- a/src/registrar/models/utility/generic_helper.py
+++ b/src/registrar/models/utility/generic_helper.py
@@ -345,7 +345,7 @@ def value_of_attribute(obj, attribute_name: str):
return value
-def normalize_string(string_to_normalize: str, lowercase=True) -> str:
+def normalize_string(string_to_normalize, lowercase=True):
"""Normalizes a given string. Returns a string without extra spaces, in all lowercase."""
if not isinstance(string_to_normalize, str):
logger.error(f"normalize_string => {string_to_normalize} is not type str.")
From 628c4c0d0e4015a248bcc2ee33d583bbf5bcdb69 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Wed, 8 Jan 2025 13:56:48 -0500
Subject: [PATCH 50/77] expired domain renewal form
---
src/registrar/templates/domain_detail.html | 6 ++++++
src/registrar/templates/domain_sidebar.html | 2 +-
2 files changed, 7 insertions(+), 1 deletion(-)
diff --git a/src/registrar/templates/domain_detail.html b/src/registrar/templates/domain_detail.html
index b168f7e82..becf46d5b 100644
--- a/src/registrar/templates/domain_detail.html
+++ b/src/registrar/templates/domain_detail.html
@@ -50,11 +50,17 @@
{% if domain.get_state_help_text %}
{% if has_domain_renewal_flag and domain.is_expiring and is_domain_manager %}
+ This domain has expired, but it is still online.
+ {% url 'domain-renewal' pk=domain.id as url %}
+ Renew to maintain access.
+ {% elif has_domain_renewal_flag and domain.is_expired and is_domain_manager %}
This domain will expire soon.
{% url 'domain-renewal' pk=domain.id as url %}
Renew to maintain access.
{% elif has_domain_renewal_flag and domain.is_expiring and is_portfolio_user %}
This domain will expire soon. Contact one of the listed domain managers to renew the domain.
+ {% elif has_domain_renewal_flag and domain.is_expired and is_portfolio_user %}
+ This domain has expired, but it is still online. Contact one of the listed domain managers to renew the domain.
{% else %}
{{ domain.get_state_help_text }}
{% endif %}
diff --git a/src/registrar/templates/domain_sidebar.html b/src/registrar/templates/domain_sidebar.html
index 9d71ebf63..c9feb7200 100644
--- a/src/registrar/templates/domain_sidebar.html
+++ b/src/registrar/templates/domain_sidebar.html
@@ -80,7 +80,7 @@
{% include "includes/domain_sidenav_item.html" with item_text="Domain managers" %}
{% endwith %}
- {% if has_domain_renewal_flag and is_domain_manager and domain.is_expiring %}
+ {% if has_domain_renewal_flag and is_domain_manager and (domain.is_expiring or domain.is_expired) %}
{% with url_name="domain-renewal" %}
{% include "includes/domain_sidenav_item.html" with item_text="Renewal form" %}
{% endwith %}
From 6da172c0285ad0c568216311ecbe397b9103a81f Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Wed, 8 Jan 2025 12:25:17 -0700
Subject: [PATCH 51/77] Update create_federal_portfolio.py
---
.../management/commands/create_federal_portfolio.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index d0fb14a9f..4f4002da4 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -108,7 +108,9 @@ class Command(BaseCommand):
TerminalHelper.prompt_for_execution(
system_exit_on_terminate=True,
prompt_message="This action will update domain requests even if they aren't on a portfolio.",
- prompt_title="Do you want to clear federal agency on (related) started domain requests?",
+ prompt_title=(
+ "POST PROCESS STEP: Do you want to clear federal agency on (related) started domain requests?"
+ ),
verify_message=None,
)
self.post_process_started_domain_requests(agencies, portfolios)
@@ -247,9 +249,7 @@ class Command(BaseCommand):
)
TerminalHelper.colorful_logger(logger.warning, TerminalColors.YELLOW, message)
else:
- new_suborgs.append(
- Suborganization(name=name, portfolio=portfolio)
- ) # type: ignore
+ new_suborgs.append(Suborganization(name=name, portfolio=portfolio)) # type: ignore
if new_suborgs:
Suborganization.objects.bulk_create(new_suborgs)
From e8fede74ac05885d3b83d90b5cff372f870a5c89 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Wed, 8 Jan 2025 15:25:06 -0500
Subject: [PATCH 52/77] updated code to fix parsing error
---
src/registrar/templates/domain_sidebar.html | 10 +--
src/registrar/tests/test_views_domain.py | 77 +++++++++++++++------
2 files changed, 61 insertions(+), 26 deletions(-)
diff --git a/src/registrar/templates/domain_sidebar.html b/src/registrar/templates/domain_sidebar.html
index c9feb7200..336a9fe7c 100644
--- a/src/registrar/templates/domain_sidebar.html
+++ b/src/registrar/templates/domain_sidebar.html
@@ -80,10 +80,12 @@
{% include "includes/domain_sidenav_item.html" with item_text="Domain managers" %}
{% endwith %}
- {% if has_domain_renewal_flag and is_domain_manager and (domain.is_expiring or domain.is_expired) %}
- {% with url_name="domain-renewal" %}
- {% include "includes/domain_sidenav_item.html" with item_text="Renewal form" %}
- {% endwith %}
+ {% if has_domain_renewal_flag and is_domain_manager%}
+ {% if domain.is_expiring or domain.is_expired %}
+ {% with url_name="domain-renewal" %}
+ {% include "includes/domain_sidenav_item.html" with item_text="Renewal form" %}
+ {% endwith %}
+ {% endif %}
{% endif %}
{% endif %}
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index ee8adf903..406e96ed4 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -440,15 +440,15 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
username="usertest",
)
- self.expiringdomain, _ = Domain.objects.get_or_create(
- name="expiringdomain.gov",
+ self.domaintorenew, _ = Domain.objects.get_or_create(
+ name="domainrenewal.gov",
)
UserDomainRole.objects.get_or_create(
- user=self.user, domain=self.expiringdomain, role=UserDomainRole.Roles.MANAGER
+ user=self.user, domain=self.domaintorenew, role=UserDomainRole.Roles.MANAGER
)
- DomainInformation.objects.get_or_create(creator=self.user, domain=self.expiringdomain)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=self.domaintorenew)
self.portfolio, _ = Portfolio.objects.get_or_create(organization_name="Test org", creator=self.user)
@@ -459,9 +459,12 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
new_expiration_date = todays_date.replace(year=todays_date.year + 1)
return new_expiration_date
- def custom_is_expired(self):
+ def custom_is_expired_false(self):
return False
+ def custom_is_expired_true(self):
+ return True
+
def custom_is_expiring(self):
return True
@@ -473,11 +476,11 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
def test_expiring_domain_on_detail_page_as_domain_manager(self):
self.client.force_login(self.user)
with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
- Domain, "is_expired", self.custom_is_expired
+ Domain, "is_expired", self.custom_is_expired_false
):
- self.assertEquals(self.expiringdomain.state, Domain.State.UNKNOWN)
+ self.assertEquals(self.domaintorenew.state, Domain.State.UNKNOWN)
detail_page = self.client.get(
- reverse("domain", kwargs={"pk": self.expiringdomain.id}),
+ reverse("domain", kwargs={"pk": self.domaintorenew.id}),
)
self.assertContains(detail_page, "Expiring soon")
@@ -508,17 +511,17 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
],
)
- expiringdomain2, _ = Domain.objects.get_or_create(name="bogusdomain2.gov")
+ domaintorenew2, _ = Domain.objects.get_or_create(name="bogusdomain2.gov")
DomainInformation.objects.get_or_create(
- creator=non_dom_manage_user, domain=expiringdomain2, portfolio=self.portfolio
+ creator=non_dom_manage_user, domain=domaintorenew2, portfolio=self.portfolio
)
non_dom_manage_user.refresh_from_db()
self.client.force_login(non_dom_manage_user)
with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
- Domain, "is_expired", self.custom_is_expired
+ Domain, "is_expired", self.custom_is_expired_false
):
detail_page = self.client.get(
- reverse("domain", kwargs={"pk": expiringdomain2.id}),
+ reverse("domain", kwargs={"pk": domaintorenew2.id}),
)
self.assertContains(detail_page, "Contact one of the listed domain managers to renew the domain.")
@@ -527,29 +530,29 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
def test_expiring_domain_on_detail_page_in_org_model_as_a_domain_manager(self):
portfolio, _ = Portfolio.objects.get_or_create(organization_name="Test org2", creator=self.user)
- expiringdomain3, _ = Domain.objects.get_or_create(name="bogusdomain3.gov")
+ domaintorenew3, _ = Domain.objects.get_or_create(name="bogusdomain3.gov")
- UserDomainRole.objects.get_or_create(user=self.user, domain=expiringdomain3, role=UserDomainRole.Roles.MANAGER)
- DomainInformation.objects.get_or_create(creator=self.user, domain=expiringdomain3, portfolio=portfolio)
+ UserDomainRole.objects.get_or_create(user=self.user, domain=domaintorenew3, role=UserDomainRole.Roles.MANAGER)
+ DomainInformation.objects.get_or_create(creator=self.user, domain=domaintorenew3, portfolio=portfolio)
self.user.refresh_from_db()
self.client.force_login(self.user)
with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
- Domain, "is_expired", self.custom_is_expired
+ Domain, "is_expired", self.custom_is_expired_false
):
detail_page = self.client.get(
- reverse("domain", kwargs={"pk": expiringdomain3.id}),
+ reverse("domain", kwargs={"pk": domaintorenew3.id}),
)
self.assertContains(detail_page, "Renew to maintain access")
@override_flag("domain_renewal", active=True)
- def test_domain_renewal_form_and_sidebar(self):
+ def test_domain_renewal_form_and_sidebar_expiring(self):
self.client.force_login(self.user)
with patch.object(Domain, "is_expiring", self.custom_is_expiring), patch.object(
- Domain, "is_expired", self.custom_is_expired
+ Domain, "is_expiring", self.custom_is_expiring
):
# Grab the detail page
detail_page = self.client.get(
- reverse("domain", kwargs={"pk": self.expiringdomain.id}),
+ reverse("domain", kwargs={"pk": self.domaintorenew.id}),
)
# Make sure we see the link as a domain manager
@@ -559,14 +562,44 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
self.assertContains(detail_page, "Renewal form")
# Grab link to the renewal page
- renewal_form_url = reverse("domain-renewal", kwargs={"pk": self.expiringdomain.id})
+ renewal_form_url = reverse("domain-renewal", kwargs={"pk": self.domaintorenew.id})
self.assertContains(detail_page, f'href="{renewal_form_url}"')
# Simulate clicking the link
response = self.client.get(renewal_form_url)
self.assertEqual(response.status_code, 200)
- self.assertContains(response, f"Renew {self.expiringdomain.name}")
+ self.assertContains(response, f"Renew {self.domaintorenew.name}")
+
+ @override_flag("domain_renewal", active=True)
+ def test_domain_renewal_form_and_sidebar_expired(self):
+
+ self.client.force_login(self.user)
+
+ with patch.object(Domain, "is_expired", self.custom_is_expired_true), patch.object(
+ Domain, "is_expired", self.custom_is_expired_true
+ ):
+ # Grab the detail page
+ detail_page = self.client.get(
+ reverse("domain", kwargs={"pk": self.domaintorenew.id}),
+ )
+
+ print("puglesss", self.domaintorenew.is_expired)
+ # Make sure we see the link as a domain manager
+ self.assertContains(detail_page, "Renew to maintain access")
+
+ # Make sure we can see Renewal form on the sidebar since it's expired
+ self.assertContains(detail_page, "Renewal form")
+
+ # Grab link to the renewal page
+ renewal_form_url = reverse("domain-renewal", kwargs={"pk": self.domaintorenew.id})
+ self.assertContains(detail_page, f'href="{renewal_form_url}"')
+
+ # Simulate clicking the link
+ response = self.client.get(renewal_form_url)
+
+ self.assertEqual(response.status_code, 200)
+ self.assertContains(response, f"Renew {self.domaintorenew.name}")
@override_flag("domain_renewal", active=True)
def test_domain_renewal_form_your_contact_info_edit(self):
From c7af6645d4a8ffac6a3b33b307f97ed6871aded2 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Wed, 8 Jan 2025 15:31:59 -0500
Subject: [PATCH 53/77] ran app black .
---
src/registrar/tests/test_views_domain.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 406e96ed4..575dc0faf 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -464,7 +464,7 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
def custom_is_expired_true(self):
return True
-
+
def custom_is_expiring(self):
return True
@@ -570,12 +570,12 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
self.assertEqual(response.status_code, 200)
self.assertContains(response, f"Renew {self.domaintorenew.name}")
-
+
@override_flag("domain_renewal", active=True)
def test_domain_renewal_form_and_sidebar_expired(self):
-
+
self.client.force_login(self.user)
-
+
with patch.object(Domain, "is_expired", self.custom_is_expired_true), patch.object(
Domain, "is_expired", self.custom_is_expired_true
):
From acd20e89141f7a581fdb62281fc3d5c082d3b780 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Wed, 8 Jan 2025 21:16:01 -0800
Subject: [PATCH 54/77] Fix uncheck error
---
src/registrar/templates/domain_renewal.html | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/src/registrar/templates/domain_renewal.html b/src/registrar/templates/domain_renewal.html
index bf529a04d..7867bfce8 100644
--- a/src/registrar/templates/domain_renewal.html
+++ b/src/registrar/templates/domain_renewal.html
@@ -103,7 +103,9 @@
class="usa-checkbox__input"
id="renewal-checkbox"
type="checkbox"
- name="{{ form.is_policy_acknowledged.name }}">
+ name="{{ form.is_policy_acknowledged.name }}"
+ {% if form.is_policy_acknowledged.value %}checked{% endif %}
+ >
{% url 'user-profile' as url %}
- {% include "includes/summary_item.html" with title='Your Contact Information' value=request.user edit_link=url editable=is_editable contact='true' %}
+ {% include "includes/summary_item.html" with title='Your contact information' value=request.user edit_link=url editable=is_editable contact='true' %}
{% if analyst_action != 'edit' or analyst_action_location != domain.pk %}
{% if is_portfolio_user and not is_domain_manager %}
From 25ba5b2a5172c4f7e4cd79eac25663ec0a80b4a6 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Fri, 10 Jan 2025 09:56:58 -0800
Subject: [PATCH 67/77] Fix test capitalization
---
src/registrar/tests/test_views_domain.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/tests/test_views_domain.py b/src/registrar/tests/test_views_domain.py
index 56bfe7306..d92da17dd 100644
--- a/src/registrar/tests/test_views_domain.py
+++ b/src/registrar/tests/test_views_domain.py
@@ -607,7 +607,7 @@ class TestDomainDetailDomainRenewal(TestDomainOverview):
renewal_page = self.app.get(reverse("domain-renewal", kwargs={"pk": self.domain_with_ip.id}))
# Verify we see "Your contact information" on the renewal form
- self.assertContains(renewal_page, "Your Contact Information")
+ self.assertContains(renewal_page, "Your contact information")
# Verify that the "Edit" button for Your contact is there and links to correct URL
edit_button_url = reverse("user-profile")
From 19114c7e7214474e2afcb49a57140846e40640c6 Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Fri, 10 Jan 2025 11:02:31 -0800
Subject: [PATCH 68/77] Fix checkbox issue
---
src/registrar/templates/domain_renewal.html | 7 +++----
src/registrar/views/domain.py | 3 +++
2 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/src/registrar/templates/domain_renewal.html b/src/registrar/templates/domain_renewal.html
index f81389efb..02c9666e3 100644
--- a/src/registrar/templates/domain_renewal.html
+++ b/src/registrar/templates/domain_renewal.html
@@ -94,14 +94,13 @@
{% csrf_token %}
- {% if form.is_policy_acknowledged.errors %}
-
{{ form.is_policy_acknowledged.errors|join:" " }}
- {% endif %}
+
-
+
Required fields are marked with an asterisk (*).
-
+
{% url 'user-profile' as url %}
{% include "includes/summary_item.html" with title='Your contact information' value=request.user edit_link=url editable=is_editable contact='true' %}
From 9241790e48b8618087804c154b197de3ede3bd73 Mon Sep 17 00:00:00 2001
From: asaki222
Date: Fri, 10 Jan 2025 16:04:11 -0500
Subject: [PATCH 73/77] added exec info true
---
src/registrar/models/domain.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/models/domain.py b/src/registrar/models/domain.py
index 6a135036d..6bd8278a1 100644
--- a/src/registrar/models/domain.py
+++ b/src/registrar/models/domain.py
@@ -326,7 +326,7 @@ class Domain(TimeStampedModel, DomainHelper):
exp_date = self.registry_expiration_date
except KeyError:
# if no expiration date from registry, set it to today
- logger.warning("current expiration date not set; setting to today")
+ logger.warning("current expiration date not set; setting to today", exc_info=True)
exp_date = date.today()
# create RenewDomain request
request = commands.RenewDomain(name=self.name, cur_exp_date=exp_date, period=epp.Period(length, unit))
From 797561df45c3783576d34b684bf92fe88930563a Mon Sep 17 00:00:00 2001
From: Rebecca Hsieh
Date: Mon, 13 Jan 2025 08:58:58 -0800
Subject: [PATCH 74/77] Remove duplicated function
---
src/registrar/views/domain.py | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/src/registrar/views/domain.py b/src/registrar/views/domain.py
index 2c741055f..4b2edba06 100644
--- a/src/registrar/views/domain.py
+++ b/src/registrar/views/domain.py
@@ -316,18 +316,6 @@ class DomainRenewalView(DomainView):
template_name = "domain_renewal.html"
- def can_access_domain_via_portfolio(self, pk):
- """Most views should not allow permission to portfolio users.
- If particular views allow permissions, they will need to override
- this function."""
- portfolio = self.request.session.get("portfolio")
- if self.request.user.has_any_domains_portfolio_permission(portfolio):
- if Domain.objects.filter(id=pk).exists():
- domain = Domain.objects.get(id=pk)
- if domain.domain_info.portfolio == portfolio:
- return True
- return False
-
def post(self, request, pk):
domain = get_object_or_404(Domain, id=pk)
From 5308217d225b7750ea83305c99020314206e514d Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Mon, 13 Jan 2025 10:08:08 -0700
Subject: [PATCH 75/77] Added better function comment for add_arugments
---
.../commands/create_federal_portfolio.py | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index dc21c6f64..096580609 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -22,10 +22,21 @@ class Command(BaseCommand):
self.failed_portfolios = set()
def add_arguments(self, parser):
- """Add three arguments:
- 1. agency_name => the value of FederalAgency.agency
- 2. --parse_requests => if true, adds the given portfolio to each related DomainRequest
- 3. --parse_domains => if true, adds the given portfolio to each related DomainInformation
+ """Add command line arguments to create federal portfolios.
+
+ Required (mutually exclusive) arguments:
+ --agency_name: Name of a specific FederalAgency to create a portfolio for
+ --branch: Federal branch to process ("executive", "legislative", or "judicial").
+ Creates portfolios for all FederalAgencies in that branch.
+
+ Required (at least one):
+ --parse_requests: Add the created portfolio(s) to related DomainRequest records
+ --parse_domains: Add the created portfolio(s) to related DomainInformation records
+ Note: You can use both --parse_requests and --parse_domains together
+
+ Optional (mutually exclusive with parse options):
+ --both: Shorthand for using both --parse_requests and --parse_domains
+ Cannot be used with --parse_requests or --parse_domains
"""
group = parser.add_mutually_exclusive_group(required=True)
group.add_argument(
From f6e94da96868cf2d915b4a5e8d0f74052793773b Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Mon, 13 Jan 2025 10:12:43 -0700
Subject: [PATCH 76/77] Update
src/registrar/management/commands/create_federal_portfolio.py
---
src/registrar/management/commands/create_federal_portfolio.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index 096580609..a3c8d3e21 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -162,7 +162,7 @@ class Command(BaseCommand):
f"{len(domain_requests_to_update)} domain requests will be updated. "
f"These records will be changed: {[str(req) for req in updated_requests]}"
),
- prompt_title="Do wish to commit this update to the database?",
+ prompt_title="Do you wish to commit this update to the database?",
):
DomainRequest.objects.bulk_update(updated_requests, ["federal_agency"])
TerminalHelper.colorful_logger(logger.info, TerminalColors.OKBLUE, "Action completed successfully.")
From 0f59a631d294dddbf11b44104c83f60662d43890 Mon Sep 17 00:00:00 2001
From: zandercymatics <141044360+zandercymatics@users.noreply.github.com>
Date: Mon, 13 Jan 2025 10:30:23 -0700
Subject: [PATCH 77/77] Lint
---
src/registrar/management/commands/create_federal_portfolio.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/registrar/management/commands/create_federal_portfolio.py b/src/registrar/management/commands/create_federal_portfolio.py
index 096580609..5731154a2 100644
--- a/src/registrar/management/commands/create_federal_portfolio.py
+++ b/src/registrar/management/commands/create_federal_portfolio.py
@@ -26,12 +26,12 @@ class Command(BaseCommand):
Required (mutually exclusive) arguments:
--agency_name: Name of a specific FederalAgency to create a portfolio for
- --branch: Federal branch to process ("executive", "legislative", or "judicial").
+ --branch: Federal branch to process ("executive", "legislative", or "judicial").
Creates portfolios for all FederalAgencies in that branch.
Required (at least one):
--parse_requests: Add the created portfolio(s) to related DomainRequest records
- --parse_domains: Add the created portfolio(s) to related DomainInformation records
+ --parse_domains: Add the created portfolio(s) to related DomainInformation records
Note: You can use both --parse_requests and --parse_domains together
Optional (mutually exclusive with parse options):