prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Provide documentation about user_groups and permission changes
  ### Issue description
  
  If we edit permissions for User Groups, such as to make different items viewable on django admin, this requires a very specific set of instructions that is only documentated inside user group migration files. We should reference this documentation somewhere else in our developer readme so it's clear what is needed to be done if you ever change permissions in the future.
  
   We had a case where permissions were changed and it wasn't clear what needed to be done (make a manual migration). The developers lost time trying to figure out why permissions didn't show and why running makemigrations changed nothing. I suggest adding an inline code comment around where permissions are set in user_groups too that points to documentation in developer readme. This may save future developer's time.
  
  ### Acceptance criteria
  
  - [ ] update developer documentation (inline and md) about user_group/ permission changes
  
  ### Additional context
  the migration files that have documentation about this are all ones that say _create_groups_v (followed by a number), such as 0075_create_groups_v08.py. See those for the current documentation and note that this was hard for developers to find.
  [Slack thread](https://cisa-corp.slack.com/archives/C05BGB4L5NF/p1709939481415349)
  
  ### Links to other issues
  
  _No response_
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `src/registrar/models/user_group.py`
  Content:
  ```
  1 from django.contrib.auth.models import Group
  2 import logging
  3 
  4 logger = logging.getLogger(__name__)
  5 
  6 
  7 class UserGroup(Group):
  8     class Meta:
  9         verbose_name = "User group"
  10         verbose_name_plural = "User groups"
  11 
  12     def create_cisa_analyst_group(apps, schema_editor):
  13         """This method gets run from a data migration."""
  14 
  15         # Hard to pass self to these methods as the calls from migrations
  16         # are only expecting apps and schema_editor, so we'll just define
  17         # apps, schema_editor in the local scope instead
  18         CISA_ANALYST_GROUP_PERMISSIONS = [
  19             {
  20                 "app_label": "auditlog",
  21                 "model": "logentry",
  22                 "permissions": ["view_logentry"],
  23             },
  24             {
  25                 "app_label": "registrar",
  26                 "model": "contact",
  27                 "permissions": ["change_contact"],
  28             },
  29             {
  30                 "app_label": "registrar",
  31                 "model": "domainrequest",
  32                 "permissions": ["change_domainrequest"],
  33             },
  34             {
  35                 "app_label": "registrar",
  36                 "model": "domain",
  37                 "permissions": ["view_domain"],
  38             },
  39             {
  40                 "app_label": "registrar",
  41                 "model": "draftdomain",
  42                 "permissions": ["change_draftdomain"],
  43             },
  44             {
  45                 "app_label": "registrar",
  46                 "model": "user",
  47                 "permissions": ["analyst_access_permission", "change_user"],
  48             },
  49             {
  50                 "app_label": "registrar",
  51                 "model": "domaininvitation",
  52                 "permissions": ["add_domaininvitation", "view_domaininvitation"],
  53             },
  54             {
  55                 "app_label": "registrar",
  56                 "model": "website",
  57                 "permissions": ["change_website"],
  58             },
  59             {
  60                 "app_label": "registrar",
  61                 "model": "userdomainrole",
  62                 "permissions": ["view_userdomainrole", "delete_userdomainrole"],
  63             },
  64             {
  65                 "app_label": "registrar",
  66                 "model": "verifiedbystaff",
  67                 "permissions": ["add_verifiedbystaff", "change_verifiedbystaff", "delete_verifiedbystaff"],
  68             },
  69             {
  70                 "app_label": "registrar",
  71                 "model": "federalagency",
  72                 "permissions": ["add_federalagency", "change_federalagency", "delete_federalagency"],
  73             },
  74         ]
  75 
  76         # Avoid error: You can't execute queries until the end
  77         # of the 'atomic' block.
  78         # From django docs:
  79         # https://docs.djangoproject.com/en/4.2/topics/migrations/#data-migrations
  80         # We can’t import the Person model directly as it may be a newer
  81         # version than this migration expects. We use the historical version.
  82         ContentType = apps.get_model("contenttypes", "ContentType")
  83         Permission = apps.get_model("auth", "Permission")
  84         UserGroup = apps.get_model("registrar", "UserGroup")
  85 
  86         logger.info("Going to create the Analyst Group")
  87         try:
  88             cisa_analysts_group, _ = UserGroup.objects.get_or_create(
  89                 name="cisa_analysts_group",
  90             )
  91 
  92             cisa_analysts_group.permissions.clear()
  93 
  94             for permission in CISA_ANALYST_GROUP_PERMISSIONS:
  95                 app_label = permission["app_label"]
  96                 model_name = permission["model"]
  97                 permissions = permission["permissions"]
  98 
  99                 # Retrieve the content type for the app and model
  100                 content_type = ContentType.objects.get(app_label=app_label, model=model_name)
  101 
  102                 # Retrieve the permissions based on their codenames
  103                 permissions = Permission.objects.filter(content_type=content_type, codename__in=permissions)
  104 
  105                 # Assign the permissions to the group
  106                 cisa_analysts_group.permissions.add(*permissions)
  107 
  108                 # Convert the permissions QuerySet to a list of codenames
  109                 permission_list = list(permissions.values_list("codename", flat=True))
  110 
  111                 logger.debug(
  112                     app_label
  113                     + " | "
  114                     + model_name
  115                     + " | "
  116                     + ", ".join(permission_list)
  117                     + " added to group "
  118                     + cisa_analysts_group.name
  119                 )
  120 
  121                 cisa_analysts_group.save()
  122                 logger.debug("CISA Analyst permissions added to group " + cisa_analysts_group.name)
  123         except Exception as e:
  124             logger.error(f"Error creating analyst permissions group: {e}")
  125 
  126     def create_full_access_group(apps, schema_editor):
  127         """This method gets run from a data migration."""
  128 
  129         Permission = apps.get_model("auth", "Permission")
  130         UserGroup = apps.get_model("registrar", "UserGroup")
  131 
  132         logger.info("Going to create the Full Access Group")
  133         try:
  134             full_access_group, _ = UserGroup.objects.get_or_create(
  135                 name="full_access_group",
  136             )
  137             # Get all available permissions
  138             all_permissions = Permission.objects.all()
  139 
  140             # Assign all permissions to the group
  141             full_access_group.permissions.add(*all_permissions)
  142 
  143             full_access_group.save()
  144             logger.debug("All permissions added to group " + full_access_group.name)
  145         except Exception as e:
  146             logger.error(f"Error creating full access group: {e}")
  147
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py
  --- a/src/registrar/models/user_group.py
  +++ b/src/registrar/models/user_group.py
  @@ -5,6 +5,11 @@
   
   
   class UserGroup(Group):
  +    """
  +    UserGroup sets read and write permissions for superusers (who have full access)
  +    and analysts. For more details, see the dev docs for user-permissions.
  +    """
  +
       class Meta:
           verbose_name = "User group"
           verbose_name_plural = "User groups"
  
verification_info: {"golden_diff": "diff --git a/src/registrar/models/user_group.py b/src/registrar/models/user_group.py\n--- a/src/registrar/models/user_group.py\n+++ b/src/registrar/models/user_group.py\n@@ -5,6 +5,11 @@\n \n \n class UserGroup(Group):\n+    \"\"\"\n+    UserGroup sets read and write permissions for superusers (who have full access)\n+    and analysts. For more details, see the dev docs for user-permissions.\n+    \"\"\"\n+\n     class Meta:\n         verbose_name = \"User group\"\n         verbose_name_plural = \"User groups\"\n", "issue": "Provide documentation about user_groups and permission changes\n### Issue description\r\n\r\nIf we edit permissions for User Groups, such as to make different items viewable on django admin, this requires a very specific set of instructions that is only documentated inside user group migration files. We should reference this documentation somewhere else in our developer readme so it's clear what is needed to be done if you ever change permissions in the future.\r\n\r\n We had a case where permissions were changed and it wasn't clear what needed to be done (make a manual migration). The developers lost time trying to figure out why permissions didn't show and why running makemigrations changed nothing. I suggest adding an inline code comment around where permissions are set in user_groups too that points to documentation in developer readme. This may save future developer's time.\r\n\r\n### Acceptance criteria\r\n\r\n- [ ] update developer documentation (inline and md) about user_group/ permission changes\r\n\r\n### Additional context\r\nthe migration files that have documentation about this are all ones that say _create_groups_v (followed by a number), such as 0075_create_groups_v08.py. See those for the current documentation and note that this was hard for developers to find.\r\n[Slack thread](https://cisa-corp.slack.com/archives/C05BGB4L5NF/p1709939481415349)\r\n\r\n### Links to other issues\r\n\r\n_No response_\n", "before_files": [{"content": "from django.contrib.auth.models import Group\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass UserGroup(Group):\n    class Meta:\n        verbose_name = \"User group\"\n        verbose_name_plural = \"User groups\"\n\n    def create_cisa_analyst_group(apps, schema_editor):\n        \"\"\"This method gets run from a data migration.\"\"\"\n\n        # Hard to pass self to these methods as the calls from migrations\n        # are only expecting apps and schema_editor, so we'll just define\n        # apps, schema_editor in the local scope instead\n        CISA_ANALYST_GROUP_PERMISSIONS = [\n            {\n                \"app_label\": \"auditlog\",\n                \"model\": \"logentry\",\n                \"permissions\": [\"view_logentry\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"contact\",\n                \"permissions\": [\"change_contact\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domainrequest\",\n                \"permissions\": [\"change_domainrequest\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domain\",\n                \"permissions\": [\"view_domain\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"draftdomain\",\n                \"permissions\": [\"change_draftdomain\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"user\",\n                \"permissions\": [\"analyst_access_permission\", \"change_user\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domaininvitation\",\n                \"permissions\": [\"add_domaininvitation\", \"view_domaininvitation\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"website\",\n                \"permissions\": [\"change_website\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"userdomainrole\",\n                \"permissions\": [\"view_userdomainrole\", \"delete_userdomainrole\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"verifiedbystaff\",\n                \"permissions\": [\"add_verifiedbystaff\", \"change_verifiedbystaff\", \"delete_verifiedbystaff\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"federalagency\",\n                \"permissions\": [\"add_federalagency\", \"change_federalagency\", \"delete_federalagency\"],\n            },\n        ]\n\n        # Avoid error: You can't execute queries until the end\n        # of the 'atomic' block.\n        # From django docs:\n        # https://docs.djangoproject.com/en/4.2/topics/migrations/#data-migrations\n        # We can\u2019t import the Person model directly as it may be a newer\n        # version than this migration expects. We use the historical version.\n        ContentType = apps.get_model(\"contenttypes\", \"ContentType\")\n        Permission = apps.get_model(\"auth\", \"Permission\")\n        UserGroup = apps.get_model(\"registrar\", \"UserGroup\")\n\n        logger.info(\"Going to create the Analyst Group\")\n        try:\n            cisa_analysts_group, _ = UserGroup.objects.get_or_create(\n                name=\"cisa_analysts_group\",\n            )\n\n            cisa_analysts_group.permissions.clear()\n\n            for permission in CISA_ANALYST_GROUP_PERMISSIONS:\n                app_label = permission[\"app_label\"]\n                model_name = permission[\"model\"]\n                permissions = permission[\"permissions\"]\n\n                # Retrieve the content type for the app and model\n                content_type = ContentType.objects.get(app_label=app_label, model=model_name)\n\n                # Retrieve the permissions based on their codenames\n                permissions = Permission.objects.filter(content_type=content_type, codename__in=permissions)\n\n                # Assign the permissions to the group\n                cisa_analysts_group.permissions.add(*permissions)\n\n                # Convert the permissions QuerySet to a list of codenames\n                permission_list = list(permissions.values_list(\"codename\", flat=True))\n\n                logger.debug(\n                    app_label\n                    + \" | \"\n                    + model_name\n                    + \" | \"\n                    + \", \".join(permission_list)\n                    + \" added to group \"\n                    + cisa_analysts_group.name\n                )\n\n                cisa_analysts_group.save()\n                logger.debug(\"CISA Analyst permissions added to group \" + cisa_analysts_group.name)\n        except Exception as e:\n            logger.error(f\"Error creating analyst permissions group: {e}\")\n\n    def create_full_access_group(apps, schema_editor):\n        \"\"\"This method gets run from a data migration.\"\"\"\n\n        Permission = apps.get_model(\"auth\", \"Permission\")\n        UserGroup = apps.get_model(\"registrar\", \"UserGroup\")\n\n        logger.info(\"Going to create the Full Access Group\")\n        try:\n            full_access_group, _ = UserGroup.objects.get_or_create(\n                name=\"full_access_group\",\n            )\n            # Get all available permissions\n            all_permissions = Permission.objects.all()\n\n            # Assign all permissions to the group\n            full_access_group.permissions.add(*all_permissions)\n\n            full_access_group.save()\n            logger.debug(\"All permissions added to group \" + full_access_group.name)\n        except Exception as e:\n            logger.error(f\"Error creating full access group: {e}\")\n", "path": "src/registrar/models/user_group.py"}], "after_files": [{"content": "from django.contrib.auth.models import Group\nimport logging\n\nlogger = logging.getLogger(__name__)\n\n\nclass UserGroup(Group):\n    \"\"\"\n    UserGroup sets read and write permissions for superusers (who have full access)\n    and analysts. For more details, see the dev docs for user-permissions.\n    \"\"\"\n\n    class Meta:\n        verbose_name = \"User group\"\n        verbose_name_plural = \"User groups\"\n\n    def create_cisa_analyst_group(apps, schema_editor):\n        \"\"\"This method gets run from a data migration.\"\"\"\n\n        # Hard to pass self to these methods as the calls from migrations\n        # are only expecting apps and schema_editor, so we'll just define\n        # apps, schema_editor in the local scope instead\n        CISA_ANALYST_GROUP_PERMISSIONS = [\n            {\n                \"app_label\": \"auditlog\",\n                \"model\": \"logentry\",\n                \"permissions\": [\"view_logentry\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"contact\",\n                \"permissions\": [\"change_contact\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domaininformation\",\n                \"permissions\": [\"change_domaininformation\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domainrequest\",\n                \"permissions\": [\"change_domainrequest\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domain\",\n                \"permissions\": [\"view_domain\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"draftdomain\",\n                \"permissions\": [\"change_draftdomain\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"user\",\n                \"permissions\": [\"analyst_access_permission\", \"change_user\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"domaininvitation\",\n                \"permissions\": [\"add_domaininvitation\", \"view_domaininvitation\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"website\",\n                \"permissions\": [\"change_website\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"userdomainrole\",\n                \"permissions\": [\"view_userdomainrole\", \"delete_userdomainrole\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"verifiedbystaff\",\n                \"permissions\": [\"add_verifiedbystaff\", \"change_verifiedbystaff\", \"delete_verifiedbystaff\"],\n            },\n            {\n                \"app_label\": \"registrar\",\n                \"model\": \"federalagency\",\n                \"permissions\": [\"add_federalagency\", \"change_federalagency\", \"delete_federalagency\"],\n            },\n        ]\n\n        # Avoid error: You can't execute queries until the end\n        # of the 'atomic' block.\n        # From django docs:\n        # https://docs.djangoproject.com/en/4.2/topics/migrations/#data-migrations\n        # We can\u2019t import the Person model directly as it may be a newer\n        # version than this migration expects. We use the historical version.\n        ContentType = apps.get_model(\"contenttypes\", \"ContentType\")\n        Permission = apps.get_model(\"auth\", \"Permission\")\n        UserGroup = apps.get_model(\"registrar\", \"UserGroup\")\n\n        logger.info(\"Going to create the Analyst Group\")\n        try:\n            cisa_analysts_group, _ = UserGroup.objects.get_or_create(\n                name=\"cisa_analysts_group\",\n            )\n\n            cisa_analysts_group.permissions.clear()\n\n            for permission in CISA_ANALYST_GROUP_PERMISSIONS:\n                app_label = permission[\"app_label\"]\n                model_name = permission[\"model\"]\n                permissions = permission[\"permissions\"]\n\n                # Retrieve the content type for the app and model\n                content_type = ContentType.objects.get(app_label=app_label, model=model_name)\n\n                # Retrieve the permissions based on their codenames\n                permissions = Permission.objects.filter(content_type=content_type, codename__in=permissions)\n\n                # Assign the permissions to the group\n                cisa_analysts_group.permissions.add(*permissions)\n\n                # Convert the permissions QuerySet to a list of codenames\n                permission_list = list(permissions.values_list(\"codename\", flat=True))\n\n                logger.debug(\n                    app_label\n                    + \" | \"\n                    + model_name\n                    + \" | \"\n                    + \", \".join(permission_list)\n                    + \" added to group \"\n                    + cisa_analysts_group.name\n                )\n\n                cisa_analysts_group.save()\n                logger.debug(\"CISA Analyst permissions added to group \" + cisa_analysts_group.name)\n        except Exception as e:\n            logger.error(f\"Error creating analyst permissions group: {e}\")\n\n    def create_full_access_group(apps, schema_editor):\n        \"\"\"This method gets run from a data migration.\"\"\"\n\n        Permission = apps.get_model(\"auth\", \"Permission\")\n        UserGroup = apps.get_model(\"registrar\", \"UserGroup\")\n\n        logger.info(\"Going to create the Full Access Group\")\n        try:\n            full_access_group, _ = UserGroup.objects.get_or_create(\n                name=\"full_access_group\",\n            )\n            # Get all available permissions\n            all_permissions = Permission.objects.all()\n\n            # Assign all permissions to the group\n            full_access_group.permissions.add(*all_permissions)\n\n            full_access_group.save()\n            logger.debug(\"All permissions added to group \" + full_access_group.name)\n        except Exception as e:\n            logger.error(f\"Error creating full access group: {e}\")\n", "path": "src/registrar/models/user_group.py"}]}