From 17274a606d7b3a8bb44d34934fd53491e53267e4 Mon Sep 17 00:00:00 2001
From: Erin <121973038+erinysong@users.noreply.github.com>
Date: Wed, 17 Jul 2024 14:09:50 -0700
Subject: [PATCH 01/34] Removed unused comment job from manual deploy
---
.github/workflows/deploy-sandbox.yaml | 18 +-----------------
1 file changed, 1 insertion(+), 17 deletions(-)
diff --git a/.github/workflows/deploy-sandbox.yaml b/.github/workflows/deploy-sandbox.yaml
index 4bd7f99dd..7f8637a04 100644
--- a/.github/workflows/deploy-sandbox.yaml
+++ b/.github/workflows/deploy-sandbox.yaml
@@ -64,20 +64,4 @@ jobs:
cf_password: ${{ secrets[env.CF_PASSWORD] }}
cf_org: cisa-dotgov
cf_space: ${{ env.ENVIRONMENT }}
- cf_manifest: ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml
- comment:
- runs-on: ubuntu-latest
- needs: [variables, deploy]
- steps:
- - uses: actions/github-script@v6
- env:
- ENVIRONMENT: ${{ needs.variables.outputs.environment }}
- with:
- github-token: ${{secrets.GITHUB_TOKEN}}
- script: |
- github.rest.issues.createComment({
- issue_number: context.issue.number,
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: 'š„³ Successfully deployed to developer sandbox **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.'
- })
\ No newline at end of file
+ cf_manifest: ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml
\ No newline at end of file
From f2fd764d6735c4a8bc177c5466ba6cfea6cf668c Mon Sep 17 00:00:00 2001
From: Erin <121973038+erinysong@users.noreply.github.com>
Date: Wed, 17 Jul 2024 14:20:23 -0700
Subject: [PATCH 02/34] Correct removed comment job in deploy workflow
---
...anch-to-sandbox.yaml => deploy-manual.yaml} | 16 ----------------
.github/workflows/deploy-sandbox.yaml | 18 +++++++++++++++++-
2 files changed, 17 insertions(+), 17 deletions(-)
rename .github/workflows/{deploy-branch-to-sandbox.yaml => deploy-manual.yaml} (78%)
diff --git a/.github/workflows/deploy-branch-to-sandbox.yaml b/.github/workflows/deploy-manual.yaml
similarity index 78%
rename from .github/workflows/deploy-branch-to-sandbox.yaml
rename to .github/workflows/deploy-manual.yaml
index 14a3d8ef8..97415a0d9 100644
--- a/.github/workflows/deploy-branch-to-sandbox.yaml
+++ b/.github/workflows/deploy-manual.yaml
@@ -71,20 +71,4 @@ jobs:
cf_org: cisa-dotgov
cf_space: ${{ env.ENVIRONMENT }}
cf_manifest: ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml
- comment:
- runs-on: ubuntu-latest
- needs: [deploy]
- steps:
- - uses: actions/github-script@v6
- env:
- ENVIRONMENT: ${{ github.event.inputs.environment }}
- with:
- github-token: ${{secrets.GITHUB_TOKEN}}
- script: |
- github.rest.issues.createComment({
- owner: context.repo.owner,
- repo: context.repo.repo,
- body: 'š„³ Successfully deployed to developer sandbox **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.'
- })
-
diff --git a/.github/workflows/deploy-sandbox.yaml b/.github/workflows/deploy-sandbox.yaml
index 7f8637a04..4bd7f99dd 100644
--- a/.github/workflows/deploy-sandbox.yaml
+++ b/.github/workflows/deploy-sandbox.yaml
@@ -64,4 +64,20 @@ jobs:
cf_password: ${{ secrets[env.CF_PASSWORD] }}
cf_org: cisa-dotgov
cf_space: ${{ env.ENVIRONMENT }}
- cf_manifest: ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml
\ No newline at end of file
+ cf_manifest: ops/manifests/manifest-${{ env.ENVIRONMENT }}.yaml
+ comment:
+ runs-on: ubuntu-latest
+ needs: [variables, deploy]
+ steps:
+ - uses: actions/github-script@v6
+ env:
+ ENVIRONMENT: ${{ needs.variables.outputs.environment }}
+ with:
+ github-token: ${{secrets.GITHUB_TOKEN}}
+ script: |
+ github.rest.issues.createComment({
+ issue_number: context.issue.number,
+ owner: context.repo.owner,
+ repo: context.repo.repo,
+ body: 'š„³ Successfully deployed to developer sandbox **[${{ env.ENVIRONMENT }}](https://getgov-${{ env.ENVIRONMENT }}.app.cloud.gov/)**.'
+ })
\ No newline at end of file
From 7820c362433d714c1e47a9aa0de7ad75dcd1967b Mon Sep 17 00:00:00 2001
From: Erin <121973038+erinysong@users.noreply.github.com>
Date: Wed, 17 Jul 2024 14:21:55 -0700
Subject: [PATCH 03/34] Revert workflow name for testing purposes
---
.../{deploy-manual.yaml => deploy-branch-to-sandbox.yaml} | 0
1 file changed, 0 insertions(+), 0 deletions(-)
rename .github/workflows/{deploy-manual.yaml => deploy-branch-to-sandbox.yaml} (100%)
diff --git a/.github/workflows/deploy-manual.yaml b/.github/workflows/deploy-branch-to-sandbox.yaml
similarity index 100%
rename from .github/workflows/deploy-manual.yaml
rename to .github/workflows/deploy-branch-to-sandbox.yaml
From 3e5401a549d0fc4b8abb756730482a1d6e23dbc3 Mon Sep 17 00:00:00 2001
From: Erin <121973038+erinysong@users.noreply.github.com>
Date: Mon, 22 Jul 2024 11:31:20 -0700
Subject: [PATCH 04/34] Add new sandboxes to deploy-manual workflow. Rename
workflow name to deploy-manual
---
.../{deploy-branch-to-sandbox.yaml => deploy-manual.yaml} | 0
ops/scripts/create_dev_sandbox.sh | 6 +++++-
2 files changed, 5 insertions(+), 1 deletion(-)
rename .github/workflows/{deploy-branch-to-sandbox.yaml => deploy-manual.yaml} (100%)
diff --git a/.github/workflows/deploy-branch-to-sandbox.yaml b/.github/workflows/deploy-manual.yaml
similarity index 100%
rename from .github/workflows/deploy-branch-to-sandbox.yaml
rename to .github/workflows/deploy-manual.yaml
diff --git a/ops/scripts/create_dev_sandbox.sh b/ops/scripts/create_dev_sandbox.sh
index 676fcf7ae..b3a970584 100755
--- a/ops/scripts/create_dev_sandbox.sh
+++ b/ops/scripts/create_dev_sandbox.sh
@@ -112,10 +112,14 @@ sed -i '' '/ - development/ {a\
- '"$1"'
}' .github/workflows/reset-db.yaml
-sed -i '' '/ - development/ {a\
+sed -i '' '/ - backup/ {a\
- '"$1"'
}' .github/workflows/migrate.yaml
+sed -i '' '/ - development/ {a\
+ - '"$1"'
+}' .github/workflows/deploy-manual.yaml
+
sed -i '' '/${{startsWith(github.head_ref, / {a\
|| startsWith(github.head_ref, '"'$1'"')
}' .github/workflows/deploy-sandbox.yaml
From 05d86ad11caf9bc5776e8af8e28112f3c0d79cc6 Mon Sep 17 00:00:00 2001
From: Matthew Spence
Date: Mon, 22 Jul 2024 15:37:25 -0500
Subject: [PATCH 05/34] Link to new FSM diagram in developer README
---
docs/developer/README.md | 5 ++++-
1 file changed, 4 insertions(+), 1 deletion(-)
diff --git a/docs/developer/README.md b/docs/developer/README.md
index f63f01938..e978ab666 100644
--- a/docs/developer/README.md
+++ b/docs/developer/README.md
@@ -357,4 +357,7 @@ Then, copy the variables under the section labled `s3`.
1. On the app, navigate to `\admin`.
2. Under models, click `Waffle flags`.
3. Click the `disable_email_sending` record. This should exist by default, if not - create one with that name.
-4. (Important) Set the field `everyone` to `Yes`. This field overrides all other settings
\ No newline at end of file
+4. (Important) Set the field `everyone` to `Yes`. This field overrides all other settings
+
+## Request Flow FSM Diagram
+There is a diagram detailing the flow of domain requests and resulting domain objects [here](https://miro.com/app/board/uXjVMuqbLOk=/?moveToWidget=3458764594819017396&cot=14)
\ No newline at end of file
From 427094edca500c210e9e943b6d0404846ba10c50 Mon Sep 17 00:00:00 2001
From: matthewswspence
Date: Mon, 29 Jul 2024 11:53:34 -0500
Subject: [PATCH 06/34] add another cert format and a cert folder to .gitignore
---
.gitignore | 2 ++
1 file changed, 2 insertions(+)
diff --git a/.gitignore b/.gitignore
index ddd75475d..f2d82f599 100644
--- a/.gitignore
+++ b/.gitignore
@@ -7,8 +7,10 @@ docs/research/data/**
public/
credentials*
+src/certs/
*.pem
*.crt
+*.cer
*.bk
From ee18be87c7ed8e64277046713cf88447e7003f55 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Tue, 30 Jul 2024 11:39:48 -0400
Subject: [PATCH 07/34] use css for read only styles
---
src/registrar/assets/sass/_theme/_forms.scss | 10 +++
...rtfolio_additional_permissions_and_more.py | 52 ++++++++++++
src/registrar/models/user.py | 17 ++--
.../includes/finish_profile_form.html | 8 +-
.../templates/includes/input_read_only.html | 7 ++
.../templates/includes/input_with_errors.html | 8 +-
...donly_input.html => toggleable_input.html} | 0
...edit_button.html => toggleable_label.html} | 0
.../templates/portfolio_organization.html | 78 ++++++++++--------
src/registrar/templatetags/field_helpers.py | 4 +-
src/registrar/tests/test_views_portfolio.py | 80 ++++++++++---------
src/registrar/views/portfolios.py | 3 +
12 files changed, 179 insertions(+), 88 deletions(-)
create mode 100644 src/registrar/migrations/0114_alter_user_portfolio_additional_permissions_and_more.py
create mode 100644 src/registrar/templates/includes/input_read_only.html
rename src/registrar/templates/includes/{readonly_input.html => toggleable_input.html} (100%)
rename src/registrar/templates/includes/{label_with_edit_button.html => toggleable_label.html} (100%)
diff --git a/src/registrar/assets/sass/_theme/_forms.scss b/src/registrar/assets/sass/_theme/_forms.scss
index c025bdb29..0aedfcdba 100644
--- a/src/registrar/assets/sass/_theme/_forms.scss
+++ b/src/registrar/assets/sass/_theme/_forms.scss
@@ -82,3 +82,13 @@ legend.float-left-tablet + button.float-right-tablet {
color: var(--close-button-hover-bg);
}
}
+
+.read-only-label {
+ font-size: size('body', 'sm');
+ color: color('primary');
+ margin-bottom: units(0.5);
+}
+
+.read-only-value {
+ margin-top: units(0);
+}
diff --git a/src/registrar/migrations/0114_alter_user_portfolio_additional_permissions_and_more.py b/src/registrar/migrations/0114_alter_user_portfolio_additional_permissions_and_more.py
new file mode 100644
index 000000000..f70c5388c
--- /dev/null
+++ b/src/registrar/migrations/0114_alter_user_portfolio_additional_permissions_and_more.py
@@ -0,0 +1,52 @@
+# Generated by Django 4.2.10 on 2024-07-30 02:51
+
+import django.contrib.postgres.fields
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ("registrar", "0113_user_portfolio_user_portfolio_additional_permissions_and_more"),
+ ]
+
+ operations = [
+ migrations.AlterField(
+ model_name="user",
+ name="portfolio_additional_permissions",
+ field=django.contrib.postgres.fields.ArrayField(
+ base_field=models.CharField(
+ choices=[
+ ("view_all_domains", "View all domains and domain reports"),
+ ("view_managed_domains", "View managed domains"),
+ ("edit_domains", "User is a manager on a domain"),
+ ("view_member", "View members"),
+ ("edit_member", "Create and edit members"),
+ ("view_all_requests", "View all requests"),
+ ("view_created_requests", "View created requests"),
+ ("edit_requests", "Create and edit requests"),
+ ("edit_portfolio", "Edit organization"),
+ ],
+ max_length=50,
+ ),
+ blank=True,
+ help_text="Select one or more additional permissions.",
+ null=True,
+ size=None,
+ ),
+ ),
+ migrations.AlterField(
+ model_name="user",
+ name="portfolio_roles",
+ field=django.contrib.postgres.fields.ArrayField(
+ base_field=models.CharField(
+ choices=[("organization_admin", "Admin"), ("organization_admin_read_only", "Admin read only")],
+ max_length=50,
+ ),
+ blank=True,
+ help_text="Select one or more roles.",
+ null=True,
+ size=None,
+ ),
+ ),
+ ]
diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py
index b135e30c7..dd826bc11 100644
--- a/src/registrar/models/user.py
+++ b/src/registrar/models/user.py
@@ -69,7 +69,7 @@ class User(AbstractUser):
ORGANIZATION_ADMIN = "organization_admin", "Admin"
ORGANIZATION_ADMIN_READ_ONLY = "organization_admin_read_only", "Admin read only"
- ORGANIZATION_MEMBER = "organization_member", "Member"
+ # ORGANIZATION_MEMBER is an abstract role where user.portfolio is true
class UserPortfolioPermissionChoices(models.TextChoices):
""" """
@@ -89,7 +89,7 @@ class User(AbstractUser):
VIEW_CREATED_REQUESTS = "view_created_requests", "View created requests"
EDIT_REQUESTS = "edit_requests", "Create and edit requests"
- VIEW_PORTFOLIO = "view_portfolio", "View organization"
+ # VIEW_PORTFOLIO is an abstract permission that returns true when user.portfolio is true
EDIT_PORTFOLIO = "edit_portfolio", "Edit organization"
PORTFOLIO_ROLE_PERMISSIONS = {
@@ -99,17 +99,12 @@ class User(AbstractUser):
UserPortfolioPermissionChoices.EDIT_MEMBER,
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
UserPortfolioPermissionChoices.EDIT_REQUESTS,
- UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
],
UserPortfolioRoleChoices.ORGANIZATION_ADMIN_READ_ONLY: [
UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
UserPortfolioPermissionChoices.VIEW_MEMBER,
UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
- UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- ],
- UserPortfolioRoleChoices.ORGANIZATION_MEMBER: [
- UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
],
}
@@ -280,10 +275,14 @@ class User(AbstractUser):
return portfolio_permission in portfolio_permissions
- # the methods below are checks for individual portfolio permissions. they are defined here
+ # the methods below are checks for individual portfolio permissions. They are defined here
# to make them easier to call elsewhere throughout the application
def has_base_portfolio_permission(self):
- return self._has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO)
+ """Base role/permission, the user is simply linked to a portfolio"""
+ return self.portfolio is not None
+
+ def has_edit_org_portfolio_permission(self):
+ return self._has_portfolio_permission(User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO)
def has_domains_portfolio_permission(self):
return (
diff --git a/src/registrar/templates/includes/finish_profile_form.html b/src/registrar/templates/includes/finish_profile_form.html
index 88f7a73af..8369511a5 100644
--- a/src/registrar/templates/includes/finish_profile_form.html
+++ b/src/registrar/templates/includes/finish_profile_form.html
@@ -35,7 +35,7 @@
- {% with show_edit_button=True show_readonly=True group_classes="usa-form-editable usa-form-editable--no-border padding-top-2" %}
+ {% with toggleable_input=True toggleable_label=True group_classes="usa-form-editable usa-form-editable--no-border padding-top-2" %}
{% input_with_errors form.full_name %}
{% endwith %}
@@ -54,7 +54,7 @@
{% public_site_url "help/account-management/#get-help-with-login.gov" as login_help_url %}
- {% with show_readonly=True add_class="display-none" group_classes="usa-form-editable usa-form-editable padding-top-2 bold-usa-label" %}
+ {% with toggleable_input=True add_class="display-none" group_classes="usa-form-editable usa-form-editable padding-top-2 bold-usa-label" %}
{% with link_href=login_help_url %}
{% with sublabel_text="We recommend using your work email for your .gov account. If the wrong email is displayed below, youāll need to update your Login.gov account and log back in. Get help with your Login.gov account." %}
{% with link_text="Get help with your Login.gov account" target_blank=True do_not_show_max_chars=True %}
@@ -64,11 +64,11 @@
{% endwith %}
{% endwith %}
- {% with show_edit_button=True show_readonly=True group_classes="usa-form-editable padding-top-2" %}
+ {% with toggleable_input=True toggleable_label=True group_classes="usa-form-editable padding-top-2" %}
{% input_with_errors form.title %}
{% endwith %}
- {% with show_edit_button=True show_readonly=True group_classes="usa-form-editable padding-top-2" %}
+ {% with toggleable_input=True toggleable_label=True group_classes="usa-form-editable padding-top-2" %}
{% with add_class="usa-input--medium" %}
{% input_with_errors form.phone %}
{% endwith %}
diff --git a/src/registrar/templates/includes/input_read_only.html b/src/registrar/templates/includes/input_read_only.html
new file mode 100644
index 000000000..b76f82e8b
--- /dev/null
+++ b/src/registrar/templates/includes/input_read_only.html
@@ -0,0 +1,7 @@
+{% comment %}
+Template include for read-only form fields
+{% endcomment %}
+
+
+
{{ field.label }}
+
{{ field.value }}
diff --git a/src/registrar/templates/includes/input_with_errors.html b/src/registrar/templates/includes/input_with_errors.html
index 623ec0a33..d1e53968e 100644
--- a/src/registrar/templates/includes/input_with_errors.html
+++ b/src/registrar/templates/includes/input_with_errors.html
@@ -27,8 +27,8 @@ error messages, if necessary.
{% endif %}
{% if not field.widget_type == "checkbox" %}
- {% if show_edit_button %}
- {% include "includes/label_with_edit_button.html" with bold_label=True %}
+ {% if toggleable_label %}
+ {% include "includes/toggleable_label.html" with bold_label=True %}
{% else %}
{% include "django/forms/label.html" %}
{% endif %}
@@ -63,8 +63,8 @@ error messages, if necessary.
{% endif %}
- {% if show_readonly %}
- {% include "includes/readonly_input.html" %}
+ {% if toggleable_input %}
+ {% include "includes/toggleable_input.html" %}
{% endif %}
{# this is the input field, itself #}
diff --git a/src/registrar/templates/includes/readonly_input.html b/src/registrar/templates/includes/toggleable_input.html
similarity index 100%
rename from src/registrar/templates/includes/readonly_input.html
rename to src/registrar/templates/includes/toggleable_input.html
diff --git a/src/registrar/templates/includes/label_with_edit_button.html b/src/registrar/templates/includes/toggleable_label.html
similarity index 100%
rename from src/registrar/templates/includes/label_with_edit_button.html
rename to src/registrar/templates/includes/toggleable_label.html
diff --git a/src/registrar/templates/portfolio_organization.html b/src/registrar/templates/portfolio_organization.html
index 0dede3c32..cc9cf5b6a 100644
--- a/src/registrar/templates/portfolio_organization.html
+++ b/src/registrar/templates/portfolio_organization.html
@@ -23,42 +23,56 @@
The name of your federal agency will be publicly listed as the domain registrant.
-
- The federal agency for your organization canāt be updated here.
- To suggest an update, email help@get.gov.
-
-
- {% include "includes/form_errors.html" with form=form %}
-
- {% include "includes/required_fields.html" %}
-
-
+ {% else %}
+
Federal agency
+
+ {{ portfolio }}
+
+ {% if form.address_line1.value is not None %}
+ {% include "includes/input_read_only.html" with field=form.address_line1 %}
+ {% endif %}
+ {% if form.address_line2.value is not None %}
+ {% include "includes/input_read_only.html" with field=form.address_line2 %}
+ {% endif %}
+ {% if form.city.value is not None %}
+ {% include "includes/input_read_only.html" with field=form.city %}
+ {% endif %}
+ {% if form.state_territory.value is not None %}
+ {% include "includes/input_read_only.html" with field=form.state_territory %}
+ {% endif %}
+ {% if form.zipcode.value is not None %}
+ {% include "includes/input_read_only.html" with field=form.zipcode %}
+ {% endif %}
+ {% endif %}
- {% input_with_errors form.address_line2 %}
-
- {% input_with_errors form.city %}
-
- {% input_with_errors form.state_territory %}
-
- {% with add_class="usa-input--small" %}
- {% input_with_errors form.zipcode %}
- {% endwith %}
-
-
-
{% endblock %}
diff --git a/src/registrar/templatetags/field_helpers.py b/src/registrar/templatetags/field_helpers.py
index b72f77e21..68a803711 100644
--- a/src/registrar/templatetags/field_helpers.py
+++ b/src/registrar/templatetags/field_helpers.py
@@ -26,7 +26,7 @@ def input_with_errors(context, field=None): # noqa: C901
add_group_class: append to input element's surrounding tag's `class` attribute
attr_* - adds or replaces any single html attribute for the input
add_error_attr_* - like `attr_*` but only if field.errors is not empty
- show_edit_button: shows a simple edit button, and adds display-none to the input field.
+ toggleable_input: shows a simple edit button, and adds display-none to the input field.
Example usage:
```
@@ -92,7 +92,7 @@ def input_with_errors(context, field=None): # noqa: C901
elif key == "add_group_class":
group_classes.append(value)
- elif key == "show_edit_button":
+ elif key == "toggleable_input":
# Hide the primary input field.
# Used such that we can toggle it with JS
if "display-none" not in classes:
diff --git a/src/registrar/tests/test_views_portfolio.py b/src/registrar/tests/test_views_portfolio.py
index 3596bf567..c4cdcc2b2 100644
--- a/src/registrar/tests/test_views_portfolio.py
+++ b/src/registrar/tests/test_views_portfolio.py
@@ -37,25 +37,10 @@ class TestPortfolio(WebTest):
User.objects.all().delete()
super().tearDown()
- @less_console_noise_decorator
- def test_middleware_does_not_redirect_if_no_permission(self):
- """Test that user with no portfolio permission is not redirected when attempting to access home"""
- self.app.set_user(self.user.username)
- self.user.portfolio = self.portfolio
- self.user.save()
- self.user.refresh_from_db()
- with override_flag("organization_feature", active=True):
- # This will redirect the user to the portfolio page.
- # Follow implicity checks if our redirect is working.
- portfolio_page = self.app.get(reverse("home"))
- # Assert that we're on the right page
- self.assertNotContains(portfolio_page, self.portfolio.organization_name)
-
@less_console_noise_decorator
def test_middleware_does_not_redirect_if_no_portfolio(self):
"""Test that user with no assigned portfolio is not redirected when attempting to access home"""
self.app.set_user(self.user.username)
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
@@ -67,10 +52,9 @@ class TestPortfolio(WebTest):
@less_console_noise_decorator
def test_middleware_redirects_to_portfolio_organization_page(self):
- """Test that user with VIEW_PORTFOLIO is redirected to portfolio organization page"""
+ """Test that user with a portfolio is redirected to portfolio organization page"""
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
@@ -83,11 +67,10 @@ class TestPortfolio(WebTest):
@less_console_noise_decorator
def test_middleware_redirects_to_portfolio_domains_page(self):
- """Test that user with VIEW_PORTFOLIO and VIEW_ALL_DOMAINS is redirected to portfolio domains page"""
+ """Test that user with a portfolio and VIEW_ALL_DOMAINS is redirected to portfolio domains page"""
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
]
self.user.save()
@@ -134,20 +117,47 @@ class TestPortfolio(WebTest):
self.assertEqual(response.status_code, 403)
@less_console_noise_decorator
- def test_portfolio_organization_page_403_when_user_not_have_permission(self):
- """Test that user without proper permission is not allowed access to portfolio organization page"""
+ def test_portfolio_organization_page_read_only(self):
+ """Test that user with a portfolio can access the portfolio organization page, read only"""
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
+ self.portfolio.city = "Los Angeles"
+ self.portfolio.save()
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
- # This will redirect the user to the portfolio page.
- # Follow implicity checks if our redirect is working.
- response = self.app.get(
- reverse("portfolio-organization", kwargs={"portfolio_id": self.portfolio.pk}), status=403
- )
- # Assert the response is a 403 Forbidden
- self.assertEqual(response.status_code, 403)
+ response = self.app.get(reverse("portfolio-organization", kwargs={"portfolio_id": self.portfolio.pk}))
+ # Assert the response is a 200
+ self.assertEqual(response.status_code, 200)
+ # The label for Federal agency will always be a h4
+ self.assertContains(response, '
Federal agency
')
+ # The read only label for city will be a h4
+ self.assertContains(response, '
')
+
+ @less_console_noise_decorator
+ def test_portfolio_organization_page_edit_access(self):
+ """Test that user with a portfolio can access the portfolio organization page, read only"""
+ self.app.set_user(self.user.username)
+ self.user.portfolio = self.portfolio
+ self.user.portfolio_additional_permissions = [
+ User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
+ ]
+ self.portfolio.city = "Los Angeles"
+ self.portfolio.save()
+ self.user.save()
+ self.user.refresh_from_db()
+ with override_flag("organization_feature", active=True):
+ response = self.app.get(reverse("portfolio-organization", kwargs={"portfolio_id": self.portfolio.pk}))
+ # Assert the response is a 200
+ self.assertEqual(response.status_code, 200)
+ # The label for Federal agency will always be a h4
+ self.assertContains(response, '
Federal agency
')
+ # The read only label for city will be a h4
+ self.assertNotContains(response, '
City
')
+ self.assertNotContains(response, '
Los Angeles
>')
+ self.assertContains(response, 'for="id_city"')
@less_console_noise_decorator
def test_navigation_links_hidden_when_user_not_have_permission(self):
@@ -155,7 +165,6 @@ class TestPortfolio(WebTest):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
User.UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
]
@@ -176,9 +185,9 @@ class TestPortfolio(WebTest):
portfolio_page, reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk})
)
- # reducing portfolio permissions to just VIEW_PORTFOLIO, which should remove domains
+ # removing non-basic portfolio perms, which should remove domains
# and domain requests from nav
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
+ self.user.portfolio_additional_permissions = []
self.user.save()
self.user.refresh_from_db()
@@ -194,16 +203,13 @@ class TestPortfolio(WebTest):
portfolio_page, reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk})
)
-
-class TestPortfolioOrganization(TestPortfolio):
-
+ @less_console_noise_decorator
def test_portfolio_org_name(self):
"""Can load portfolio's org name page."""
with override_flag("organization_feature", active=True):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
@@ -214,13 +220,13 @@ class TestPortfolioOrganization(TestPortfolio):
page, "The name of your federal agency will be publicly listed as the domain registrant."
)
+ @less_console_noise_decorator
def test_domain_org_name_address_content(self):
"""Org name and address information appears on the page."""
with override_flag("organization_feature", active=True):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
@@ -232,13 +238,13 @@ class TestPortfolioOrganization(TestPortfolio):
# Once in the sidenav, once in the main nav, once in the form
self.assertContains(page, "Hotel California", count=3)
+ @less_console_noise_decorator
def test_domain_org_name_address_form(self):
"""Submitting changes works on the org name address page."""
with override_flag("organization_feature", active=True):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
diff --git a/src/registrar/views/portfolios.py b/src/registrar/views/portfolios.py
index abd9648ba..c04044664 100644
--- a/src/registrar/views/portfolios.py
+++ b/src/registrar/views/portfolios.py
@@ -64,6 +64,9 @@ class PortfolioOrganizationView(PortfolioBasePermissionView, FormMixin):
"""Add additional context data to the template."""
context = super().get_context_data(**kwargs)
# no need to add portfolio to request context here
+
+ context["has_edit_org_portfolio_permission"] = self.request.user.has_edit_org_portfolio_permission()
+
context["has_profile_feature_flag"] = flag_is_active(self.request, "profile_feature")
context["has_organization_feature_flag"] = flag_is_active(self.request, "organization_feature")
return context
From f183090e24bd05461fb7c2b1b084914df26bd0e7 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Tue, 30 Jul 2024 12:04:25 -0400
Subject: [PATCH 08/34] fix unit tests
---
src/registrar/tests/test_views_portfolio.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/registrar/tests/test_views_portfolio.py b/src/registrar/tests/test_views_portfolio.py
index c4cdcc2b2..f28b10516 100644
--- a/src/registrar/tests/test_views_portfolio.py
+++ b/src/registrar/tests/test_views_portfolio.py
@@ -130,9 +130,9 @@ class TestPortfolio(WebTest):
# Assert the response is a 200
self.assertEqual(response.status_code, 200)
# The label for Federal agency will always be a h4
- self.assertContains(response, '
Federal agency
')
+ self.assertContains(response, '
Federal agency
')
# The read only label for city will be a h4
- self.assertContains(response, '
')
@@ -153,9 +153,9 @@ class TestPortfolio(WebTest):
# Assert the response is a 200
self.assertEqual(response.status_code, 200)
# The label for Federal agency will always be a h4
- self.assertContains(response, '
Federal agency
')
+ self.assertContains(response, '
Federal agency
')
# The read only label for city will be a h4
- self.assertNotContains(response, '
City
')
+ self.assertNotContains(response, '
City
')
self.assertNotContains(response, '
Los Angeles
>')
self.assertContains(response, 'for="id_city"')
From 6e900bc501cf00238b006fff9719f54de287bc13 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Tue, 30 Jul 2024 12:35:17 -0400
Subject: [PATCH 09/34] fix unit tests
---
src/registrar/tests/test_views_portfolio.py | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/registrar/tests/test_views_portfolio.py b/src/registrar/tests/test_views_portfolio.py
index f28b10516..089b710aa 100644
--- a/src/registrar/tests/test_views_portfolio.py
+++ b/src/registrar/tests/test_views_portfolio.py
@@ -134,7 +134,7 @@ class TestPortfolio(WebTest):
# The read only label for city will be a h4
self.assertContains(response, '
+Portfolio invitations contain all individuals who have been invited to become members of an organization.
+Invitations are sent via email, and the recipient must log in to the registrar to officially
+accept and become a member.
+
+
+
+An āinvitedā status indicates that the recipient has not logged in to the registrar since the invitation was sent
+or that the recipient has logged in but is already a member of an organization.
+A āreceivedā status indicates that the recipient has logged in.
+
diff --git a/src/registrar/tests/test_admin.py b/src/registrar/tests/test_admin.py
index c145e1f98..aa139b74e 100644
--- a/src/registrar/tests/test_admin.py
+++ b/src/registrar/tests/test_admin.py
@@ -13,6 +13,7 @@ from registrar.admin import (
ContactAdmin,
DomainInformationAdmin,
MyHostAdmin,
+ PortfolioInvitationAdmin,
UserDomainRoleAdmin,
VerifiedByStaffAdmin,
FsmModelResource,
@@ -38,6 +39,7 @@ from registrar.models import (
UserGroup,
TransitionDomain,
)
+from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.models.senior_official import SeniorOfficial
from registrar.models.user_domain_role import UserDomainRole
from registrar.models.verified_by_staff import VerifiedByStaff
@@ -177,6 +179,77 @@ class TestDomainInvitationAdmin(TestCase):
self.assertContains(response, retrieved_html, count=1)
+class TestPortfolioInvitationAdmin(TestCase):
+ """Tests for the PortfolioInvitationAdmin class as super user
+
+ Notes:
+ all tests share superuser; do not change this model in tests
+ tests have available superuser, client, and admin
+ """
+
+ @classmethod
+ def setUpClass(cls):
+ cls.factory = RequestFactory()
+ cls.admin = ListHeaderAdmin(model=PortfolioInvitationAdmin, admin_site=AdminSite())
+ cls.superuser = create_superuser()
+
+ def setUp(self):
+ """Create a client object"""
+ self.client = Client(HTTP_HOST="localhost:8080")
+
+ def tearDown(self):
+ """Delete all DomainInvitation objects"""
+ PortfolioInvitation.objects.all().delete()
+ Contact.objects.all().delete()
+
+ @classmethod
+ def tearDownClass(self):
+ User.objects.all().delete()
+
+ @less_console_noise_decorator
+ def test_has_model_description(self):
+ """Tests if this model has a model description on the table view"""
+ self.client.force_login(self.superuser)
+ response = self.client.get(
+ "/admin/registrar/portfolioinvitation/",
+ follow=True,
+ )
+
+ # Make sure that the page is loaded correctly
+ self.assertEqual(response.status_code, 200)
+
+ # Test for a description snippet
+ self.assertContains(
+ response,
+ "Portfolio invitations contain all individuals who have been invited to become members of an organization.",
+ )
+ self.assertContains(response, "Show more")
+
+ def test_get_filters(self):
+ """Ensures that our filters are displaying correctly"""
+ with less_console_noise():
+ self.client.force_login(self.superuser)
+
+ response = self.client.get(
+ "/admin/registrar/portfolioinvitation/",
+ {},
+ follow=True,
+ )
+
+ # Assert that the filters are added
+ self.assertContains(response, "invited", count=4)
+ self.assertContains(response, "Invited", count=2)
+ self.assertContains(response, "retrieved", count=2)
+ self.assertContains(response, "Retrieved", count=2)
+
+ # Check for the HTML context specificially
+ invited_html = 'Invited'
+ retrieved_html = 'Retrieved'
+
+ self.assertContains(response, invited_html, count=1)
+ self.assertContains(response, retrieved_html, count=1)
+
+
class TestHostAdmin(TestCase):
"""Tests for the HostAdmin class as super user
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index 741ec5361..994f45480 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -20,7 +20,9 @@ from registrar.models import (
import boto3_mocking
from registrar.models.portfolio import Portfolio
+from registrar.models.portfolio_invitation import PortfolioInvitation
from registrar.models.transition_domain import TransitionDomain
+from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices, UserPortfolioRoleChoices
from registrar.models.verified_by_staff import VerifiedByStaff # type: ignore
from registrar.utility.constants import BranchChoices
@@ -1071,8 +1073,8 @@ class TestDomainInformation(TestCase):
return {k: v for k, v in dict_obj.items() if k not in bad_fields}
-class TestInvitations(TestCase):
- """Test the retrieval of invitations."""
+class TestDomainInvitations(TestCase):
+ """Test the retrieval of domain invitations."""
@less_console_noise_decorator
def setUp(self):
@@ -1116,6 +1118,65 @@ class TestInvitations(TestCase):
self.assertTrue(UserDomainRole.objects.get(user=self.user, domain=self.domain))
+class TestPortfolioInvitations(TestCase):
+ """Test the retrieval of portfolio invitations."""
+
+ @less_console_noise_decorator
+ def setUp(self):
+ self.email = "mayor@igorville.gov"
+ self.email2 = "creator@igorville.gov"
+ self.user, _ = User.objects.get_or_create(email=self.email)
+ self.user2, _ = User.objects.get_or_create(email=self.email2, username="creator")
+ self.portfolio, _ = Portfolio.objects.get_or_create(creator=self.user2, organization_name="Hotel California")
+ self.portfolio_role_base = UserPortfolioRoleChoices.ORGANIZATION_MEMBER
+ self.portfolio_role_admin = UserPortfolioRoleChoices.ORGANIZATION_ADMIN
+ self.portfolio_permission_1 = UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS
+ self.portfolio_permission_2 = UserPortfolioPermissionChoices.EDIT_REQUESTS
+ self.invitation, _ = PortfolioInvitation.objects.get_or_create(
+ email=self.email,
+ portfolio=self.portfolio,
+ portfolio_roles=[self.portfolio_role_base, self.portfolio_role_admin],
+ portfolio_additional_permissions=[self.portfolio_permission_1, self.portfolio_permission_2],
+ )
+
+ def tearDown(self):
+ super().tearDown()
+ Portfolio.objects.all().delete()
+ PortfolioInvitation.objects.all().delete()
+ User.objects.all().delete()
+
+ @less_console_noise_decorator
+ def test_retrieval(self):
+ self.assertFalse(self.user.portfolio)
+ self.invitation.retrieve()
+ self.user.refresh_from_db()
+ self.assertEqual(self.user.portfolio.organization_name, "Hotel California")
+ self.assertEqual(self.user.portfolio_roles, [self.portfolio_role_base, self.portfolio_role_admin])
+ self.assertEqual(
+ self.user.portfolio_additional_permissions, [self.portfolio_permission_1, self.portfolio_permission_2]
+ )
+ self.assertEqual(self.invitation.status, PortfolioInvitation.PortfolioInvitationStatus.RETRIEVED)
+
+ @less_console_noise_decorator
+ def test_retrieve_missing_user_error(self):
+ # get rid of matching users
+ User.objects.filter(email=self.email).delete()
+ with self.assertRaises(RuntimeError):
+ self.invitation.retrieve()
+
+ @less_console_noise_decorator
+ def test_retrieve_user_already_member_error(self):
+ self.assertFalse(self.user.portfolio)
+ portfolio2, _ = Portfolio.objects.get_or_create(creator=self.user2, organization_name="Tokyo Hotel")
+ self.user.portfolio = portfolio2
+ self.assertEqual(self.user.portfolio.organization_name, "Tokyo Hotel")
+ self.user.save()
+ self.user.check_portfolio_invitations_on_login()
+ self.user.refresh_from_db()
+ self.assertEqual(self.user.portfolio.organization_name, "Tokyo Hotel")
+ self.assertEqual(self.invitation.status, PortfolioInvitation.PortfolioInvitationStatus.INVITED)
+
+
class TestUser(TestCase):
"""Test actions that occur on user login,
test class method that controls how users get validated."""
From f22316ccc2b326ed079fd0488897a603064221cc Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 08:14:26 -0400
Subject: [PATCH 19/34] fix unit tests
---
src/registrar/tests/test_models.py | 3 ++-
src/registrar/tests/test_views_portfolio.py | 27 +++++++++++----------
2 files changed, 16 insertions(+), 14 deletions(-)
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index 994f45480..c1059012b 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -1196,6 +1196,7 @@ class TestUser(TestCase):
DomainRequest.objects.all().delete()
DraftDomain.objects.all().delete()
TransitionDomain.objects.all().delete()
+ Portfolio.objects.all().delete()
User.objects.all().delete()
UserDomainRole.objects.all().delete()
@@ -1359,7 +1360,7 @@ class TestUser(TestCase):
"""
portfolio, _ = Portfolio.objects.get_or_create(creator=self.user, organization_name="Hotel California")
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS]
+ self.user.portfolio_additional_permissions = [UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS]
self.user.save()
self.user.refresh_from_db()
diff --git a/src/registrar/tests/test_views_portfolio.py b/src/registrar/tests/test_views_portfolio.py
index 3596bf567..f1db5b29e 100644
--- a/src/registrar/tests/test_views_portfolio.py
+++ b/src/registrar/tests/test_views_portfolio.py
@@ -10,6 +10,7 @@ from registrar.models import (
UserDomainRole,
User,
)
+from registrar.models.utility.portfolio_helper import UserPortfolioPermissionChoices
from .common import create_test_user
from waffle.testutils import override_flag
@@ -55,7 +56,7 @@ class TestPortfolio(WebTest):
def test_middleware_does_not_redirect_if_no_portfolio(self):
"""Test that user with no assigned portfolio is not redirected when attempting to access home"""
self.app.set_user(self.user.username)
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
+ self.user.portfolio_additional_permissions = [UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
@@ -70,7 +71,7 @@ class TestPortfolio(WebTest):
"""Test that user with VIEW_PORTFOLIO is redirected to portfolio organization page"""
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
+ self.user.portfolio_additional_permissions = [UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
with override_flag("organization_feature", active=True):
@@ -87,8 +88,8 @@ class TestPortfolio(WebTest):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
+ UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
+ UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
]
self.user.save()
self.user.refresh_from_db()
@@ -155,9 +156,9 @@ class TestPortfolio(WebTest):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
- User.UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
+ UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
+ UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS,
+ UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS,
]
self.user.save()
self.user.refresh_from_db()
@@ -203,8 +204,8 @@ class TestPortfolioOrganization(TestPortfolio):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
+ UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
+ UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
self.user.refresh_from_db()
@@ -220,8 +221,8 @@ class TestPortfolioOrganization(TestPortfolio):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
+ UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
+ UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
self.user.refresh_from_db()
@@ -238,8 +239,8 @@ class TestPortfolioOrganization(TestPortfolio):
self.app.set_user(self.user.username)
self.user.portfolio = self.portfolio
self.user.portfolio_additional_permissions = [
- User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
- User.UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
+ UserPortfolioPermissionChoices.VIEW_PORTFOLIO,
+ UserPortfolioPermissionChoices.EDIT_PORTFOLIO,
]
self.user.save()
self.user.refresh_from_db()
From 108adce05e30b3b620408ac091446b542d4a0998 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 08:28:36 -0400
Subject: [PATCH 20/34] fix migrations
---
...14_portfolioinvitation.py => 0115_portfolioinvitation.py} | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
rename src/registrar/migrations/{0114_portfolioinvitation.py => 0115_portfolioinvitation.py} (93%)
diff --git a/src/registrar/migrations/0114_portfolioinvitation.py b/src/registrar/migrations/0115_portfolioinvitation.py
similarity index 93%
rename from src/registrar/migrations/0114_portfolioinvitation.py
rename to src/registrar/migrations/0115_portfolioinvitation.py
index afd1dd714..82a171f10 100644
--- a/src/registrar/migrations/0114_portfolioinvitation.py
+++ b/src/registrar/migrations/0115_portfolioinvitation.py
@@ -1,4 +1,4 @@
-# Generated by Django 4.2.10 on 2024-07-31 22:49
+# Generated by Django 4.2.10 on 2024-08-01 12:28
import django.contrib.postgres.fields
from django.db import migrations, models
@@ -9,7 +9,7 @@ import django_fsm
class Migration(migrations.Migration):
dependencies = [
- ("registrar", "0113_user_portfolio_user_portfolio_additional_permissions_and_more"),
+ ("registrar", "0114_alter_user_portfolio_additional_permissions"),
]
operations = [
@@ -44,7 +44,6 @@ class Migration(migrations.Migration):
choices=[
("view_all_domains", "View all domains and domain reports"),
("view_managed_domains", "View managed domains"),
- ("edit_domains", "User is a manager on a domain"),
("view_member", "View members"),
("edit_member", "Create and edit members"),
("view_all_requests", "View all requests"),
From ca24078f50f39fccbccb6a9cd9a9efe91e20c8c6 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 08:37:21 -0400
Subject: [PATCH 21/34] fix unit tests
---
src/registrar/tests/test_views_portfolio.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/registrar/tests/test_views_portfolio.py b/src/registrar/tests/test_views_portfolio.py
index f1db5b29e..29515d18f 100644
--- a/src/registrar/tests/test_views_portfolio.py
+++ b/src/registrar/tests/test_views_portfolio.py
@@ -179,7 +179,7 @@ class TestPortfolio(WebTest):
# reducing portfolio permissions to just VIEW_PORTFOLIO, which should remove domains
# and domain requests from nav
- self.user.portfolio_additional_permissions = [User.UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
+ self.user.portfolio_additional_permissions = [UserPortfolioPermissionChoices.VIEW_PORTFOLIO]
self.user.save()
self.user.refresh_from_db()
@@ -195,9 +195,7 @@ class TestPortfolio(WebTest):
portfolio_page, reverse("portfolio-domain-requests", kwargs={"portfolio_id": self.portfolio.pk})
)
-
-class TestPortfolioOrganization(TestPortfolio):
-
+ @less_console_noise_decorator
def test_portfolio_org_name(self):
"""Can load portfolio's org name page."""
with override_flag("organization_feature", active=True):
@@ -215,6 +213,7 @@ class TestPortfolioOrganization(TestPortfolio):
page, "The name of your federal agency will be publicly listed as the domain registrant."
)
+ @less_console_noise_decorator
def test_domain_org_name_address_content(self):
"""Org name and address information appears on the page."""
with override_flag("organization_feature", active=True):
@@ -233,6 +232,7 @@ class TestPortfolioOrganization(TestPortfolio):
# Once in the sidenav, once in the main nav, once in the form
self.assertContains(page, "Hotel California", count=3)
+ @less_console_noise_decorator
def test_domain_org_name_address_form(self):
"""Submitting changes works on the org name address page."""
with override_flag("organization_feature", active=True):
From 7b46e39a89ad50df6627c5680ac94ea7d14018f4 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 08:42:57 -0400
Subject: [PATCH 22/34] fix unit tests
---
src/registrar/tests/test_models.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/registrar/tests/test_models.py b/src/registrar/tests/test_models.py
index 5fffa878f..b50525e27 100644
--- a/src/registrar/tests/test_models.py
+++ b/src/registrar/tests/test_models.py
@@ -1379,7 +1379,7 @@ class TestUser(TestCase):
self.assertTrue(user_can_view_all_domains)
self.assertFalse(user_can_view_all_requests)
- self.user.portfolio_roles = [User.UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
+ self.user.portfolio_roles = [UserPortfolioRoleChoices.ORGANIZATION_ADMIN]
self.user.save()
self.user.refresh_from_db()
From 70d30f9cee2f9495ae4a76643542f9ea7f0a1ee2 Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 08:52:02 -0400
Subject: [PATCH 23/34] fix unit tests
---
src/registrar/models/user.py | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/src/registrar/models/user.py b/src/registrar/models/user.py
index d81c17123..33d8fa1ac 100644
--- a/src/registrar/models/user.py
+++ b/src/registrar/models/user.py
@@ -254,13 +254,13 @@ class User(AbstractUser):
def has_domains_portfolio_permission(self):
return self._has_portfolio_permission(
- User.UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
- ) or self._has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
+ UserPortfolioPermissionChoices.VIEW_ALL_DOMAINS
+ ) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_MANAGED_DOMAINS)
def has_domain_requests_portfolio_permission(self):
return self._has_portfolio_permission(
- User.UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
- ) or self._has_portfolio_permission(User.UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
+ UserPortfolioPermissionChoices.VIEW_ALL_REQUESTS
+ ) or self._has_portfolio_permission(UserPortfolioPermissionChoices.VIEW_CREATED_REQUESTS)
@classmethod
def needs_identity_verification(cls, email, uuid):
From 0c8b90850dadc5f7bbdd762f2c5cff496adf1fea Mon Sep 17 00:00:00 2001
From: Matt-Spence
Date: Thu, 1 Aug 2024 12:11:39 -0500
Subject: [PATCH 24/34] Update docs/developer/README.md
Co-authored-by: Erin Song <121973038+erinysong@users.noreply.github.com>
---
docs/developer/README.md | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/docs/developer/README.md b/docs/developer/README.md
index e978ab666..358df649c 100644
--- a/docs/developer/README.md
+++ b/docs/developer/README.md
@@ -360,4 +360,5 @@ Then, copy the variables under the section labled `s3`.
4. (Important) Set the field `everyone` to `Yes`. This field overrides all other settings
## Request Flow FSM Diagram
-There is a diagram detailing the flow of domain requests and resulting domain objects [here](https://miro.com/app/board/uXjVMuqbLOk=/?moveToWidget=3458764594819017396&cot=14)
\ No newline at end of file
+
+The [.gov Domain Request & Domain Status Digram](https://miro.com/app/board/uXjVMuqbLOk=/?moveToWidget=3458764594819017396&cot=14) visualizes the domain request flow and resulting domain objects.
From 165e27307bd0fb79cff17d1d9abed05cc2aaad3b Mon Sep 17 00:00:00 2001
From: Rachid Mrad
Date: Thu, 1 Aug 2024 14:10:20 -0400
Subject: [PATCH 25/34] fix federal agency
---
src/registrar/templates/portfolio_organization.html | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/registrar/templates/portfolio_organization.html b/src/registrar/templates/portfolio_organization.html
index cc9cf5b6a..b17d18b62 100644
--- a/src/registrar/templates/portfolio_organization.html
+++ b/src/registrar/templates/portfolio_organization.html
@@ -35,7 +35,7 @@
{% csrf_token %}