We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Add system checks for `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` being listed in Django configured formats
### Is your proposal related to a problem?

When configuring any of the `WAGTAIL_*_FORMAT` configs, these must be included in the relevant Django formats.

https://docs.wagtail.org/en/stable/reference/settings.html#wagtail-date-format-wagtail-datetime-format-wagtail-time-format

> ...must be one of the recognised formats listed in the DATE_INPUT_FORMATS, TIME_INPUT_FORMATS, or DATETIME_INPUT_FORMATS setting respectively 

This config coordination is easy to to get wrong causing non-intuitive behaviour as Wagtail/Django will fallback to defaults.

### Describe the solution you'd like

* Using the [Django system check framework](https://docs.djangoproject.com/en/5.0/topics/checks/) or similar, ensure that if there are misconfiguration issues there will be an error thrown or report at app startup.

### Describe alternatives you've considered

* Leave as is, the documentation advises what to do.

### Additional context

* An older PR had a really solid start to this but had a few questions and was only a draft. https://github.com/wagtail/wagtail/pull/6168
* It may make sense to start with a simple version of these checks as a smaller scoped PR.

### Working on this

* This would be good for anyone willing to dig deep into these configs & their Django equivalents.
* Some knowledge or learning of the way the Django system check framework works and exploration of the current usage in Wagtail.
* The PR linked above would be a good start but may not be the right way forward, it also did not have tests and tests are a must.
* View our [contributing guidelines](https://docs.wagtail.org/en/latest/contributing/index.html), add a comment to the issue once you’re ready to start.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `wagtail/admin/checks.py`
Content:
```
1 import os
2 
3 from django.core.checks import Error, Tags, Warning, register
4 
5 
6 @register("staticfiles")
7 def css_install_check(app_configs, **kwargs):
8     errors = []
9 
10     css_path = os.path.join(
11         os.path.dirname(__file__), "static", "wagtailadmin", "css", "core.css"
12     )
13 
14     if not os.path.isfile(css_path):
15         error_hint = (
16             """
17             Most likely you are running a development (non-packaged) copy of
18             Wagtail and have not built the static assets -
19             see https://docs.wagtail.org/en/latest/contributing/developing.html
20 
21             File not found: %s
22         """
23             % css_path
24         )
25 
26         errors.append(
27             Warning(
28                 "CSS for the Wagtail admin is missing",
29                 hint=error_hint,
30                 id="wagtailadmin.W001",
31             )
32         )
33     return errors
34 
35 
36 @register(Tags.admin)
37 def base_form_class_check(app_configs, **kwargs):
38     from wagtail.admin.forms import WagtailAdminPageForm
39     from wagtail.models import get_page_models
40 
41     errors = []
42 
43     for cls in get_page_models():
44         if not issubclass(cls.base_form_class, WagtailAdminPageForm):
45             errors.append(
46                 Error(
47                     "{}.base_form_class does not extend WagtailAdminPageForm".format(
48                         cls.__name__
49                     ),
50                     hint="Ensure that {}.{} extends WagtailAdminPageForm".format(
51                         cls.base_form_class.__module__, cls.base_form_class.__name__
52                     ),
53                     obj=cls,
54                     id="wagtailadmin.E001",
55                 )
56             )
57 
58     return errors
59 
60 
61 @register(Tags.admin)
62 def get_form_class_check(app_configs, **kwargs):
63     from wagtail.admin.forms import WagtailAdminPageForm
64     from wagtail.models import get_page_models
65 
66     errors = []
67 
68     for cls in get_page_models():
69         edit_handler = cls.get_edit_handler()
70         if not issubclass(edit_handler.get_form_class(), WagtailAdminPageForm):
71             errors.append(
72                 Error(
73                     "{cls}.get_edit_handler().get_form_class() does not extend WagtailAdminPageForm".format(
74                         cls=cls.__name__
75                     ),
76                     hint="Ensure that the panel definition for {cls} creates a subclass of WagtailAdminPageForm".format(
77                         cls=cls.__name__
78                     ),
79                     obj=cls,
80                     id="wagtailadmin.E002",
81                 )
82             )
83 
84     return errors
85 
86 
87 @register("panels")
88 def inline_panel_model_panels_check(app_configs, **kwargs):
89     from wagtail.models import get_page_models
90 
91     errors = []
92     page_models = get_page_models()
93 
94     for cls in page_models:
95         errors.extend(check_panels_in_model(cls))
96 
97     # filter out duplicate errors found for the same model
98     unique_errors = []
99     for error in errors:
100         if error.msg not in [e.msg for e in unique_errors]:
101             unique_errors.append(error)
102     return unique_errors
103 
104 
105 def check_panels_in_model(cls, context="model"):
106     """Check panels configuration uses `panels` when `edit_handler` not in use."""
107     from wagtail.admin.panels import InlinePanel, PanelGroup
108     from wagtail.models import Page
109 
110     errors = []
111 
112     if hasattr(cls, "get_edit_handler"):
113         # must check the InlinePanel related models
114         edit_handler = cls.get_edit_handler()
115         for tab in edit_handler.children:
116             if isinstance(tab, PanelGroup):
117                 inline_panel_children = [
118                     panel for panel in tab.children if isinstance(panel, InlinePanel)
119                 ]
120                 for inline_panel_child in inline_panel_children:
121                     errors.extend(
122                         check_panels_in_model(
123                             inline_panel_child.db_field.related_model,
124                             context="InlinePanel model",
125                         )
126                     )
127 
128     if issubclass(cls, Page) or hasattr(cls, "edit_handler"):
129         # Pages do not need to be checked for standalone tabbed_panel usage
130         # if edit_handler is used on any model, assume config is correct
131         return errors
132 
133     tabbed_panels = [
134         "content_panels",
135         "promote_panels",
136         "settings_panels",
137     ]
138 
139     for panel_name in tabbed_panels:
140         class_name = cls.__name__
141         if not hasattr(cls, panel_name):
142             continue
143 
144         panel_name_short = panel_name.replace("_panels", "").title()
145         error_title = "{}.{} will have no effect on {} editing".format(
146             class_name, panel_name, context
147         )
148 
149         if "InlinePanel" in context:
150             error_hint = """Ensure that {} uses `panels` instead of `{}`.
151 There are no tabs on non-Page model editing within InlinePanels.""".format(
152                 class_name, panel_name
153             )
154         else:
155             error_hint = """Ensure that {} uses `panels` instead of `{}`\
156 or set up an `edit_handler` if you want a tabbed editing interface.
157 There are no default tabs on non-Page models so there will be no \
158 {} tab for the {} to render in.""".format(
159                 class_name, panel_name, panel_name_short, panel_name
160             )
161 
162         error = Warning(error_title, hint=error_hint, obj=cls, id="wagtailadmin.W002")
163 
164         errors.append(error)
165 
166     return errors
167 
168 
169 @register("wagtailadmin_base_url")
170 def wagtail_admin_base_url_check(app_configs, **kwargs):
171     from django.conf import settings
172 
173     errors = []
174 
175     if getattr(settings, "WAGTAILADMIN_BASE_URL", None) is None:
176         errors.append(
177             Warning(
178                 "The WAGTAILADMIN_BASE_URL setting is not defined",
179                 hint="This should be the base URL used to access the Wagtail admin site. "
180                 "Without this, URLs in notification emails will not display correctly.",
181                 id="wagtailadmin.W003",
182             )
183         )
184 
185     return errors
186 
187 
188 @register("file_overwrite")
189 def file_overwrite_check(app_configs, **kwargs):
190     from django import VERSION as DJANGO_VERSION
191     from django.conf import settings
192 
193     if DJANGO_VERSION >= (5, 1):
194         file_storage = getattr(settings, "STORAGES")["default"]["BACKEND"]
195     else:
196         try:
197             file_storage = getattr(settings, "STORAGES")["default"]["BACKEND"]
198         except AttributeError:
199             file_storage = getattr(settings, "DEFAULT_FILE_STORAGE", None)
200 
201     errors = []
202 
203     if file_storage == "storages.backends.s3boto3.S3Boto3Storage" and getattr(
204         settings, "AWS_S3_FILE_OVERWRITE", True
205     ):
206         errors.append(
207             Warning(
208                 "The AWS_S3_FILE_OVERWRITE setting is set to True",
209                 hint="This should be set to False. The incorrect setting can cause documents and "
210                 "other user-uploaded files to be silently overwritten or deleted.",
211                 id="wagtailadmin.W004",
212             )
213         )
214     if file_storage == "storages.backends.azure_storage.AzureStorage" and getattr(
215         settings, "AZURE_OVERWRITE_FILES", False
216     ):
217         errors.append(
218             Warning(
219                 "The AZURE_OVERWRITE_FILES setting is set to True",
220                 hint="This should be set to False. The incorrect setting can cause documents and "
221                 "other user-uploaded files to be silently overwritten or deleted.",
222                 id="wagtailadmin.W004",
223             )
224         )
225     if file_storage == "storages.backends.gcloud.GoogleCloudStorage" and getattr(
226         settings, "GS_FILE_OVERWRITE", True
227     ):
228         errors.append(
229             Warning(
230                 "The GS_FILE_OVERWRITE setting is set to True",
231                 hint="This should be set to False. The incorrect setting can cause documents and "
232                 "other user-uploaded files to be silently overwritten or deleted.",
233                 id="wagtailadmin.W004",
234             )
235         )
236 
237     return errors
238
```
--- 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()

```

diff --git a/wagtail/admin/checks.py b/wagtail/admin/checks.py
--- a/wagtail/admin/checks.py
+++ b/wagtail/admin/checks.py
@@ -235,3 +235,54 @@
         )
 
     return errors
+
+
+@register("datetime_format")
+def datetime_format_check(app_configs, **kwargs):
+    """
+    If L10N is enabled, check if WAGTAIL_* formats are compatible with Django input formats.
+    See https://docs.djangoproject.com/en/stable/topics/i18n/formatting/#creating-custom-format-files
+    See https://docs.wagtail.org/en/stable/reference/settings.html#wagtail-date-format-wagtail-datetime-format-wagtail-time-format
+    """
+
+    from django.conf import settings
+    from django.utils import formats, translation
+
+    errors = []
+
+    if not getattr(settings, "USE_L10N", False):
+        return errors
+
+    formats.FORMAT_SETTINGS = formats.FORMAT_SETTINGS.union(
+        [
+            "WAGTAIL_DATE_FORMAT",
+            "WAGTAIL_DATETIME_FORMAT",
+            "WAGTAIL_TIME_FORMAT",
+        ]
+    )
+
+    for code, label in settings.LANGUAGES:
+        with translation.override(code):
+            for wagtail_format, django_formats in [
+                ("WAGTAIL_DATE_FORMAT", "DATE_INPUT_FORMATS"),
+                ("WAGTAIL_DATETIME_FORMAT", "DATETIME_INPUT_FORMATS"),
+                ("WAGTAIL_TIME_FORMAT", "TIME_INPUT_FORMATS"),
+            ]:
+                wagtail_format_value = getattr(settings, wagtail_format, None)
+                django_formats_value = getattr(settings, django_formats, None)
+
+                if wagtail_format_value is None:
+                    # Skip the iteration if wagtail_format is not present
+                    continue
+
+                input_format = formats.get_format_lazy(wagtail_format_value)
+                input_formats = formats.get_format_lazy(django_formats_value)
+                if str(input_format) not in str(input_formats):
+                    errors.append(
+                        Error(
+                            "Configuration error",
+                            hint=f"{wagtail_format} {input_format} must be in {django_formats} for language {label} ({code}).",
+                        )
+                    )
+
+    return errors

{"golden_diff": "diff --git a/wagtail/admin/checks.py b/wagtail/admin/checks.py\n--- a/wagtail/admin/checks.py\n+++ b/wagtail/admin/checks.py\n@@ -235,3 +235,54 @@\n         )\n \n     return errors\n+\n+\n+@register(\"datetime_format\")\n+def datetime_format_check(app_configs, **kwargs):\n+    \"\"\"\n+    If L10N is enabled, check if WAGTAIL_* formats are compatible with Django input formats.\n+    See https://docs.djangoproject.com/en/stable/topics/i18n/formatting/#creating-custom-format-files\n+    See https://docs.wagtail.org/en/stable/reference/settings.html#wagtail-date-format-wagtail-datetime-format-wagtail-time-format\n+    \"\"\"\n+\n+    from django.conf import settings\n+    from django.utils import formats, translation\n+\n+    errors = []\n+\n+    if not getattr(settings, \"USE_L10N\", False):\n+        return errors\n+\n+    formats.FORMAT_SETTINGS = formats.FORMAT_SETTINGS.union(\n+        [\n+            \"WAGTAIL_DATE_FORMAT\",\n+            \"WAGTAIL_DATETIME_FORMAT\",\n+            \"WAGTAIL_TIME_FORMAT\",\n+        ]\n+    )\n+\n+    for code, label in settings.LANGUAGES:\n+        with translation.override(code):\n+            for wagtail_format, django_formats in [\n+                (\"WAGTAIL_DATE_FORMAT\", \"DATE_INPUT_FORMATS\"),\n+                (\"WAGTAIL_DATETIME_FORMAT\", \"DATETIME_INPUT_FORMATS\"),\n+                (\"WAGTAIL_TIME_FORMAT\", \"TIME_INPUT_FORMATS\"),\n+            ]:\n+                wagtail_format_value = getattr(settings, wagtail_format, None)\n+                django_formats_value = getattr(settings, django_formats, None)\n+\n+                if wagtail_format_value is None:\n+                    # Skip the iteration if wagtail_format is not present\n+                    continue\n+\n+                input_format = formats.get_format_lazy(wagtail_format_value)\n+                input_formats = formats.get_format_lazy(django_formats_value)\n+                if str(input_format) not in str(input_formats):\n+                    errors.append(\n+                        Error(\n+                            \"Configuration error\",\n+                            hint=f\"{wagtail_format} {input_format} must be in {django_formats} for language {label} ({code}).\",\n+                        )\n+                    )\n+\n+    return errors\n", "issue": "Add system checks for `WAGTAIL_DATE_FORMAT`, `WAGTAIL_DATETIME_FORMAT`, `WAGTAIL_TIME_FORMAT` being listed in Django configured formats\n### Is your proposal related to a problem?\r\n\r\nWhen configuring any of the `WAGTAIL_*_FORMAT` configs, these must be included in the relevant Django formats.\r\n\r\nhttps://docs.wagtail.org/en/stable/reference/settings.html#wagtail-date-format-wagtail-datetime-format-wagtail-time-format\r\n\r\n> ...must be one of the recognised formats listed in the DATE_INPUT_FORMATS, TIME_INPUT_FORMATS, or DATETIME_INPUT_FORMATS setting respectively \r\n\r\nThis config coordination is easy to to get wrong causing non-intuitive behaviour as Wagtail/Django will fallback to defaults.\r\n\r\n### Describe the solution you'd like\r\n\r\n* Using the [Django system check framework](https://docs.djangoproject.com/en/5.0/topics/checks/) or similar, ensure that if there are misconfiguration issues there will be an error thrown or report at app startup.\r\n\r\n### Describe alternatives you've considered\r\n\r\n* Leave as is, the documentation advises what to do.\r\n\r\n### Additional context\r\n\r\n* An older PR had a really solid start to this but had a few questions and was only a draft. https://github.com/wagtail/wagtail/pull/6168\r\n* It may make sense to start with a simple version of these checks as a smaller scoped PR.\r\n\r\n### Working on this\r\n\r\n* This would be good for anyone willing to dig deep into these configs & their Django equivalents.\r\n* Some knowledge or learning of the way the Django system check framework works and exploration of the current usage in Wagtail.\r\n* The PR linked above would be a good start but may not be the right way forward, it also did not have tests and tests are a must.\r\n* View our [contributing guidelines](https://docs.wagtail.org/en/latest/contributing/index.html), add a comment to the issue once you\u2019re ready to start.\r\n\n", "before_files": [{"content": "import os\n\nfrom django.core.checks import Error, Tags, Warning, register\n\n\n@register(\"staticfiles\")\ndef css_install_check(app_configs, **kwargs):\n    errors = []\n\n    css_path = os.path.join(\n        os.path.dirname(__file__), \"static\", \"wagtailadmin\", \"css\", \"core.css\"\n    )\n\n    if not os.path.isfile(css_path):\n        error_hint = (\n            \"\"\"\n            Most likely you are running a development (non-packaged) copy of\n            Wagtail and have not built the static assets -\n            see https://docs.wagtail.org/en/latest/contributing/developing.html\n\n            File not found: %s\n        \"\"\"\n            % css_path\n        )\n\n        errors.append(\n            Warning(\n                \"CSS for the Wagtail admin is missing\",\n                hint=error_hint,\n                id=\"wagtailadmin.W001\",\n            )\n        )\n    return errors\n\n\n@register(Tags.admin)\ndef base_form_class_check(app_configs, **kwargs):\n    from wagtail.admin.forms import WagtailAdminPageForm\n    from wagtail.models import get_page_models\n\n    errors = []\n\n    for cls in get_page_models():\n        if not issubclass(cls.base_form_class, WagtailAdminPageForm):\n            errors.append(\n                Error(\n                    \"{}.base_form_class does not extend WagtailAdminPageForm\".format(\n                        cls.__name__\n                    ),\n                    hint=\"Ensure that {}.{} extends WagtailAdminPageForm\".format(\n                        cls.base_form_class.__module__, cls.base_form_class.__name__\n                    ),\n                    obj=cls,\n                    id=\"wagtailadmin.E001\",\n                )\n            )\n\n    return errors\n\n\n@register(Tags.admin)\ndef get_form_class_check(app_configs, **kwargs):\n    from wagtail.admin.forms import WagtailAdminPageForm\n    from wagtail.models import get_page_models\n\n    errors = []\n\n    for cls in get_page_models():\n        edit_handler = cls.get_edit_handler()\n        if not issubclass(edit_handler.get_form_class(), WagtailAdminPageForm):\n            errors.append(\n                Error(\n                    \"{cls}.get_edit_handler().get_form_class() does not extend WagtailAdminPageForm\".format(\n                        cls=cls.__name__\n                    ),\n                    hint=\"Ensure that the panel definition for {cls} creates a subclass of WagtailAdminPageForm\".format(\n                        cls=cls.__name__\n                    ),\n                    obj=cls,\n                    id=\"wagtailadmin.E002\",\n                )\n            )\n\n    return errors\n\n\n@register(\"panels\")\ndef inline_panel_model_panels_check(app_configs, **kwargs):\n    from wagtail.models import get_page_models\n\n    errors = []\n    page_models = get_page_models()\n\n    for cls in page_models:\n        errors.extend(check_panels_in_model(cls))\n\n    # filter out duplicate errors found for the same model\n    unique_errors = []\n    for error in errors:\n        if error.msg not in [e.msg for e in unique_errors]:\n            unique_errors.append(error)\n    return unique_errors\n\n\ndef check_panels_in_model(cls, context=\"model\"):\n    \"\"\"Check panels configuration uses `panels` when `edit_handler` not in use.\"\"\"\n    from wagtail.admin.panels import InlinePanel, PanelGroup\n    from wagtail.models import Page\n\n    errors = []\n\n    if hasattr(cls, \"get_edit_handler\"):\n        # must check the InlinePanel related models\n        edit_handler = cls.get_edit_handler()\n        for tab in edit_handler.children:\n            if isinstance(tab, PanelGroup):\n                inline_panel_children = [\n                    panel for panel in tab.children if isinstance(panel, InlinePanel)\n                ]\n                for inline_panel_child in inline_panel_children:\n                    errors.extend(\n                        check_panels_in_model(\n                            inline_panel_child.db_field.related_model,\n                            context=\"InlinePanel model\",\n                        )\n                    )\n\n    if issubclass(cls, Page) or hasattr(cls, \"edit_handler\"):\n        # Pages do not need to be checked for standalone tabbed_panel usage\n        # if edit_handler is used on any model, assume config is correct\n        return errors\n\n    tabbed_panels = [\n        \"content_panels\",\n        \"promote_panels\",\n        \"settings_panels\",\n    ]\n\n    for panel_name in tabbed_panels:\n        class_name = cls.__name__\n        if not hasattr(cls, panel_name):\n            continue\n\n        panel_name_short = panel_name.replace(\"_panels\", \"\").title()\n        error_title = \"{}.{} will have no effect on {} editing\".format(\n            class_name, panel_name, context\n        )\n\n        if \"InlinePanel\" in context:\n            error_hint = \"\"\"Ensure that {} uses `panels` instead of `{}`.\nThere are no tabs on non-Page model editing within InlinePanels.\"\"\".format(\n                class_name, panel_name\n            )\n        else:\n            error_hint = \"\"\"Ensure that {} uses `panels` instead of `{}`\\\nor set up an `edit_handler` if you want a tabbed editing interface.\nThere are no default tabs on non-Page models so there will be no \\\n{} tab for the {} to render in.\"\"\".format(\n                class_name, panel_name, panel_name_short, panel_name\n            )\n\n        error = Warning(error_title, hint=error_hint, obj=cls, id=\"wagtailadmin.W002\")\n\n        errors.append(error)\n\n    return errors\n\n\n@register(\"wagtailadmin_base_url\")\ndef wagtail_admin_base_url_check(app_configs, **kwargs):\n    from django.conf import settings\n\n    errors = []\n\n    if getattr(settings, \"WAGTAILADMIN_BASE_URL\", None) is None:\n        errors.append(\n            Warning(\n                \"The WAGTAILADMIN_BASE_URL setting is not defined\",\n                hint=\"This should be the base URL used to access the Wagtail admin site. \"\n                \"Without this, URLs in notification emails will not display correctly.\",\n                id=\"wagtailadmin.W003\",\n            )\n        )\n\n    return errors\n\n\n@register(\"file_overwrite\")\ndef file_overwrite_check(app_configs, **kwargs):\n    from django import VERSION as DJANGO_VERSION\n    from django.conf import settings\n\n    if DJANGO_VERSION >= (5, 1):\n        file_storage = getattr(settings, \"STORAGES\")[\"default\"][\"BACKEND\"]\n    else:\n        try:\n            file_storage = getattr(settings, \"STORAGES\")[\"default\"][\"BACKEND\"]\n        except AttributeError:\n            file_storage = getattr(settings, \"DEFAULT_FILE_STORAGE\", None)\n\n    errors = []\n\n    if file_storage == \"storages.backends.s3boto3.S3Boto3Storage\" and getattr(\n        settings, \"AWS_S3_FILE_OVERWRITE\", True\n    ):\n        errors.append(\n            Warning(\n                \"The AWS_S3_FILE_OVERWRITE setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n    if file_storage == \"storages.backends.azure_storage.AzureStorage\" and getattr(\n        settings, \"AZURE_OVERWRITE_FILES\", False\n    ):\n        errors.append(\n            Warning(\n                \"The AZURE_OVERWRITE_FILES setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n    if file_storage == \"storages.backends.gcloud.GoogleCloudStorage\" and getattr(\n        settings, \"GS_FILE_OVERWRITE\", True\n    ):\n        errors.append(\n            Warning(\n                \"The GS_FILE_OVERWRITE setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n\n    return errors\n", "path": "wagtail/admin/checks.py"}], "after_files": [{"content": "import os\n\nfrom django.core.checks import Error, Tags, Warning, register\n\n\n@register(\"staticfiles\")\ndef css_install_check(app_configs, **kwargs):\n    errors = []\n\n    css_path = os.path.join(\n        os.path.dirname(__file__), \"static\", \"wagtailadmin\", \"css\", \"core.css\"\n    )\n\n    if not os.path.isfile(css_path):\n        error_hint = (\n            \"\"\"\n            Most likely you are running a development (non-packaged) copy of\n            Wagtail and have not built the static assets -\n            see https://docs.wagtail.org/en/latest/contributing/developing.html\n\n            File not found: %s\n        \"\"\"\n            % css_path\n        )\n\n        errors.append(\n            Warning(\n                \"CSS for the Wagtail admin is missing\",\n                hint=error_hint,\n                id=\"wagtailadmin.W001\",\n            )\n        )\n    return errors\n\n\n@register(Tags.admin)\ndef base_form_class_check(app_configs, **kwargs):\n    from wagtail.admin.forms import WagtailAdminPageForm\n    from wagtail.models import get_page_models\n\n    errors = []\n\n    for cls in get_page_models():\n        if not issubclass(cls.base_form_class, WagtailAdminPageForm):\n            errors.append(\n                Error(\n                    \"{}.base_form_class does not extend WagtailAdminPageForm\".format(\n                        cls.__name__\n                    ),\n                    hint=\"Ensure that {}.{} extends WagtailAdminPageForm\".format(\n                        cls.base_form_class.__module__, cls.base_form_class.__name__\n                    ),\n                    obj=cls,\n                    id=\"wagtailadmin.E001\",\n                )\n            )\n\n    return errors\n\n\n@register(Tags.admin)\ndef get_form_class_check(app_configs, **kwargs):\n    from wagtail.admin.forms import WagtailAdminPageForm\n    from wagtail.models import get_page_models\n\n    errors = []\n\n    for cls in get_page_models():\n        edit_handler = cls.get_edit_handler()\n        if not issubclass(edit_handler.get_form_class(), WagtailAdminPageForm):\n            errors.append(\n                Error(\n                    \"{cls}.get_edit_handler().get_form_class() does not extend WagtailAdminPageForm\".format(\n                        cls=cls.__name__\n                    ),\n                    hint=\"Ensure that the panel definition for {cls} creates a subclass of WagtailAdminPageForm\".format(\n                        cls=cls.__name__\n                    ),\n                    obj=cls,\n                    id=\"wagtailadmin.E002\",\n                )\n            )\n\n    return errors\n\n\n@register(\"panels\")\ndef inline_panel_model_panels_check(app_configs, **kwargs):\n    from wagtail.models import get_page_models\n\n    errors = []\n    page_models = get_page_models()\n\n    for cls in page_models:\n        errors.extend(check_panels_in_model(cls))\n\n    # filter out duplicate errors found for the same model\n    unique_errors = []\n    for error in errors:\n        if error.msg not in [e.msg for e in unique_errors]:\n            unique_errors.append(error)\n    return unique_errors\n\n\ndef check_panels_in_model(cls, context=\"model\"):\n    \"\"\"Check panels configuration uses `panels` when `edit_handler` not in use.\"\"\"\n    from wagtail.admin.panels import InlinePanel, PanelGroup\n    from wagtail.models import Page\n\n    errors = []\n\n    if hasattr(cls, \"get_edit_handler\"):\n        # must check the InlinePanel related models\n        edit_handler = cls.get_edit_handler()\n        for tab in edit_handler.children:\n            if isinstance(tab, PanelGroup):\n                inline_panel_children = [\n                    panel for panel in tab.children if isinstance(panel, InlinePanel)\n                ]\n                for inline_panel_child in inline_panel_children:\n                    errors.extend(\n                        check_panels_in_model(\n                            inline_panel_child.db_field.related_model,\n                            context=\"InlinePanel model\",\n                        )\n                    )\n\n    if issubclass(cls, Page) or hasattr(cls, \"edit_handler\"):\n        # Pages do not need to be checked for standalone tabbed_panel usage\n        # if edit_handler is used on any model, assume config is correct\n        return errors\n\n    tabbed_panels = [\n        \"content_panels\",\n        \"promote_panels\",\n        \"settings_panels\",\n    ]\n\n    for panel_name in tabbed_panels:\n        class_name = cls.__name__\n        if not hasattr(cls, panel_name):\n            continue\n\n        panel_name_short = panel_name.replace(\"_panels\", \"\").title()\n        error_title = \"{}.{} will have no effect on {} editing\".format(\n            class_name, panel_name, context\n        )\n\n        if \"InlinePanel\" in context:\n            error_hint = \"\"\"Ensure that {} uses `panels` instead of `{}`.\nThere are no tabs on non-Page model editing within InlinePanels.\"\"\".format(\n                class_name, panel_name\n            )\n        else:\n            error_hint = \"\"\"Ensure that {} uses `panels` instead of `{}`\\\nor set up an `edit_handler` if you want a tabbed editing interface.\nThere are no default tabs on non-Page models so there will be no \\\n{} tab for the {} to render in.\"\"\".format(\n                class_name, panel_name, panel_name_short, panel_name\n            )\n\n        error = Warning(error_title, hint=error_hint, obj=cls, id=\"wagtailadmin.W002\")\n\n        errors.append(error)\n\n    return errors\n\n\n@register(\"wagtailadmin_base_url\")\ndef wagtail_admin_base_url_check(app_configs, **kwargs):\n    from django.conf import settings\n\n    errors = []\n\n    if getattr(settings, \"WAGTAILADMIN_BASE_URL\", None) is None:\n        errors.append(\n            Warning(\n                \"The WAGTAILADMIN_BASE_URL setting is not defined\",\n                hint=\"This should be the base URL used to access the Wagtail admin site. \"\n                \"Without this, URLs in notification emails will not display correctly.\",\n                id=\"wagtailadmin.W003\",\n            )\n        )\n\n    return errors\n\n\n@register(\"file_overwrite\")\ndef file_overwrite_check(app_configs, **kwargs):\n    from django import VERSION as DJANGO_VERSION\n    from django.conf import settings\n\n    if DJANGO_VERSION >= (5, 1):\n        file_storage = getattr(settings, \"STORAGES\")[\"default\"][\"BACKEND\"]\n    else:\n        try:\n            file_storage = getattr(settings, \"STORAGES\")[\"default\"][\"BACKEND\"]\n        except AttributeError:\n            file_storage = getattr(settings, \"DEFAULT_FILE_STORAGE\", None)\n\n    errors = []\n\n    if file_storage == \"storages.backends.s3boto3.S3Boto3Storage\" and getattr(\n        settings, \"AWS_S3_FILE_OVERWRITE\", True\n    ):\n        errors.append(\n            Warning(\n                \"The AWS_S3_FILE_OVERWRITE setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n    if file_storage == \"storages.backends.azure_storage.AzureStorage\" and getattr(\n        settings, \"AZURE_OVERWRITE_FILES\", False\n    ):\n        errors.append(\n            Warning(\n                \"The AZURE_OVERWRITE_FILES setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n    if file_storage == \"storages.backends.gcloud.GoogleCloudStorage\" and getattr(\n        settings, \"GS_FILE_OVERWRITE\", True\n    ):\n        errors.append(\n            Warning(\n                \"The GS_FILE_OVERWRITE setting is set to True\",\n                hint=\"This should be set to False. The incorrect setting can cause documents and \"\n                \"other user-uploaded files to be silently overwritten or deleted.\",\n                id=\"wagtailadmin.W004\",\n            )\n        )\n\n    return errors\n\n\n@register(\"datetime_format\")\ndef datetime_format_check(app_configs, **kwargs):\n    \"\"\"\n    If L10N is enabled, check if WAGTAIL_* formats are compatible with Django input formats.\n    See https://docs.djangoproject.com/en/stable/topics/i18n/formatting/#creating-custom-format-files\n    See https://docs.wagtail.org/en/stable/reference/settings.html#wagtail-date-format-wagtail-datetime-format-wagtail-time-format\n    \"\"\"\n\n    from django.conf import settings\n    from django.utils import formats, translation\n\n    errors = []\n\n    if not getattr(settings, \"USE_L10N\", False):\n        return errors\n\n    formats.FORMAT_SETTINGS = formats.FORMAT_SETTINGS.union(\n        [\n            \"WAGTAIL_DATE_FORMAT\",\n            \"WAGTAIL_DATETIME_FORMAT\",\n            \"WAGTAIL_TIME_FORMAT\",\n        ]\n    )\n\n    for code, label in settings.LANGUAGES:\n        with translation.override(code):\n            for wagtail_format, django_formats in [\n                (\"WAGTAIL_DATE_FORMAT\", \"DATE_INPUT_FORMATS\"),\n                (\"WAGTAIL_DATETIME_FORMAT\", \"DATETIME_INPUT_FORMATS\"),\n                (\"WAGTAIL_TIME_FORMAT\", \"TIME_INPUT_FORMATS\"),\n            ]:\n                wagtail_format_value = getattr(settings, wagtail_format, None)\n                django_formats_value = getattr(settings, django_formats, None)\n\n                if wagtail_format_value is None:\n                    # Skip the iteration if wagtail_format is not present\n                    continue\n\n                input_format = formats.get_format_lazy(wagtail_format_value)\n                input_formats = formats.get_format_lazy(django_formats_value)\n                if str(input_format) not in str(input_formats):\n                    errors.append(\n                        Error(\n                            \"Configuration error\",\n                            hint=f\"{wagtail_format} {input_format} must be in {django_formats} for language {label} ({code}).\",\n                        )\n                    )\n\n    return errors\n", "path": "wagtail/admin/checks.py"}]}