diff options
| -rw-r--r-- | pydis_site/apps/api/migrations/0088_unique_filter_list.py | 2 | ||||
| -rw-r--r-- | pydis_site/apps/api/models/bot/filters.py | 12 | ||||
| -rw-r--r-- | pydis_site/apps/api/serializers.py | 50 | ||||
| -rw-r--r-- | pydis_site/apps/api/tests/test_filters.py | 24 | ||||
| -rw-r--r-- | pydis_site/apps/api/viewsets/bot/filters.py | 532 | 
5 files changed, 428 insertions, 192 deletions
| diff --git a/pydis_site/apps/api/migrations/0088_unique_filter_list.py b/pydis_site/apps/api/migrations/0088_unique_filter_list.py index 3f3a34bb..98d14e2b 100644 --- a/pydis_site/apps/api/migrations/0088_unique_filter_list.py +++ b/pydis_site/apps/api/migrations/0088_unique_filter_list.py @@ -99,4 +99,4 @@ class Migration(migrations.Migration):              code=create_unique_list,              reverse_code=None          ), -    ]
\ No newline at end of file +    ] diff --git a/pydis_site/apps/api/models/bot/filters.py b/pydis_site/apps/api/models/bot/filters.py index 4d8a4025..1eab79ba 100644 --- a/pydis_site/apps/api/models/bot/filters.py +++ b/pydis_site/apps/api/models/bot/filters.py @@ -4,8 +4,8 @@ from django.db import models  from django.db.models import UniqueConstraint  # Must be imported that way to avoid circular imports +from pydis_site.apps.api.models.mixins import ModelReprMixin, ModelTimestampMixin  from .infraction import Infraction -from pydis_site.apps.api.models.mixins import ModelTimestampMixin, ModelReprMixin  class FilterListType(models.IntegerChoices): @@ -76,7 +76,10 @@ class FilterList(ModelTimestampMixin, ModelReprMixin, models.Model):          null=False      )      remove_context = models.BooleanField( -        help_text="Whether this filter should remove the context (such as a message) triggering it.", +        help_text=( +            "Whether this filter should remove the context (such as a message) " +            "triggering it." +        ),          null=False      )      bypass_roles = ArrayField( @@ -186,7 +189,10 @@ class FilterBase(ModelTimestampMixin, ModelReprMixin, models.Model):          null=True      )      remove_context = models.BooleanField( -        help_text="Whether this filter should remove the context (such as a message) triggering it.", +        help_text=( +            "Whether this filter should remove the context (such as a message) " +            "triggering it." +        ),          null=True      )      bypass_roles = ArrayField( diff --git a/pydis_site/apps/api/serializers.py b/pydis_site/apps/api/serializers.py index 8da47802..a6328eff 100644 --- a/pydis_site/apps/api/serializers.py +++ b/pydis_site/apps/api/serializers.py @@ -21,9 +21,9 @@ from .models import (      BumpedThread,      DeletedMessage,      DocumentationLink, -    Infraction, -    FilterList,      Filter, +    FilterList, +    Infraction,      MessageDeletionContext,      Nomination,      NominationEntry, @@ -183,7 +183,9 @@ ALLOW_EMPTY_SETTINGS = (  )  # Required fields for custom JSON representation purposes -BASE_FILTER_FIELDS = ('id', 'created_at', 'updated_at', 'content', 'description', 'additional_field') +BASE_FILTER_FIELDS = ( +    'id', 'created_at', 'updated_at', 'content', 'description', 'additional_field' +)  BASE_FILTERLIST_FIELDS = ('id', 'created_at', 'updated_at', 'name', 'list_type')  BASE_SETTINGS_FIELDS = (      "bypass_roles", @@ -235,16 +237,31 @@ class FilterSerializer(ModelSerializer):      def validate(self, data: dict) -> dict:          """Perform infraction data + allowed and disallowed lists validation."""          if ( -            (get_field_value(data, "infraction_reason") or get_field_value(data, "infraction_duration")) +            ( +                get_field_value(data, "infraction_reason") +                or get_field_value(data, "infraction_duration") +            )              and get_field_value(data, "infraction_type") == "NONE"          ): -            raise ValidationError("Infraction type is required with infraction duration or reason.") +            raise ValidationError( +                "Infraction type is required with infraction duration or reason." +            ) -        if set(get_field_value(data, "disabled_channels")) & set(get_field_value(data, "enabled_channels")): -            raise ValidationError("You can't have the same value in both enabled and disabled channels lists.") +        if ( +            set(get_field_value(data, "disabled_channels")) +            & set(get_field_value(data, "enabled_channels")) +        ): +            raise ValidationError( +                "You can't have the same value in both enabled and disabled channels lists." +            ) -        if set(get_field_value(data, "disabled_categories")) & set(get_field_value(data, "enabled_categories")): -            raise ValidationError("You can't have the same value in both enabled and disabled categories lists.") +        if ( +            set(get_field_value(data, "disabled_categories")) +            & set(get_field_value(data, "enabled_categories")) +        ): +            raise ValidationError( +                "You can't have the same value in both enabled and disabled categories lists." +            )          return data @@ -253,7 +270,13 @@ class FilterSerializer(ModelSerializer):          model = Filter          fields = ( -            'id', 'created_at', 'updated_at', 'content', 'description', 'additional_field', 'filter_list' +            'id', +            'created_at', +            'updated_at', +            'content', +            'description', +            'additional_field', +            'filter_list'          ) + SETTINGS_FIELDS          extra_kwargs = _create_filter_meta_extra_kwargs() @@ -263,7 +286,8 @@ class FilterSerializer(ModelSerializer):              return super().create(validated_data)          except IntegrityError:              raise ValidationError( -                "Check if a filter with this combination of content and settings already exists in this filter list." +                "Check if a filter with this combination of content " +                "and settings already exists in this filter list."              )      def to_representation(self, instance: Filter) -> dict: @@ -340,7 +364,9 @@ class FilterListSerializer(ModelSerializer):          """Metadata defined for the Django REST Framework."""          model = FilterList -        fields = ('id', 'created_at', 'updated_at', 'name', 'list_type', 'filters') + SETTINGS_FIELDS +        fields = ( +            'id', 'created_at', 'updated_at', 'name', 'list_type', 'filters' +        ) + SETTINGS_FIELDS          extra_kwargs = _create_filter_list_meta_extra_kwargs()          # Ensure there can only be one filter list with the same name and type. diff --git a/pydis_site/apps/api/tests/test_filters.py b/pydis_site/apps/api/tests/test_filters.py index 73c8e0d9..62de23c4 100644 --- a/pydis_site/apps/api/tests/test_filters.py +++ b/pydis_site/apps/api/tests/test_filters.py @@ -6,7 +6,7 @@ from typing import Any, Dict, Tuple, Type  from django.db.models import Model  from django.urls import reverse -from pydis_site.apps.api.models.bot.filters import FilterList, Filter +from pydis_site.apps.api.models.bot.filters import Filter, FilterList  from pydis_site.apps.api.tests.base import AuthenticatedAPITestCase @@ -271,11 +271,14 @@ class FilterValidationTests(AuthenticatedAPITestCase):          base_filter = test_sequences["filter"]          base_filter_list = test_sequences["filter_list1"]          cases = ( -            ({"infraction_reason": "hi"}, {}, 400), ({"infraction_duration": timedelta(seconds=10)}, {}, 400), +            ({"infraction_reason": "hi"}, {}, 400), +            ({"infraction_duration": timedelta(seconds=10)}, {}, 400),              ({"infraction_reason": "hi"}, {"infraction_type": "NOTE"}, 200),              ({"infraction_duration": timedelta(seconds=10)}, {"infraction_type": "MUTE"}, 200), -            ({"enabled_channels": ["admins"]}, {}, 200), ({"disabled_channels": ["123"]}, {}, 200), -            ({"enabled_categories": ["CODE JAM"]}, {}, 200), ({"disabled_categories": ["CODE JAM"]}, {}, 200), +            ({"enabled_channels": ["admins"]}, {}, 200), +            ({"disabled_channels": ["123"]}, {}, 200), +            ({"enabled_categories": ["CODE JAM"]}, {}, 200), +            ({"disabled_categories": ["CODE JAM"]}, {}, 200),              ({"enabled_channels": ["admins"], "disabled_channels": ["123", "admins"]}, {}, 400),              ({"enabled_categories": ["admins"], "disabled_categories": ["123", "admins"]}, {}, 400),              ({"enabled_channels": ["admins"]}, {"disabled_channels": ["123", "admins"]}, 400), @@ -283,7 +286,9 @@ class FilterValidationTests(AuthenticatedAPITestCase):          )          for filter_settings, filter_list_settings, response_code in cases: -            with self.subTest(f_settings=filter_settings, fl_settings=filter_list_settings, response=response_code): +            with self.subTest( +                f_settings=filter_settings, fl_settings=filter_list_settings, response=response_code +            ):                  base_filter.model.objects.all().delete()                  base_filter_list.model.objects.all().delete() @@ -306,11 +311,13 @@ class FilterValidationTests(AuthenticatedAPITestCase):          test_sequences = get_test_sequences()          base_filter_list = test_sequences["filter_list1"]          cases = ( -            ({"infraction_reason": "hi"}, 400), ({"infraction_duration": timedelta(seconds=10)}, 400), +            ({"infraction_reason": "hi"}, 400), +            ({"infraction_duration": timedelta(seconds=10)}, 400),              ({"infraction_reason": "hi", "infraction_type": "NOTE"}, 200),              ({"infraction_duration": timedelta(seconds=10), "infraction_type": "MUTE"}, 200),              ({"enabled_channels": ["admins"]}, 200), ({"disabled_channels": ["123"]}, 200), -            ({"enabled_categories": ["CODE JAM"]}, 200), ({"disabled_categories": ["CODE JAM"]}, 200), +            ({"enabled_categories": ["CODE JAM"]}, 200), +            ({"disabled_categories": ["CODE JAM"]}, 200),              ({"enabled_channels": ["admins"], "disabled_channels": ["123", "admins"]}, 400),              ({"enabled_categories": ["admins"], "disabled_categories": ["123", "admins"]}, 400),          ) @@ -324,7 +331,8 @@ class FilterValidationTests(AuthenticatedAPITestCase):                  save_nested_objects(case_fl)                  response = self.client.patch( -                    f"{base_filter_list.url()}/{case_fl.id}", data=clean_test_json(filter_list_settings) +                    f"{base_filter_list.url()}/{case_fl.id}", +                    data=clean_test_json(filter_list_settings)                  )                  self.assertEqual(response.status_code, response_code) diff --git a/pydis_site/apps/api/viewsets/bot/filters.py b/pydis_site/apps/api/viewsets/bot/filters.py index 1eb05053..8e677612 100644 --- a/pydis_site/apps/api/viewsets/bot/filters.py +++ b/pydis_site/apps/api/viewsets/bot/filters.py @@ -22,69 +22,79 @@ class FilterListViewSet(ModelViewSet):      >>> [      ...     {      ...         "id": 1, -    ...         "name": "invites", +    ...         "created_at": "2023-01-27T21:26:34.027293Z", +    ...         "updated_at": "2023-01-27T21:26:34.027308Z", +    ...         "name": "invite",      ...         "list_type": 1,      ...         "filters": [      ...             {      ...                 "id": 1, +    ...                 "created_at": "2023-01-27T21:26:34.029539Z", +    ...                 "updated_at": "2023-01-27T21:26:34.030532Z",      ...                 "content": "267624335836053506",      ...                 "description": "Python Discord",      ...                 "additional_field": None, -    ...                 "filter_list": 1 +    ...                 "filter_list": 1,      ...                 "settings": { -    ...                        "bypass_roles": None -    ...                        "filter_dm": None, -    ...                        "enabled": None -    ...                        "send_alert": True, -    ...                        "remove_context": None -    ...                        "infraction_and_notification": { -    ...                            "infraction_type": None, -    ...                            "infraction_reason": "", -    ...                            "infraction_duration": None -    ...                            "dm_content": None, -    ...                            "dm_embed": None -    ...                        }, -    ...                        "channel_scope": { -    ...                            "disabled_channels": None, -    ...                            "disabled_categories": None, -    ...                            "enabled_channels": None -    ...                        } -    ...                        "mentions": { -    ...                            "ping_type": None -    ...                            "dm_ping_type": None -    ...                         } -    ...                    } -    ... +    ...                     "bypass_roles": None, +    ...                     "filter_dm": None, +    ...                     "enabled": None, +    ...                     "remove_context": None, +    ...                     "send_alert": None, +    ...                     "infraction_and_notification": { +    ...                         "infraction_type": None, +    ...                         "infraction_reason": None, +    ...                         "infraction_duration": None, +    ...                         "infraction_channel": None, +    ...                         "dm_content": None, +    ...                         "dm_embed": None +    ...                     }, +    ...                     "channel_scope": { +    ...                         "disabled_channels": None, +    ...                         "disabled_categories": None, +    ...                         "enabled_channels": None, +    ...                         "enabled_categories": None +    ...                     }, +    ...                     "mentions": { +    ...                         "guild_pings": None, +    ...                         "dm_pings": None +    ...                     } +    ...                 }      ...             },      ...             ...      ...         ], -    ...            "settings": { -    ...              "bypass_roles": [ -    ...                  "staff" -    ...              ], -    ...              "filter_dm": True, -    ...              "enabled": True -    ...              "remove_context": True, -    ...              "send_alert": True -    ...              "infraction_and_notification": { -    ...                   "infraction_type": "", -    ...                   "infraction_reason": "", -    ...                   "infraction_duration": "0.0", -    ...                   "dm_content": "", -    ...                   "dm_embed": "" -    ...               } -    ...               "channel_scope": { +    ...         "settings": { +    ...             "bypass_roles": [ +    ...                 "Helpers" +    ...             ], +    ...             "filter_dm": True, +    ...             "enabled": True, +    ...             "remove_context": True, +    ...             "send_alert": True, +    ...             "infraction_and_notification": { +    ...                 "infraction_type": "NONE", +    ...                 "infraction_reason": "", +    ...                 "infraction_duration": "0.0", +    ...                 "infraction_channel": 0, +    ...                 "dm_content": "Per Rule 6, your invite link has been removed...", +    ...                 "dm_embed": "" +    ...             }, +    ...             "channel_scope": {      ...                 "disabled_channels": [], -    ...                 "disabled_categories": [], -    ...                 "enabled_channels": [] -    ...               } -    ...               "mentions": { -    ...                 "ping_type": [ -    ...                     "onduty" -    ...                 ] -    ...                 "dm_ping_type": [] -    ...                } -    ...           }, +    ...                 "disabled_categories": [ +    ...                     "CODE JAM" +    ...                 ], +    ...                 "enabled_channels": [], +    ...                 "enabled_categories": [] +    ...             }, +    ...             "mentions": { +    ...                 "guild_pings": [ +    ...                     "Moderators" +    ...                 ], +    ...                 "dm_pings": [] +    ...             } +    ...         } +    ...     },      ...     ...      ... ] @@ -97,75 +107,205 @@ class FilterListViewSet(ModelViewSet):      #### Response format      >>> { -    ...         "id": 1, -    ...         "name": "invites", -    ...         "list_type": 1, -    ...         "filters": [ -    ...             { -    ...                 "id": 1, -    ...                 "filter_list": 1 -    ...                 "content": "267624335836053506", -    ...                 "description": "Python Discord", -    ...                 "additional_field": None, -    ...                 "settings": { -    ...                        "bypass_roles": None -    ...                        "filter_dm": None, -    ...                        "enabled": None -    ...                        "remove_context": None, -    ...                        "send_alert": None -    ...                        "infraction_and_notification": { -    ...                            "infraction_type": None, -    ...                            "infraction_reason": "", -    ...                            "infraction_duration": None -    ...                            "dm_content": None, -    ...                            "dm_embed": None -    ...                        }, -    ...                        "channel_scope": { -    ...                            "disabled_channels": None, -    ...                            "disabled_categories": None, -    ...                            "enabled_channels": None -    ...                        } -    ...                        "mentions": { -    ...                            "ping_type": None -    ...                            "dm_ping_type": None -    ...                         } -    ...                    } -    ... -    ...             }, -    ...             ... +    ...     "id": 1, +    ...     "created_at": "2023-01-27T21:26:34.027293Z", +    ...     "updated_at": "2023-01-27T21:26:34.027308Z", +    ...     "name": "invite", +    ...     "list_type": 1, +    ...     "filters": [ +    ...         { +    ...             "id": 1, +    ...             "created_at": "2023-01-27T21:26:34.029539Z", +    ...             "updated_at": "2023-01-27T21:26:34.030532Z", +    ...             "content": "267624335836053506", +    ...             "description": "Python Discord", +    ...             "additional_field": None, +    ...             "filter_list": 1, +    ...             "settings": { +    ...                 "bypass_roles": None, +    ...                 "filter_dm": None, +    ...                 "enabled": None, +    ...                 "remove_context": None, +    ...                 "send_alert": None, +    ...                 "infraction_and_notification": { +    ...                     "infraction_type": None, +    ...                     "infraction_reason": None, +    ...                     "infraction_duration": None, +    ...                     "infraction_channel": None, +    ...                     "dm_content": None, +    ...                     "dm_embed": None +    ...                 }, +    ...                 "channel_scope": { +    ...                     "disabled_channels": None, +    ...                     "disabled_categories": None, +    ...                     "enabled_channels": None, +    ...                     "enabled_categories": None +    ...                 }, +    ...                 "mentions": { +    ...                     "guild_pings": None, +    ...                     "dm_pings": None +    ...                 } +    ...             } +    ...         }, +    ...         ... +    ...     ], +    ...     "settings": { +    ...         "bypass_roles": [ +    ...             "Helpers"      ...         ], -    ...            "settings": { -    ...              "bypass_roles": [ -    ...                  "staff" -    ...              ], -    ...              "filter_dm": True, -    ...              "enabled": True -    ...              "remove_context": True -    ...              "send_alert": True -    ...              "infraction_and_notification": { -    ...                   "infraction_type": "", -    ...                   "infraction_reason": "", -    ...                   "infraction_duration": "0.0", -    ...                   "dm_content": "", -    ...                   "dm_embed": "" -    ...               } -    ...               "channel_scope": { -    ...                 "disabled_channels": [], -    ...                 "disabled_categories": [], -    ...                 "enabled_channels": [] -    ...                } -    ...               "mentions": { -    ...                 "ping_type": [ -    ...                     "onduty" -    ...                 ] -    ...                 "dm_ping_type": [] -    ...                } +    ...         "filter_dm": True, +    ...         "enabled": True, +    ...         "remove_context": True, +    ...         "send_alert": True, +    ...         "infraction_and_notification": { +    ...             "infraction_type": "NONE", +    ...             "infraction_reason": "", +    ...             "infraction_duration": "0.0", +    ...             "infraction_channel": 0, +    ...             "dm_content": "Per Rule 6, your invite link has been removed...", +    ...             "dm_embed": "" +    ...         }, +    ...         "channel_scope": { +    ...             "disabled_channels": [], +    ...             "disabled_categories": [ +    ...                 "CODE JAM" +    ...             ], +    ...             "enabled_channels": [], +    ...             "enabled_categories": [] +    ...         }, +    ...         "mentions": { +    ...             "guild_pings": [ +    ...                 "Moderators" +    ...             ], +    ...             "dm_pings": [] +    ...         } +    ...     }      ... }      #### Status codes      - 200: returned on success      - 404: returned if the id was not found. +    ### POST /bot/filter/filter_lists +    Adds a single FilterList item to the database. + +    #### Request body +    >>> { +    ...     "name": "invite", +    ...     "list_type": 1, +    ...     "bypass_roles": [ +    ...         "Helpers" +    ...     ], +    ...     "filter_dm": True, +    ...     "enabled": True, +    ...     "remove_context": True, +    ...     "send_alert": True, +    ...     "infraction_type": "NONE", +    ...     "infraction_reason": "", +    ...     "infraction_duration": "0.0", +    ...     "infraction_channel": 0, +    ...     "dm_content": "Per Rule 6, your invite link has been removed...", +    ...     "dm_embed": "", +    ...     "disabled_channels": [], +    ...     "disabled_categories": [ +    ...         "CODE JAM" +    ...     ], +    ...     "enabled_channels": [], +    ...     "enabled_categories": [] +    ...     "guild_pings": [ +    ...         "Moderators" +    ...     ], +    ...     "dm_pings": [] +    ... } + +    #### Status codes +    - 201: returned on success +    - 400: if one of the given fields is invalid + +    ### PATCH /bot/filter/filter_lists/<id:int> +    Updates a specific FilterList item from the database. + +    #### Response format +    >>> { +    ...     "id": 1, +    ...     "created_at": "2023-01-27T21:26:34.027293Z", +    ...     "updated_at": "2023-01-27T21:26:34.027308Z", +    ...     "name": "invite", +    ...     "list_type": 1, +    ...     "filters": [ +    ...         { +    ...             "id": 1, +    ...             "created_at": "2023-01-27T21:26:34.029539Z", +    ...             "updated_at": "2023-01-27T21:26:34.030532Z", +    ...             "content": "267624335836053506", +    ...             "description": "Python Discord", +    ...             "additional_field": None, +    ...             "filter_list": 1, +    ...             "settings": { +    ...                 "bypass_roles": None, +    ...                 "filter_dm": None, +    ...                 "enabled": None, +    ...                 "remove_context": None, +    ...                 "send_alert": None, +    ...                 "infraction_and_notification": { +    ...                     "infraction_type": None, +    ...                     "infraction_reason": None, +    ...                     "infraction_duration": None, +    ...                     "infraction_channel": None, +    ...                     "dm_content": None, +    ...                     "dm_embed": None +    ...                 }, +    ...                 "channel_scope": { +    ...                     "disabled_channels": None, +    ...                     "disabled_categories": None, +    ...                     "enabled_channels": None, +    ...                     "enabled_categories": None +    ...                 }, +    ...                 "mentions": { +    ...                     "guild_pings": None, +    ...                     "dm_pings": None +    ...                 } +    ...             } +    ...         }, +    ...         ... +    ...     ], +    ...     "settings": { +    ...         "bypass_roles": [ +    ...             "Helpers" +    ...         ], +    ...         "filter_dm": True, +    ...         "enabled": True, +    ...         "remove_context": True, +    ...         "send_alert": True, +    ...         "infraction_and_notification": { +    ...             "infraction_type": "NONE", +    ...             "infraction_reason": "", +    ...             "infraction_duration": "0.0", +    ...             "infraction_channel": 0, +    ...             "dm_content": "Per Rule 6, your invite link has been removed...", +    ...             "dm_embed": "" +    ...         }, +    ...         "channel_scope": { +    ...             "disabled_channels": [], +    ...             "disabled_categories": [ +    ...                 "CODE JAM" +    ...             ], +    ...             "enabled_channels": [], +    ...             "enabled_categories": [] +    ...         }, +    ...         "mentions": { +    ...             "guild_pings": [ +    ...                 "Moderators" +    ...             ], +    ...             "dm_pings": [] +    ...         } +    ...     } +    ... } + +    #### Status codes +    - 200: returned on success +    - 400: if one of the given fields is invalid +      ### DELETE /bot/filter/filter_lists/<id:int>      Deletes the FilterList item with the given `id`. @@ -188,33 +328,39 @@ class FilterViewSet(ModelViewSet):      #### Response format      >>> [ -    ...     { -    ...                 "id": 1, -    ...                 "filter_list": 1 -    ...                 "content": "267624335836053506", -    ...                 "description": "Python Discord", -    ...                 "additional_field": None, -    ...                 "settings": { -    ...                        "bypass_roles": None -    ...                        "filter_dm": None, -    ...                        "enabled": None -    ...                        "remove_context": True, -    ...                        "send_alert": True -    ...                        "infraction": { -    ...                            "infraction_type": None, -    ...                            "infraction_reason": None, -    ...                            "infraction_duration": None -    ...                        }, -    ...                        "channel_scope": { -    ...                          "disabled_channels": None, -    ...                          "disabled_categories": None, -    ...                          "enabled_channels": None -    ...                        } -    ...                        "mentions": { -    ...                          "ping_type": None, -    ...                          "dm_ping_type": None -    ...                       } -    ...                    } +    ...         { +    ...         "id": 1, +    ...         "created_at": "2023-01-27T21:26:34.029539Z", +    ...         "updated_at": "2023-01-27T21:26:34.030532Z", +    ...         "content": "267624335836053506", +    ...         "description": "Python Discord", +    ...         "additional_field": None, +    ...         "filter_list": 1, +    ...         "settings": { +    ...             "bypass_roles": None, +    ...             "filter_dm": None, +    ...             "enabled": None, +    ...             "remove_context": None, +    ...             "send_alert": None, +    ...             "infraction_and_notification": { +    ...                 "infraction_type": None, +    ...                 "infraction_reason": None, +    ...                 "infraction_duration": None, +    ...                 "infraction_channel": None, +    ...                 "dm_content": None, +    ...                 "dm_embed": None +    ...             }, +    ...             "channel_scope": { +    ...                 "disabled_channels": None, +    ...                 "disabled_categories": None, +    ...                 "enabled_channels": None, +    ...                 "enabled_categories": None +    ...             }, +    ...             "mentions": { +    ...                 "guild_pings": None, +    ...                 "dm_pings": None +    ...             } +    ...         }      ...     },      ...     ...      ... ] @@ -228,32 +374,38 @@ class FilterViewSet(ModelViewSet):      #### Response format      >>> { -    ...                 "id": 1, -    ...                 "filter_list": 1 -    ...                 "content": "267624335836053506", -    ...                 "description": "Python Discord", -    ...                 "additional_field": None, -    ...                 "settings": { -    ...                        "bypass_roles": None -    ...                        "filter_dm": None, -    ...                        "enabled": None -    ...                        "remove_context": True, -    ...                        "send_alert": True -    ...                        "infraction": { -    ...                            "infraction_type": None, -    ...                            "infraction_reason": None, -    ...                            "infraction_duration": None -    ...                        }, -    ...                        "channel_scope": { -    ...                          "disabled_channels": None, -    ...                          "disabled_categories": None, -    ...                          "enabled_channels": None, -    ...                        } -    ...                       "mentions": { -    ...                         "ping_type": None -    ...                         "dm_ping_type": None -    ...                       } -    ...                    } +    ...     "id": 1, +    ...     "created_at": "2023-01-27T21:26:34.029539Z", +    ...     "updated_at": "2023-01-27T21:26:34.030532Z", +    ...     "content": "267624335836053506", +    ...     "description": "Python Discord", +    ...     "additional_field": None, +    ...     "filter_list": 1, +    ...     "settings": { +    ...         "bypass_roles": None, +    ...         "filter_dm": None, +    ...         "enabled": None, +    ...         "remove_context": None, +    ...         "send_alert": None, +    ...         "infraction_and_notification": { +    ...             "infraction_type": None, +    ...             "infraction_reason": None, +    ...             "infraction_duration": None, +    ...             "infraction_channel": None, +    ...             "dm_content": None, +    ...             "dm_embed": None +    ...         }, +    ...         "channel_scope": { +    ...             "disabled_channels": None, +    ...             "disabled_categories": None, +    ...             "enabled_channels": None, +    ...             "enabled_categories": None +    ...         }, +    ...         "mentions": { +    ...             "guild_pings": None, +    ...             "dm_pings": None +    ...         } +    ...     }      ... }      #### Status codes @@ -265,10 +417,27 @@ class FilterViewSet(ModelViewSet):      #### Request body      >>> { +    ...     "filter_list": 1,      ...     "content": "267624335836053506",      ...     "description": "Python Discord",      ...     "additional_field": None, -    ...     "override": 1 +    ...     "bypass_roles": None, +    ...     "filter_dm": None, +    ...     "enabled": False, +    ...     "remove_context": None, +    ...     "send_alert": None, +    ...     "infraction_type": None, +    ...     "infraction_reason": None, +    ...     "infraction_duration": None, +    ...     "infraction_channel": None, +    ...     "dm_content": None, +    ...     "dm_embed": None +    ...     "disabled_channels": None, +    ...     "disabled_categories": None, +    ...     "enabled_channels": None, +    ...     "enabled_categories": None +    ...     "guild_pings": None, +    ...     "dm_pings": None      ... }      #### Status codes @@ -281,10 +450,37 @@ class FilterViewSet(ModelViewSet):      #### Response format      >>> {      ...     "id": 1, +    ...     "created_at": "2023-01-27T21:26:34.029539Z", +    ...     "updated_at": "2023-01-27T21:26:34.030532Z",      ...     "content": "267624335836053506",      ...     "description": "Python Discord",      ...     "additional_field": None, -    ...     "override": 1 +    ...     "filter_list": 1, +    ...     "settings": { +    ...         "bypass_roles": None, +    ...         "filter_dm": None, +    ...         "enabled": None, +    ...         "remove_context": None, +    ...         "send_alert": None, +    ...         "infraction_and_notification": { +    ...             "infraction_type": None, +    ...             "infraction_reason": None, +    ...             "infraction_duration": None, +    ...             "infraction_channel": None, +    ...             "dm_content": None, +    ...             "dm_embed": None +    ...         }, +    ...         "channel_scope": { +    ...             "disabled_channels": None, +    ...             "disabled_categories": None, +    ...             "enabled_channels": None, +    ...             "enabled_categories": None +    ...         }, +    ...         "mentions": { +    ...             "guild_pings": None, +    ...             "dm_pings": None +    ...         } +    ...     }      ... }      #### Status codes | 
