diff --git a/docs/developer/feature-flags.md b/docs/developer/feature-flags.md new file mode 100644 index 000000000..e69de29bb diff --git a/src/registrar/migrations/0090_waffleflag.py b/src/registrar/migrations/0090_waffleflag.py index d8e6fb229..ff449d77a 100644 --- a/src/registrar/migrations/0090_waffleflag.py +++ b/src/registrar/migrations/0090_waffleflag.py @@ -1,4 +1,4 @@ -# Generated by Django 4.2.10 on 2024-04-30 16:25 +# Generated by Django 4.2.10 on 2024-04-30 16:56 from django.conf import settings from django.db import migrations, models @@ -33,9 +33,8 @@ class Migration(migrations.Migration): ('users', models.ManyToManyField(blank=True, help_text='Activate this flag for these users.', to=settings.AUTH_USER_MODEL, verbose_name='Users')), ], options={ - 'verbose_name': 'Flag', - 'verbose_name_plural': 'Flags', - 'abstract': False, + 'verbose_name': 'waffle flag', + 'verbose_name_plural': 'Waffle flags', }, ), ] diff --git a/src/registrar/migrations/0091_create_waffle_flags_v01.py b/src/registrar/migrations/0091_create_waffle_flags_v01.py new file mode 100644 index 000000000..c98542a14 --- /dev/null +++ b/src/registrar/migrations/0091_create_waffle_flags_v01.py @@ -0,0 +1,38 @@ +# This migration creates default WaffleFlag objects for our DB. +# Whenever you add to the `create_waffle_flags` function, increment/copy this +# migration by one + +from django.db import migrations +from registrar.models import WaffleFlag +from typing import Any + + +# For linting: RunPython expects a function reference, +# so let's give it one +def create_flags(): + """ + Populates pre-existing flags we wish to associate. + Only generates a flag name and a note, but no other data is loaded at this point. + """ + WaffleFlag.create_waffle_flags_for_migrations() + +def delete_flags(): + """ + Deletes all prexisting flags. + Does not delete flags not defined in this scope (user generated). + """ + WaffleFlag.delete_waffle_flags_for_migrations() + + +class Migration(migrations.Migration): + dependencies = [ + ("registrar", "0090_waffleflag"), + ] + + operations = [ + migrations.RunPython( + code=create_flags, + reverse_code=delete_flags, + atomic=True, + ), + ] diff --git a/src/registrar/models/waffle_flag.py b/src/registrar/models/waffle_flag.py index 827947cb3..8fe710dbd 100644 --- a/src/registrar/models/waffle_flag.py +++ b/src/registrar/models/waffle_flag.py @@ -17,21 +17,45 @@ class WaffleFlag(AbstractUserFlag): verbose_name = "waffle flag" verbose_name_plural = "Waffle flags" + # Defines which waffle flags should be created at startup. + # Add to this list if you want to add another flag that is generated at startup. + # When you do so, you will need to add a new instance of `0091_create_waffle_flags_v{version_number}` + # in registrar/migrations for that change to update automatically on migrate. + DEFAULT_WAFFLE_FLAGS = [ + "profile_feature", + "dns_hosting_feature" + ] + @classmethod - def create_waffle_flags(cls): + def create_waffle_flags_for_migrations(cls): """ Creates a pre-defined list of flags for our migrations. """ logger.info("Creating default waffle flags...") - try: - # Flags can be activated through the command line or through django admin. - # To keep the scope of this function minimal and simple, if we require additional - # config on these flag, it should be done in a seperate function or as a command. - flag_names = [ - "profile_feature", - "dns_hosting_feature", - ] - flags = [cls(name=flag_name) for flag_name in flag_names] - cls.objects.bulk_create(flags) - except Exception as e: - logger.error(f"An error occurred when attempting to create WaffleFlags: {e}") \ No newline at end of file + # Flags can be changed through the command line or through django admin. + # To keep the scope of this function minimal and simple, if we require additional + # config on these flag, it should be done in a seperate function or as a command. + for flag_name in cls.DEFAULT_WAFFLE_FLAGS: + try: + cls.objects.update_or_create( + name=flag_name, + # Booleans like superusers or is_staff can be set here, if needed. + defaults={ + 'note': 'Auto-generated waffle flag' + } + ) + except Exception as e: + logger.error(f"An error occurred when attempting to add or update flag {flag_name}: {e}") + + @classmethod + def delete_waffle_flags_for_migrations(cls): + """ + Delete a pre-defined list of flags for our migrations (the reverse_code operation). + """ + logger.info("Deleting default waffle flags...") + existing_flags = cls.objects.filter(name__in=cls.DEFAULT_WAFFLE_FLAGS) + for flag in existing_flags: + try: + cls.objects.get(name=flag.name).delete() + except Exception as e: + logger.error(f"An error occurred when attempting to delete flag {flag.name}: {e}") \ No newline at end of file diff --git a/src/registrar/templates/base.html b/src/registrar/templates/base.html index 9a801f274..c0702e78f 100644 --- a/src/registrar/templates/base.html +++ b/src/registrar/templates/base.html @@ -72,9 +72,6 @@ {% if not IS_PRODUCTION %} {% include "includes/non-production-alert.html" %} - {% if has_profile_feature_flag %} -