diff --git a/.github/ISSUE_TEMPLATE/developer-onboarding.md b/.github/ISSUE_TEMPLATE/developer-onboarding.md index 11b2d86fc..8d0f9c2d8 100644 --- a/.github/ISSUE_TEMPLATE/developer-onboarding.md +++ b/.github/ISSUE_TEMPLATE/developer-onboarding.md @@ -24,13 +24,13 @@ There are several tools we use locally that you will need to have. ### Steps for the onboardee - [ ] Setup [commit signing in Github](#setting-up-commit-signing) and with git locally. - [ ] [Create a cloud.gov account](https://cloud.gov/docs/getting-started/accounts/) -- [ ] Have an admin add you to the CISA Github organization and Dotgov Team. +- [ ] Email github@cisa.dhs.gov (cc: Cameron) to add you to the [CISA Github organization](https://github.com/getgov) and [.gov Team](https://github.com/orgs/cisagov/teams/gov). - [ ] Ensure you can login to your cloud.gov account via the CLI ```bash cf login -a api.fr.cloud.gov --sso ``` - [ ] Have an admin add you to cloud.gov org and set up your [sandbox developer space](#setting-up-developer-sandbox). Ensure you can deploy to your sandbox space. -- [ ] Have an admin add you to our login.gov sandbox team (`.gov registrar poc`) via the [dashboard](https://dashboard.int.identitysandbox.gov/). +- [ ] Have an admin add you to our login.gov sandbox team (`.gov Registrar`) via the [dashboard](https://dashboard.int.identitysandbox.gov/). **Note:** As mentioned in the [Login documentation](https://developers.login.gov/testing/), the sandbox Login account is different account from your regular, production Login account. If you have not created a Login account for the sandbox before, you will need to create a new account first. @@ -39,12 +39,12 @@ cf login -a api.fr.cloud.gov --sso ### Steps for the onboarder - [ ] Add the onboardee to cloud.gov org (cisa-getgov-prototyping) - [ ] Setup a [developer specific space for the new developer](#setting-up-developer-sandbox) -- [ ] Add the onboardee to our login.gov sandbox team (`.gov registrar poc`) via the [dashboard](https://dashboard.int.identitysandbox.gov/) +- [ ] Add the onboardee to our login.gov sandbox team (`.gov Registrar`) via the [dashboard](https://dashboard.int.identitysandbox.gov/) ## Documents to Review -- [ ] [Team Charter](https://docs.google.com/document/d/1xhMKlW8bMcxyF7ipsOYxw1SQYVi-lWPkcDHSUS6miNg/edit), in particular our Github Policy +- [ ] [Team Onboarding](https://docs.google.com/document/d/1ukbpW4LSqkb_CCt8LWfpehP03qqfyYfvK3Fl21NaEq8/edit?usp=sharing) - [ ] [Architecture Decision Records](https://github.com/cisagov/dotgov/tree/main/docs/architecture/decisions) - [ ] [Contributing Policy](https://github.com/cisagov/dotgov/tree/main/CONTRIBUTING.md) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 1eeef397b..f65007b2b 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,13 +1,134 @@ -# # +## Ticket -## 🗣 Description ## +Resolves #00 + - +All other changes require just a single approving review.--> -## 💭 Motivation and context ## +## Changes - - - - \ No newline at end of file + +- Change 1 +- Change 2 + + + +## Context for reviewers + + + +## Setup + + + +## Code Review Verification Steps + +### As the original developer, I have + +#### Satisfied acceptance criteria and met development standards + +- [ ] Met the acceptance criteria, or will meet them in a subsequent PR +- [ ] Created/modified automated tests +- [ ] Added at least 2 developers as PR reviewers (only 1 will need to approve) +- [ ] Messaged on Slack or in standup to notify the team that a PR is ready for review +- [ ] Changes to “how we do things” are documented in READMEs and or onboarding guide +- [ ] If any model was updated to modify/add/delete columns, makemigrations was ran and the assoicated migrations file has been commited. + +#### Ensured code standards are met (Original Developer) + +- [ ] All new functions and methods are commented using plain language +- [ ] Did dependency updates in Pipfile also get changed in requirements.txt? +- [ ] Interactions with external systems are wrapped in try/except +- [ ] Error handling exists for unusual or missing values + +#### Validated user-facing changes (if applicable) + +- [ ] New pages have been added to .pa11yci file so that they will be tested with our automated accessibility testing +- [ ] Checked keyboard navigability +- [ ] Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI) +- [ ] Add at least 1 designer as PR reviewer + +### As a code reviewer, I have + +#### Reviewed, tested, and left feedback about the changes + +- [ ] Pulled this branch locally and tested it +- [ ] Reviewed this code and left comments +- [ ] Checked that all code is adequately covered by tests +- [ ] Made it clear which comments need to be addressed before this work is merged +- [ ] If any model was updated to modify/add/delete columns, makemigrations was ran and the assoicated migrations file has been commited. + +#### Ensured code standards are met (Code reviewer) + +- [ ] All new functions and methods are commented using plain language +- [ ] Interactions with external systems are wrapped in try/except +- [ ] Error handling exists for unusual or missing values +- [ ] (Rarely needed) Did dependency updates in Pipfile also get changed in requirements.txt? + +#### Validated user-facing changes as a developer + +- [ ] New pages have been added to .pa11yci file so that they will be tested with our automated accessibility testing +- [ ] Checked keyboard navigability +- [ ] Meets all designs and user flows provided by design/product +- [ ] Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI) + +- [ ] Tested with multiple browsers, the suggestion is to use ones that the developer didn't (check off which ones were used) + - [ ] Chrome + - [ ] Microsoft Edge + - [ ] FireFox + - [ ] Safari + +- [ ] (Rarely needed) Tested as both an analyst and applicant user + +**Note:** Multiple code reviewers can share the checklists above, a second reviewers should not make a duplicate checklist + +### As a designer reviewer, I have + +#### Verified that the changes match the design intention + +- [ ] Checked that the design translated visually +- [ ] Checked behavior +- [ ] Checked different states (empty, one, some, error) +- [ ] Checked for landmarks, page heading structure, and links +- [ ] Tried to break the intended flow + +#### Validated user-facing changes as a designer + +- [ ] Checked keyboard navigability +- [ ] Tested general usability, landmarks, page header structure, and links with a screen reader (such as Voiceover or ANDI) + +- [ ] Tested with multiple browsers (check off which ones were used) + - [ ] Chrome + - [ ] Microsoft Edge + - [ ] FireFox + - [ ] Safari + +- [ ] (Rarely needed) Tested as both an analyst and applicant user + +## Screenshots + + diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index d745f76c7..ab15c660f 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -9,6 +9,22 @@ There are a handful of things we do not commit to the repository: - Compliance documentation that includes IP addresses - Secrets of any kind +## Branch naming convention + +For developers, you can auto-deploy your code to your sandbox (if applicable) by naming your branch thusly: jsd/123-feature-description +Where 'jsd' stands for your initials and sandbox environment name (if you were called John Smith Doe), and 123 matches the ticket number if applicable. + +## Approvals + +When a code change is made that is not user facing, then the following is required: +- a developer approves the PR + +When a code change is made that is user facing, beyond content updates, then the following are required: +- a developer approves the PR +- a designer approves the PR or checks off all relevant items in this checklist + +Content or document updates require a single person to approve. + ## Project Management We use [Github Projects](https://docs.github.com/en/issues/planning-and-tracking-with-projects/learning-about-projects/about-projects) for project management and tracking. diff --git a/docs/architecture/decisions/0021-django-admin.md b/docs/architecture/decisions/0021-django-admin.md index 6e9580932..add6992cd 100644 --- a/docs/architecture/decisions/0021-django-admin.md +++ b/docs/architecture/decisions/0021-django-admin.md @@ -34,6 +34,13 @@ In contrast to building an admin interface from scratch where development activi involve _building up_, leveraging Django Admin will require carefully _pairing back_ the functionalities available to users such as analysts. +On accessibility: Django admin is almost fully accessible out-of-the-box, the exceptions being tables, checkboxes, and +color contrast. We have remedied the first 2 with template overrides and the 3rd with theming (see below). + +On USWDS and theming: Django admin brings its own high level design framework. We have determined that theming on top of Django (scss) +is easy and worthwhile, while overwriting Django's templates with USWDS is hard and provides little return on investment +([research PR](https://github.com/cisagov/getgov/pull/831)). + While we anticipate that Django Admin will meet (or even exceed) the user needs that we are aware of today, it is still an open question whether Django Admin will be the long-term administrator tool of choice. A pivot away from Django Admin in the future would of course mean starting from scratch at a later date, and potentially juggling two separate admin diff --git a/docs/developer/README.md b/docs/developer/README.md index b6938298c..de97b6107 100644 --- a/docs/developer/README.md +++ b/docs/developer/README.md @@ -18,9 +18,19 @@ If you're new to Django, see [Getting Started with Django](https://www.djangopro Visit the running application at [http://localhost:8080](http://localhost:8080). -Note: If you are using Windows, you may need to change your [line endings](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings). If not, you may not be able to run manage.py. + +### Troubleshooting + +* If you are using Windows, you may need to change your [line endings](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings). If not, you may not be able to run manage.py. * Unix based operating systems (like macOS or Linux) handle line separators [differently than Windows does](https://superuser.com/questions/374028/how-are-n-and-r-handled-differently-on-linux-and-windows). This can break bash scripts in particular. In the case of manage.py, it uses *#!/usr/bin/env python* to access the Python executable. Since the script is still thinking in terms of unix line seperators, it may look for the executable *python\r* rather than *python* (since Windows cannot read the carriage return on its own) - thus leading to the error `usr/bin/env: 'python\r' no such file or directory` * If you'd rather not change this globally, add a `.gitattributes` file in the project root with `* text eol=lf` as the text content, and [refresh the repo](https://docs.github.com/en/get-started/getting-started-with-git/configuring-git-to-handle-line-endings#refreshing-a-repository-after-changing-line-endings) +* If you are using a Mac with a M1 chip, and see this error `The chromium binary is not available for arm64.` or an error involving `puppeteer`, try adding this line below into your `.bashrc` or `.zshrc`. + +``` +export DOCKER_DEFAULT_PLATFORM=linux/amd64 +``` + +When completed, don't forget to rerun `docker-compose up`! ## Branch Conventions @@ -84,6 +94,7 @@ The endpoint /admin can be used to view and manage site content, including but n ``` 5. In the browser, navigate to /admin. To verify that all is working correctly, under "domain applications" you should see fake domains with various fake statuses. +6. Add an optional email key/value pair ### Adding an Analyst to /admin Analysts are a variant of the admin role with limited permissions. The process for adding an Analyst is much the same as adding an admin: @@ -105,6 +116,7 @@ Analysts are a variant of the admin role with limited permissions. The process f ``` 5. In the browser, navigate to /admin. To verify that all is working correctly, verify that you can only see a sub-section of the modules and some are set to view-only. +6. Add an optional email key/value pair Do note that if you wish to have both an analyst and admin account, append `-Analyst` to your first and last name, or use a completely different first/last name to avoid confusion. Example: `Bob-Analyst` ## Adding to CODEOWNERS (optional) diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 0fa019a13..e38393a5a 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -277,22 +277,27 @@ class DomainApplicationAdmin(ListHeaderAdmin): pass elif obj.status == models.DomainApplication.SUBMITTED: # This is an fsm in model which will throw an error if the - # transition condition is violated, so we call it on the - # original object which has the right status value, and pass - # the updated object which contains the up-to-date data - # for the side effects (like an email send). Same - # comment applies to original_obj method calls below. - original_obj.submit(updated_domain_application=obj) + # transition condition is violated, so we roll back the + # status to what it was before the admin user changed it and + # let the fsm method set it. Same comment applies to + # transition method calls below. + obj.status = original_obj.status + obj.submit() elif obj.status == models.DomainApplication.IN_REVIEW: - original_obj.in_review(updated_domain_application=obj) + obj.status = original_obj.status + obj.in_review() elif obj.status == models.DomainApplication.ACTION_NEEDED: - original_obj.action_needed(updated_domain_application=obj) + obj.status = original_obj.status + obj.action_needed() elif obj.status == models.DomainApplication.APPROVED: - original_obj.approve(updated_domain_application=obj) + obj.status = original_obj.status + obj.approve() elif obj.status == models.DomainApplication.WITHDRAWN: - original_obj.withdraw() + obj.status = original_obj.status + obj.withdraw() elif obj.status == models.DomainApplication.REJECTED: - original_obj.reject(updated_domain_application=obj) + obj.status = original_obj.status + obj.reject() else: logger.warning("Unknown status selected in django admin") diff --git a/src/registrar/assets/sass/_theme/_admin.scss b/src/registrar/assets/sass/_theme/_admin.scss index 4488ed398..b87257344 100644 --- a/src/registrar/assets/sass/_theme/_admin.scss +++ b/src/registrar/assets/sass/_theme/_admin.scss @@ -105,19 +105,29 @@ html[data-theme="light"] { } // Dark mode django (bug due to scss cascade) and USWDS tables - body, .change-list .usa-table, - .change-list .usa-table--striped tbody tr:nth-child(odd) td { - color: var(--body-fg)!important; + .change-list .usa-table--striped tbody tr:nth-child(odd) td, + .change-list .usa-table--borderless thead th, + .change-list .usa-table thead td, + .change-list .usa-table thead th, + body.dashboard, + body.change-list, + body.change-form { + color: var(--body-fg); } } // Firefox needs this to be specifically set html[data-theme="dark"] { - body, .change-list .usa-table, - .change-list .usa-table--striped tbody tr:nth-child(odd) td { - color: var(--body-fg)!important; + .change-list .usa-table--striped tbody tr:nth-child(odd) td, + .change-list .usa-table--borderless thead th, + .change-list .usa-table thead td, + .change-list .usa-table thead th, + body.dashboard, + body.change-list, + body.change-form { + color: var(--body-fg); } } diff --git a/src/registrar/config/urls.py b/src/registrar/config/urls.py index c21d0206c..0f136c932 100644 --- a/src/registrar/config/urls.py +++ b/src/registrar/config/urls.py @@ -4,7 +4,6 @@ For more information see: https://docs.djangoproject.com/en/4.0/topics/http/urls/ """ -from django.conf import settings from django.contrib import admin from django.urls import include, path from django.views.generic import RedirectView @@ -45,6 +44,10 @@ for step, view in [ urlpatterns = [ path("", views.index, name="home"), + path( + "admin/logout/", + RedirectView.as_view(pattern_name="logout", permanent=False), + ), path("admin/", admin.site.urls), path( "application//edit/", @@ -114,20 +117,6 @@ urlpatterns = [ ), ] - -if not settings.DEBUG: - urlpatterns += [ - # redirect to login.gov - path( - "admin/login/", RedirectView.as_view(pattern_name="login", permanent=False) - ), - # redirect to login.gov - path( - "admin/logout/", - RedirectView.as_view(pattern_name="logout", permanent=False), - ), - ] - # we normally would guard these with `if settings.DEBUG` but tests run with # DEBUG = False even when these apps have been loaded because settings.DEBUG # was actually True. Instead, let's add these URLs any time we are able to diff --git a/src/registrar/fixtures.py b/src/registrar/fixtures.py index 01de666a4..0b1b8926d 100644 --- a/src/registrar/fixtures.py +++ b/src/registrar/fixtures.py @@ -67,6 +67,11 @@ class UserFixture: "first_name": "Paul", "last_name": "Kuykendall", }, + { + "username": "2a88a97b-be96-4aad-b99e-0b605b492c78", + "first_name": "Rebecca", + "last_name": "Hsieh", + }, ] STAFF = [ @@ -74,6 +79,7 @@ class UserFixture: "username": "319c490d-453b-43d9-bc4d-7d6cd8ff6844", "first_name": "Rachid-Analyst", "last_name": "Mrad-Analyst", + "email": "rachid.mrad@gmail.com", }, { "username": "b6a15987-5c88-4e26-8de2-ca71a0bdb2cd", @@ -90,6 +96,11 @@ class UserFixture: "first_name": "Paul-Analyst", "last_name": "Kuykendall-Analyst", }, + { + "username": "e474e7a9-71ca-449d-833c-8a6e094dd117", + "first_name": "Rebecca-Analyst", + "last_name": "Hsieh-Analyst", + }, ] STAFF_PERMISSIONS = [ @@ -119,6 +130,8 @@ class UserFixture: user.is_superuser = True user.first_name = admin["first_name"] user.last_name = admin["last_name"] + if "email" in admin.keys(): + user.email = admin["email"] user.is_staff = True user.is_active = True user.save() @@ -136,6 +149,8 @@ class UserFixture: user.is_superuser = False user.first_name = staff["first_name"] user.last_name = staff["last_name"] + if "email" in admin.keys(): + user.email = admin["email"] user.is_staff = True user.is_active = True diff --git a/src/registrar/models/domain_application.py b/src/registrar/models/domain_application.py index 1f3d23d8c..67f1ee5d9 100644 --- a/src/registrar/models/domain_application.py +++ b/src/registrar/models/domain_application.py @@ -504,15 +504,10 @@ class DomainApplication(TimeStampedModel): @transition( field="status", source=[STARTED, ACTION_NEEDED, WITHDRAWN], target=SUBMITTED ) - def submit(self, updated_domain_application=None): + def submit(self): """Submit an application that is started. - As a side effect, an email notification is sent. - - This method is called in admin.py on the original application - which has the correct status value, but is passed the changed - application which has the up-to-date data that we'll use - in the email.""" + As a side effect, an email notification is sent.""" # check our conditions here inside the `submit` method so that we # can raise more informative exceptions @@ -528,46 +523,31 @@ class DomainApplication(TimeStampedModel): if not DraftDomain.string_could_be_domain(self.requested_domain.name): raise ValueError("Requested domain is not a valid domain name.") - if updated_domain_application is not None: - # A DomainApplication is being passed to this method (ie from admin) - updated_domain_application._send_status_update_email( - "submission confirmation", - "emails/submission_confirmation.txt", - "emails/submission_confirmation_subject.txt", - ) - else: - # Or this method is called with the right application - # for context, ie from views/application.py - self._send_status_update_email( - "submission confirmation", - "emails/submission_confirmation.txt", - "emails/submission_confirmation_subject.txt", - ) + self._send_status_update_email( + "submission confirmation", + "emails/submission_confirmation.txt", + "emails/submission_confirmation_subject.txt", + ) @transition(field="status", source=SUBMITTED, target=IN_REVIEW) - def in_review(self, updated_domain_application): + def in_review(self): """Investigate an application that has been submitted. - As a side effect, an email notification is sent. + As a side effect, an email notification is sent.""" - This method is called in admin.py on the original application - which has the correct status value, but is passed the changed - application which has the up-to-date data that we'll use - in the email.""" - - updated_domain_application._send_status_update_email( + self._send_status_update_email( "application in review", "emails/status_change_in_review.txt", "emails/status_change_in_review_subject.txt", ) @transition(field="status", source=[IN_REVIEW, REJECTED], target=ACTION_NEEDED) - def action_needed(self, updated_domain_application): + def action_needed(self): """Send back an application that is under investigation or rejected. - As a side effect, an email notification is sent, similar to in_review""" + As a side effect, an email notification is sent.""" - updated_domain_application._send_status_update_email( + self._send_status_update_email( "action needed", "emails/status_change_action_needed.txt", "emails/status_change_action_needed_subject.txt", @@ -576,19 +556,13 @@ class DomainApplication(TimeStampedModel): @transition( field="status", source=[SUBMITTED, IN_REVIEW, REJECTED], target=APPROVED ) - def approve(self, updated_domain_application=None): + def approve(self): """Approve an application that has been submitted. This has substantial side-effects because it creates another database object for the approved Domain and makes the user who created the application into an admin on that domain. It also triggers an email - notification. - - This method is called in admin.py on the original application - which has the correct status value, but is passed the changed - application which has the up-to-date data that we'll use - in the email. - """ + notification.""" # create the domain Domain = apps.get_model("registrar.Domain") @@ -607,31 +581,23 @@ class DomainApplication(TimeStampedModel): user=self.creator, domain=created_domain, role=UserDomainRole.Roles.ADMIN ) - if updated_domain_application is not None: - # A DomainApplication is being passed to this method (ie from admin) - updated_domain_application._send_status_update_email( - "application approved", - "emails/status_change_approved.txt", - "emails/status_change_approved_subject.txt", - ) - else: - self._send_status_update_email( - "application approved", - "emails/status_change_approved.txt", - "emails/status_change_approved_subject.txt", - ) + self._send_status_update_email( + "application approved", + "emails/status_change_approved.txt", + "emails/status_change_approved_subject.txt", + ) @transition(field="status", source=[SUBMITTED, IN_REVIEW], target=WITHDRAWN) def withdraw(self): """Withdraw an application that has been submitted.""" @transition(field="status", source=[IN_REVIEW, APPROVED], target=REJECTED) - def reject(self, updated_domain_application): + def reject(self): """Reject an application that has been submitted. As a side effect, an email notification is sent, similar to in_review""" - updated_domain_application._send_status_update_email( + self._send_status_update_email( "action needed", "emails/status_change_rejected.txt", "emails/status_change_rejected_subject.txt", diff --git a/src/registrar/templates/admin/base_site.html b/src/registrar/templates/admin/base_site.html index 9be44e43f..6b641722f 100644 --- a/src/registrar/templates/admin/base_site.html +++ b/src/registrar/templates/admin/base_site.html @@ -1,5 +1,6 @@ {% extends "admin/base.html" %} {% load static %} +{% load i18n %} {% block title %}{% if subtitle %}{{ subtitle }} | {% endif %}{{ title }} | {{ site_title|default:_('Django site admin') }}{% endblock %} @@ -13,5 +14,25 @@ {% include "admin/color_theme_toggle.html" %} {% endif %} {% endblock %} - +{% comment %} + This was copied from the 'userlinks' template, with a few minor changes. + You can find that here: + https://github.com/django/django/blob/d25f3892114466d689fd6936f79f3bd9a9acc30e/django/contrib/admin/templates/admin/base.html#L59 +{% endcomment %} +{% block userlinks %} + {% if site_url %} + {% translate 'View site' %} / + {% endif %} + {% if user.is_active and user.is_staff %} + {% url 'django-admindocs-docroot' as docsroot %} + {% if docsroot %} + {% translate 'Documentation' %} / + {% endif %} + {% endif %} + {% if user.has_usable_password %} + {% translate 'Change password' %} / + {% endif %} + {% translate 'Log out' %} + {% include "admin/color_theme_toggle.html" %} + {% endblock %} {% block nav-global %}{% endblock %} \ No newline at end of file diff --git a/src/registrar/templates/admin/change_list_results.html b/src/registrar/templates/admin/change_list_results.html index a9c5e5b4d..9ee3f9f59 100644 --- a/src/registrar/templates/admin/change_list_results.html +++ b/src/registrar/templates/admin/change_list_results.html @@ -17,53 +17,45 @@ Load our custom filters to extract info from the django generated markup. -{# .gov - hardcode the select all checkbox #} - -
- - - - -
-
- -{# .gov - don't let django generate the select all checkbox #} -{% for header in result_headers|slice:"1:" %} +{% if results.0.form %} + {# .gov - hardcode the select all checkbox #} + +
+ + + + +
+
+ + {# .gov - don't let django generate the select all checkbox #} + {% for header in result_headers|slice:"1:" %} + + {% if header.sortable %} + {% if header.sort_priority > 0 %} +
+ + {% if num_sorted_fields > 1 %}{{ header.sort_priority }}{% endif %} + +
+ {% endif %} + {% endif %} +
{% if header.sortable %}{{ header.text|capfirst }}{% else %}{{ header.text|capfirst }}{% endif %}
+
+ {% endfor %} - - {% if header.sortable %} - {% if header.sort_priority > 0 %} -
- - {% if num_sorted_fields > 1 %}{{ header.sort_priority }}{% endif %} - -
- {% endif %} - {% endif %} -
{% if header.sortable %}{{ header.text|capfirst }}{% else %}{{ header.text|capfirst }}{% endif %}
-
-{% endfor %} + + + - - - + {% comment %} + .gov - hardcode the row checkboxes using the custom filters to extract + the value attribute's value, and a label based on the anchor elements's + text. Then edit the for loop to keep django from generating the row select + checkboxes. + {% endcomment %} -{% comment %} -{% for result in results %} -{% if result.form.non_field_errors %} - {{ result.form.non_field_errors }} -{% endif %} -{% for item in result %}{{ item }}{% endfor %} -{% endfor %} -{% endcomment %} - -{% comment %} -.gov - hardcode the row checkboxes using the custom filters to extract -the value attribute's value, and a label based on the anchor elements's -text. Then edit the for loop to keep django from generating the row select -checkboxes. -{% endcomment %} -{% for result in results %} + {% for result in results %} {% if result.form.non_field_errors %} {{ result.form.non_field_errors }} {% endif %} @@ -82,7 +74,37 @@ checkboxes. {{ item }} {% endfor %} -{% endfor %} + {% endfor %} + +{% else %} {# results doesn't have a form as its first element #} + + {% for header in result_headers %} + + {% if header.sortable %} + {% if header.sort_priority > 0 %} +
+ + {% if num_sorted_fields > 1 %}{{ header.sort_priority }}{% endif %} + +
+ {% endif %} + {% endif %} +
{% if header.sortable %}{{ header.text|capfirst }}{% else %}{{ header.text|capfirst }}{% endif %}
+
+ {% endfor %} + + + + + + {% for result in results %} + {% if result.form.non_field_errors %} + {{ result.form.non_field_errors }} + {% endif %} + {% for item in result %}{{ item }}{% endfor %} + {% endfor %} + +{% endif %} diff --git a/src/registrar/templates/application_authorizing_official.html b/src/registrar/templates/application_authorizing_official.html index dead1974f..2ac99be80 100644 --- a/src/registrar/templates/application_authorizing_official.html +++ b/src/registrar/templates/application_authorizing_official.html @@ -6,13 +6,13 @@ Who is the authorizing official for your organization? -

Your authorizing official is the person within your organization who can authorize your domain request. This is generally the highest-ranking or highest-elected official in your organization.

+

Your authorizing official is the person within your organization who can authorize your domain request. This person must be in a role of significant, executive responsibility within the organization.

{% include "includes/ao_example.html" %}
-

We might contact your authorizing official, or their office, to double check that they approve this request. Read more about who can serve as an authorizing official.

+

We typically don’t reach out to the authorizing official, but if contact is necessary, our practice is to coordinate first with you, the requestor. Read more about who can serve as an authorizing official.

{% endblock %} diff --git a/src/registrar/templates/application_other_contacts.html b/src/registrar/templates/application_other_contacts.html index 805cb6927..679742281 100644 --- a/src/registrar/templates/application_other_contacts.html +++ b/src/registrar/templates/application_other_contacts.html @@ -2,7 +2,13 @@ {% load static field_helpers %} {% block form_instructions %} -

We’d like to contact other employees in your organization about your domain request. For example, they could be involved in managing your organization or its technical infrastructure. This information will help us assess your eligibility for a .gov domain. These contacts should be in addition to you and your authorizing official. They should be employees of your organization.

+

To help us assess your eligibility for a .gov domain, please provide contact information for other employees from your organization. +

+

{% endblock %} diff --git a/src/registrar/templates/application_status.html b/src/registrar/templates/application_status.html index 2488bb449..99f6a1d4c 100644 --- a/src/registrar/templates/application_status.html +++ b/src/registrar/templates/application_status.html @@ -22,7 +22,7 @@ {% if domainapplication.status == 'approved' %} Approved {% elif domainapplication.status == 'in review' %} In Review {% elif domainapplication.status == 'rejected' %} Rejected - {% elif domainapplication.status == 'submitted' %} Received + {% elif domainapplication.status == 'submitted' %} Submitted {% else %}ERROR Please contact technical support/dev {% endif %}

diff --git a/src/registrar/templates/home.html b/src/registrar/templates/home.html index 792beec43..30724de8e 100644 --- a/src/registrar/templates/home.html +++ b/src/registrar/templates/home.html @@ -125,13 +125,14 @@

You don't have any archived domains

-
+ + diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py index 8a288eb15..a27dcb741 100644 --- a/src/registrar/tests/test_admin.py +++ b/src/registrar/tests/test_admin.py @@ -174,6 +174,33 @@ class TestDomainApplicationAdmin(TestCase): # Perform assertions on the mock call itself mock_client_instance.send_email.assert_called_once() + def test_save_model_sets_approved_domain(self): + # make sure there is no user with this email + EMAIL = "mayor@igorville.gov" + User.objects.filter(email=EMAIL).delete() + + # Create a sample application + application = completed_application(status=DomainApplication.IN_REVIEW) + + # Create a mock request + request = self.factory.post( + "/admin/registrar/domainapplication/{}/change/".format(application.pk) + ) + + # Create an instance of the model admin + model_admin = DomainApplicationAdmin(DomainApplication, self.site) + + # Modify the application's property + application.status = DomainApplication.APPROVED + + # Use the model admin's save_model method + model_admin.save_model(request, application, form=None, change=True) + + # Test that approved domain exists and equals requested domain + self.assertEqual( + application.requested_domain.name, application.approved_domain.name + ) + @boto3_mocking.patching def test_save_model_sends_action_needed_email(self): # make sure there is no user with this email diff --git a/src/requirements.txt b/src/requirements.txt index ca3877529..52ded59fc 100644 --- a/src/requirements.txt +++ b/src/requirements.txt @@ -7,7 +7,7 @@ certifi==2023.7.22 ; python_version >= '3.6' cfenv==0.5.3 cffi==1.15.1 charset-normalizer==3.1.0 ; python_full_version >= '3.7.0' -cryptography==41.0.2 ; python_version >= '3.7' +cryptography==41.0.3 ; 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' dj-database-url==2.0.0 dj-email-url==1.0.6 diff --git a/src/zap.conf b/src/zap.conf index e5e7b4d04..bdd6b017d 100644 --- a/src/zap.conf +++ b/src/zap.conf @@ -31,6 +31,8 @@ 10027 OUTOFSCOPE http://app:8080/public/js/uswds-init.min.js # get-gov.js contains suspicious word "from" as in `Array.from()` 10027 OUTOFSCOPE http://app:8080/public/js/get-gov.js +# Ignore wording of "TODO" +10027 OUTOFSCOPE http://app:8080.*$ 10028 FAIL (Open Redirect - Passive/beta) 10029 FAIL (Cookie Poisoning - Passive/beta) 10030 FAIL (User Controllable Charset - Passive/beta)