From fbfab28f3b2709c20de4356af18f2a6e468dcde1 Mon Sep 17 00:00:00 2001 From: zandercymatics <141044360+zandercymatics@users.noreply.github.com> Date: Thu, 22 Aug 2024 11:17:36 -0600 Subject: [PATCH] skeleton --- src/registrar/admin.py | 9 +++++ .../migrations/0119_allowedemails.py | 25 +++++++++++++ .../migrations/0120_create_groups_v16.py | 37 +++++++++++++++++++ src/registrar/models/__init__.py | 3 ++ src/registrar/models/allowed_emails.py | 20 ++++++++++ 5 files changed, 94 insertions(+) create mode 100644 src/registrar/migrations/0119_allowedemails.py create mode 100644 src/registrar/migrations/0120_create_groups_v16.py create mode 100644 src/registrar/models/allowed_emails.py diff --git a/src/registrar/admin.py b/src/registrar/admin.py index 3ad5e3ea0..730e0fb20 100644 --- a/src/registrar/admin.py +++ b/src/registrar/admin.py @@ -3169,6 +3169,14 @@ class SuborganizationAdmin(ListHeaderAdmin, ImportExportModelAdmin): extra_context = {"domain_requests": domain_requests, "domains": domains} return super().change_view(request, object_id, form_url, extra_context) +class AllowedEmailsAdmin(ListHeaderAdmin): + class Meta: + model = models.AllowedEmails + + list_display = ["email"] + search_fields = ["email"] + search_help_text = "Search by email." + ordering = ["email"] admin.site.unregister(LogEntry) # Unregister the default registration @@ -3197,6 +3205,7 @@ admin.site.register(models.Portfolio, PortfolioAdmin) admin.site.register(models.DomainGroup, DomainGroupAdmin) admin.site.register(models.Suborganization, SuborganizationAdmin) admin.site.register(models.SeniorOfficial, SeniorOfficialAdmin) +admin.site.register(models.AllowedEmails, AllowedEmailsAdmin) # Register our custom waffle implementations admin.site.register(models.WaffleFlag, WaffleFlagAdmin) diff --git a/src/registrar/migrations/0119_allowedemails.py b/src/registrar/migrations/0119_allowedemails.py new file mode 100644 index 000000000..ddfda75ca --- /dev/null +++ b/src/registrar/migrations/0119_allowedemails.py @@ -0,0 +1,25 @@ +# Generated by Django 4.2.10 on 2024-08-22 17:16 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("registrar", "0118_alter_portfolio_options_alter_portfolio_creator_and_more"), + ] + + operations = [ + migrations.CreateModel( + name="AllowedEmails", + fields=[ + ("id", models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name="ID")), + ("created_at", models.DateTimeField(auto_now_add=True)), + ("updated_at", models.DateTimeField(auto_now=True)), + ("email", models.EmailField(max_length=320, unique=True)), + ], + options={ + "abstract": False, + }, + ), + ] diff --git a/src/registrar/migrations/0120_create_groups_v16.py b/src/registrar/migrations/0120_create_groups_v16.py new file mode 100644 index 000000000..51330bc99 --- /dev/null +++ b/src/registrar/migrations/0120_create_groups_v16.py @@ -0,0 +1,37 @@ +# This migration creates the create_full_access_group and create_cisa_analyst_group groups +# It is dependent on 0079 (which populates federal agencies) +# If permissions on the groups need changing, edit CISA_ANALYST_GROUP_PERMISSIONS +# in the user_group model then: +# [NOT RECOMMENDED] +# step 1: docker-compose exec app ./manage.py migrate --fake registrar 0035_contenttypes_permissions +# step 2: docker-compose exec app ./manage.py migrate registrar 0036_create_groups +# step 3: fake run the latest migration in the migrations list +# [RECOMMENDED] +# Alternatively: +# step 1: duplicate the migration that loads data +# step 2: docker-compose exec app ./manage.py migrate + +from django.db import migrations +from registrar.models import UserGroup +from typing import Any + + +# For linting: RunPython expects a function reference, +# so let's give it one +def create_groups(apps, schema_editor) -> Any: + UserGroup.create_cisa_analyst_group(apps, schema_editor) + UserGroup.create_full_access_group(apps, schema_editor) + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0119_allowedemails"), + ] + + operations = [ + migrations.RunPython( + create_groups, + reverse_code=migrations.RunPython.noop, + atomic=True, + ), + ] diff --git a/src/registrar/models/__init__.py b/src/registrar/models/__init__.py index 1e0aad0b1..93723de7d 100644 --- a/src/registrar/models/__init__.py +++ b/src/registrar/models/__init__.py @@ -21,6 +21,7 @@ from .portfolio import Portfolio from .domain_group import DomainGroup from .suborganization import Suborganization from .senior_official import SeniorOfficial +from .allowed_emails import AllowedEmails __all__ = [ @@ -46,6 +47,7 @@ __all__ = [ "DomainGroup", "Suborganization", "SeniorOfficial", + "AllowedEmails", ] auditlog.register(Contact) @@ -70,3 +72,4 @@ auditlog.register(Portfolio) auditlog.register(DomainGroup) auditlog.register(Suborganization) auditlog.register(SeniorOfficial) +auditlog.register(AllowedEmails) diff --git a/src/registrar/models/allowed_emails.py b/src/registrar/models/allowed_emails.py new file mode 100644 index 000000000..e89c5904b --- /dev/null +++ b/src/registrar/models/allowed_emails.py @@ -0,0 +1,20 @@ +from django.db import models + +from .utility.time_stamped_model import TimeStampedModel + + +class AllowedEmails(TimeStampedModel): + """ + AllowedEmails is a whitelist for email addresses that we can send to + in non-production environments. + """ + + email = models.EmailField( + unique=True, + null=False, + blank=False, + max_length=320, + ) + + def __str__(self): + return str(self.email)