Wagtail in Bedrock: main groundwork (#14250)

* Allow disabling Markus when DEBUG=True (default: keep it enabled)

* Add Wagtail 5.2 LTS as a dependency

* Hook in Wagtail Admin, while also keeping jinja-template rendering happy

* Support user-uploaded images into the CMS, both with local and cloud storage options

Of course, the cloud storage option is the only one we'll use when deployed.

Note that this also disables CSP for any routes inside the Wagtail admin
(but not pages rendered by Wagtail)

* Drop in wagtail-localize, ready for i18n/l10n

Also fix up some test regressions as a result of this change, including
changing how Careers renders a custom 404-page message

* Lay in intial 'cms' app as home for our Wagtail-related modelling.

* Support detection of CMS-based pages so that we don't falsely redirect away from pages managed by wagtail-localize

* Wrap simple CMS test page in a Protocol-based base template to confirm we load the right strings and get the lang picker

* Ensure that pages fall back (in their enriety) if we don't have a page with the matching lang code in the CMS

* Exclude the cms-admin path from the sitemap - doesn't need to be discoverable

* Remove now-redundant print statement from a data migration

* Add tests to show locales from page models are used as translations for pages

* Add tests to show that pages with restrictions (e.g. passwords) should not be cached downstream

* Add tests for StructuralPage, confirming it redirects to its parent if accessed directly

* Expand test coverage to include serve_preview for our base page model

* Fixup accidentally-commented-out app in INSTALLED_APPS

Co-authored-by: Ryan Johnson <escattone@gmail.com>

* Improve comment related to local GCS credentials, clarifying who will/won't need them and why

* Disable use of Gravatar URLs for Wagtail users

Low benefit to us, because they need CSP tweaks and also would need scrubbing before the DB export.

* Fix labelling of Wagtail's homepage

* We don't want wagtailforms enabled in our setup: public bedrock is read only

* Back out hack to 404.html for careers-related 404 -- unnecessary following i18n/routing refactor

* Back out unnecessary follow=True on the 404 test

* Ensure that demos run migrations on their local DB, so that any new Wagtail tables get made ASAP, preventing 500s

* Add a fake spec for WAGTAIL_CONTENT_LANGUAGES in Pocket mode, so that it'll boot.

We won't be using wagtail for Pocket mode

* Rename MEDIA_URL from user-media to custom-media, to make it easier to grasp

---------

Co-authored-by: Ryan Johnson <escattone@gmail.com>
This commit is contained in:
Steve Jalim 2024-05-20 10:55:49 +01:00 коммит произвёл GitHub
Родитель 6a4c597849
Коммит 920d418757
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: B5690EEEBB952194
31 изменённых файлов: 1522 добавлений и 133 удалений

Просмотреть файл

@ -4,3 +4,16 @@ ALLOWED_HOSTS=*
SWITCH_NEWSLETTER_MAINTENANCE_MODE=False
CSP_DEFAULT_SRC=*.allizom.org
CONTENT_CARDS_URL=https://www-dev.allizom.org/media/
WAGTAIL_ENABLE_ADMIN=True
# By default, local dev builds store CMS-uploaded media on the local system. If
# you need to enable cloud storage for CMS media (likely only needed to debug or
# test that behaviour), you'll need service-account credentials which you
# must save locally in /path/to/bedrock/local-credentials/ (which is gitignored)
# Here's how to get those credentials:
# https://django-storages.readthedocs.io/en/latest/backends/gcloud.html
# GS_BUCKET_NAME="custom-media-bucket-name-here"
# GS_PROJECT_ID="meao-stevejalim-dev-sandbox"
# # export this before starting the django runserver:
# # GOOGLE_APPLICATION_CREDENTIALS="./local-credentials/name-of-credentials-file.json"

2
.gitignore поставляемый
Просмотреть файл

@ -61,3 +61,5 @@ Thumbs.db
tmp/*
venv
tests/unit/dist/
/custom-media
/local-credentials/*.json

Просмотреть файл

@ -39,10 +39,12 @@ class PositionTests(TestCase):
self.assertEqual(response.status_code, 200)
self.assertEqual(response.context["position"].job_id, job_id_2)
def test_position_view_404_uses_custom_template(self):
def test_position_view_404_has_appropriate_wording(self):
url = reverse("careers.position", kwargs={"job_id": "aabbccdd", "source": "gh"})
response = self.client.get(url, follow=True)
self.assertEqual(response.status_code, 404)
self.assertTrue("<title>404: Job Not Found</title>" in str(response.content))
self.assertTrue(b"Sorry, we can\xe2\x80\x99t find that job posting" in response.content)
self.assertTemplateUsed(response, "careers/404.html")

3
bedrock/cms/__init__.py Normal file
Просмотреть файл

@ -0,0 +1,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

10
bedrock/cms/apps.py Normal file
Просмотреть файл

@ -0,0 +1,10 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from django.apps import AppConfig
class CmsConfig(AppConfig):
default_auto_field = "django.db.models.BigAutoField"
name = "bedrock.cms"

Просмотреть файл

@ -0,0 +1,62 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# Generated by Django 3.2.23 on 2024-02-20 10:58
import django.db.models.deletion
from django.db import migrations, models
import wagtail.fields
class Migration(migrations.Migration):
initial = True
dependencies = [
("wagtailcore", "0089_log_entry_data_json_null_to_object"),
]
operations = [
migrations.CreateModel(
name="SimpleRichTextPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
("content", wagtail.fields.RichTextField(blank=True)),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
migrations.CreateModel(
name="StructuralPage",
fields=[
(
"page_ptr",
models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="wagtailcore.page",
),
),
],
options={
"abstract": False,
},
bases=("wagtailcore.page",),
),
]

Просмотреть файл

@ -0,0 +1,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

124
bedrock/cms/models.py Normal file
Просмотреть файл

@ -0,0 +1,124 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from django.conf import settings
from django.shortcuts import redirect
from django.utils.cache import add_never_cache_headers
from django.utils.decorators import method_decorator
from django.views.decorators.cache import never_cache
from wagtail.admin.panels import FieldPanel
from wagtail.fields import RichTextField
from wagtail.models import Page as WagtailBasePage
from lib import l10n_utils
@method_decorator(never_cache, name="serve_password_required_response")
class AbstractBedrockCMSPage(WagtailBasePage):
"""Base page class for all Wagtail pages within Bedrock
Things we do to in particular are:
* Use our l10n_utils.render() method so that templates can use Fluent string
* Ensure private pages are not cached:
By default, Wagtail is unopinionated about cache-control headers,
so we need to be sure that pages with acecss restrictions are _not_
cached anywhere in a shared resource (e.g. the CDN)
Taking our lead from the relevant Wagtail issue
https://github.com/wagtail/wagtail/issues/5072#issuecomment-949397013, we:
1) Override the default `serve()` method with cache-control settings
for pages with view restrictions.
2) Apply `never_cache` headers to the `wagtail.Page` class's
`serve_password_required_response` method, via the @method_decorator above
"""
class Meta:
abstract = True
def _patch_request_for_bedrock(self, request):
# Add hints that help us integrate CMS pages with core Bedrock logic
request.is_cms_page = True
request._locales_available_via_cms = [self.locale.language_code] + [x.locale.language_code for x in self.get_translations()]
return request
def _render_with_fluent_string_support(self, request, *args, **kwargs):
# Normally, Wagtail's serve() returns a TemplateResponse, so we
# can swap that for our Fluent-compatible rendering method
template = self.get_template(request, *args, **kwargs)
context = self.get_context(request, *args, **kwargs)
# We shouldn't need to spec any special ftl_files param for render()
# here because the global spec is in settings.FLUENT_DEFAULT_FILES
return l10n_utils.render(request, template, context)
def serve(self, request, *args, **kwargs):
# Need to replicate behaviour in https://github.com/wagtail/wagtail/blob/stable/5.2.x/wagtail/models/__init__.py#L1928
request.is_preview = False
request = self._patch_request_for_bedrock(request)
response = self._render_with_fluent_string_support(request, *args, **kwargs)
if len(self.get_view_restrictions()):
add_never_cache_headers(response)
return response
def serve_preview(self, request, *args, **kwargs):
request = self._patch_request_for_bedrock(request)
return self._render_with_fluent_string_support(request, *args, **kwargs)
class StructuralPage(AbstractBedrockCMSPage):
"""A page used to create a folder-like structure within a page tree,
under/in which other pages live.
Not directly viewable - will redirect to its parent page if called"""
# There are minimal fields on this model - only exactly what we need
# `title` and `slug` fields come from Page->AbstractBedrockCMSPage
is_structural_page = True
# TO COME: guard rails on page heirarchy
# subpage_types = []
settings_panels = WagtailBasePage.settings_panels + [
FieldPanel("show_in_menus"),
]
content_panels = [
FieldPanel("title"),
FieldPanel("slug"),
]
promote_panels = []
def serve_preview(self, request, mode_name="irrelevant"):
# Regardless of mode_name, always redirect to the parent page
return redirect(self.get_parent().get_full_url())
def serve(self, request):
return redirect(self.get_parent().get_full_url())
class SimpleRichTextPage(AbstractBedrockCMSPage):
"""Simple page that renders a rich-text field, using our broadest set of
allowed rich-text features.
Not intended to be commonly used, this is more a very simple reference
implementation.
"""
# 1. Define model fields
# `title` and `slug` fields come from Page->AbstractBedrockCMSPage
content = RichTextField(
blank=True,
features=settings.WAGTAIL_RICHEXT_FEATURES_FULL,
)
# Note there are no other custom fields here
# 2. Define editing UI by extending the default field list
content_panels = AbstractBedrockCMSPage.content_panels + [
FieldPanel("content"),
]
# 3. Specify HTML Template:
# If not set, Wagtail will automatically choose a name for the template
# in the format `<app_label>/<model_name_in_snake_case>.html`
template = "cms/simple_rich_text_page.html"

Просмотреть файл

@ -0,0 +1,20 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{% extends "base-protocol-mozilla.html" %}
{% block sub_navigation %}
{% endblock %}
{% block site_css %}
{{ super() }}
{{ css_bundle('cms-base') }}
{% endblock %}
{% block js %}
{% endblock %}

Просмотреть файл

@ -0,0 +1,25 @@
{#
This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this
file, You can obtain one at https://mozilla.org/MPL/2.0/.
#}
{% extends "cms/base-protocol.html" %}
{% block page_title_prefix %}{{page.title}}{% endblock %}
{% block content %}
<div class="mzp-l-content">
<header>
<h1 class="mzp-c-article-title" itemprop="name">
{{ page.title }}
</h1>
</header>
<div itemprop="articleBody" class="mzp-c-article">
{{page.content|richtext}}
</div>
</div>
{% endblock %}

Просмотреть файл

@ -0,0 +1,3 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.

Просмотреть файл

@ -0,0 +1,36 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import pytest
import wagtail_factories
from bedrock.cms.tests.factories import LocaleFactory, SimpleRichTextPageFactory
@pytest.fixture
def minimal_site(
client,
top_level_page=None,
):
# Boostraps a minimal site with a root page at / and one child page at /test-page/
if top_level_page is None:
top_level_page = SimpleRichTextPageFactory(
slug="root_page", # this doesn't get shown
)
site = wagtail_factories.SiteFactory(
root_page=top_level_page,
hostname=client._base_environ()["SERVER_NAME"],
)
LocaleFactory(language_code="fr")
SimpleRichTextPageFactory(
slug="test-page",
parent=top_level_page,
title="Test Page",
)
return site

Просмотреть файл

@ -0,0 +1,28 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
import factory
import wagtail_factories
from wagtail import models as wagtail_models
from bedrock.cms import models
class SimpleRichTextPageFactory(wagtail_factories.PageFactory):
title = "Test SimpleRichTextPage"
live = True
slug = "homepage"
class Meta:
model = models.SimpleRichTextPage
class LocaleFactory(factory.django.DjangoModelFactory):
class Meta:
model = wagtail_models.Locale
class StructuralPageFactory(wagtail_factories.PageFactory):
class Meta:
model = models.StructuralPage

Просмотреть файл

@ -0,0 +1,69 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
from unittest import mock
import pytest
from bedrock.cms.models import AbstractBedrockCMSPage, SimpleRichTextPage
from bedrock.cms.tests.factories import StructuralPageFactory
pytestmark = [
pytest.mark.django_db,
]
@mock.patch("bedrock.cms.models.SimpleRichTextPage.get_view_restrictions")
@pytest.mark.parametrize(
"fake_restrictions, expected_headers",
(
([], "max-age=600"),
([mock.Mock()], "max-age=0, no-cache, no-store, must-revalidate, private"),
),
ids=[
"Default, unrestricted-page behaviour",
"Restricted-page behaviour",
],
)
def test_cache_control_headers_on_pages_with_view_restrictions(
mock_get_view_restrictions,
fake_restrictions,
expected_headers,
client,
minimal_site,
):
mock_get_view_restrictions.return_value = fake_restrictions
page = SimpleRichTextPage.objects.last() # made by the minimal_site fixture
# Confirm we're using the base page
assert isinstance(page, AbstractBedrockCMSPage)
_relative_url = page.relative_url(minimal_site)
assert _relative_url == "/en-US/test-page/"
response = client.get(_relative_url)
assert response.get("Cache-Control") == expected_headers
def test_StructuralPage_serve_methods(
minimal_site,
rf,
):
"Show that structural pages redirect to their parent rather than serve anything"
root_page = SimpleRichTextPage.objects.first()
sp = StructuralPageFactory(parent=root_page, slug="folder-page")
sp.save()
_relative_url = sp.relative_url(minimal_site)
assert _relative_url == "/en-US/folder-page/"
request = rf.get(_relative_url)
live_result = sp.serve(request)
assert live_result.headers["location"] == root_page.url
preview_result = sp.serve_preview(request)
assert preview_result.headers["location"] == root_page.url

Просмотреть файл

@ -0,0 +1,113 @@
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at https://mozilla.org/MPL/2.0/.
# Test the way Wagtail pages are handled by lib.l10n_utils.render
# The pytest fixtures used to run these tests are defined in bedrock/cms/tests/conftest.py
from django.conf import settings
import pytest
from wagtail.models import Locale, Page
from lib import l10n_utils
pytestmark = [
pytest.mark.django_db,
]
def test_locale_redirect_logic_is_skipped_for_cms_page(
minimal_site,
mocker,
rf,
):
"Confirm that CMS pages with the lang code in the path get served fine"
mocker.patch("lib.l10n_utils.redirect_to_locale")
mocker.patch("lib.l10n_utils.redirect_to_best_locale")
page = Page.objects.last().specific
_relative_url = page.relative_url(minimal_site)
assert _relative_url == "/en-US/test-page/"
request = rf.get(_relative_url)
resp = page.serve(request)
assert "Test Page" in str(resp.content)
l10n_utils.redirect_to_locale.assert_not_called()
l10n_utils.redirect_to_best_locale.assert_not_called()
def test_locale_redirect_will_work_for_cms_pages(
minimal_site,
mocker,
rf,
):
"""Confirm that CMS pages with the lang code in the path get
redirected before being served fine"""
redirect_to_locale_spy = mocker.spy(l10n_utils, "redirect_to_locale")
redirect_to_best_locale_spy = mocker.spy(l10n_utils, "redirect_to_best_locale")
page = Page.objects.last().specific
assert page.url_path == "/test-page/" # i.e., no lang code
request = rf.get(page.url_path)
resp = page.serve(request)
assert resp.headers["location"] == "/en-US/test-page/"
assert redirect_to_locale_spy.call_count == 1
assert redirect_to_best_locale_spy.call_count == 0
def test_locale_redirect_will_work_for_cms_pages__default_locale_not_available(
minimal_site,
mocker,
rf,
):
redirect_to_locale_spy = mocker.spy(l10n_utils, "redirect_to_locale")
redirect_to_best_locale_spy = mocker.spy(l10n_utils, "redirect_to_best_locale")
page = Page.objects.last().specific
fr_locale = Locale.objects.get(language_code="fr")
assert settings.LANGUAGE_CODE != fr_locale.language_code
page.locale = fr_locale
page.save()
assert page.url_path == "/test-page/" # i.e., no lang code
request = rf.get(page.url_path)
resp = page.serve(request)
assert resp.headers["location"] == "/fr/test-page/" # NB not en-US
assert redirect_to_locale_spy.call_count == 1
assert redirect_to_best_locale_spy.call_count == 1
@pytest.mark.parametrize("serving_method", ("serve", "serve_preview"))
def test_locales_are_drawn_from_page_translations(minimal_site, rf, serving_method):
assert Locale.objects.count() == 2 # en-US and fr
fr_locale = Locale.objects.get(language_code="fr")
page = Page.objects.last().specific
fr_page = page.copy_for_translation(fr_locale)
fr_page.title = "FR test page"
fr_page.save()
assert fr_page.locale.language_code == "fr"
_relative_url = page.relative_url(minimal_site)
assert _relative_url == "/en-US/test-page/"
request = rf.get(_relative_url)
resp = getattr(page, serving_method)(request)
page_content = str(resp.content)
assert "Test Page" in page_content
assert '<option lang="en-US" value="en-US" selected>English</option>' in page_content
assert '<option lang="fr" value="fr">Français</option>'.encode("utf-8") in resp.content
assert '<option lang="en-GB" value="en-US">English (British) </option>' not in page_content

Просмотреть файл

@ -113,8 +113,6 @@ def switch_image_urls_to_local(apps, schema_editor):
if page.slug != "unknown":
_print("No changes needed to page body\n")
_print("All done.")
class Migration(migrations.Migration):
dependencies = [

Просмотреть файл

@ -187,7 +187,7 @@ class TestWebvisionDocView(TestCase):
self.assertEqual(resp.context["doc"], {"title": "<h1>Summary</h1>"})
def test_missing_doc_is_404(self):
resp = self.client.get(reverse("mozorg.about.webvision.full"))
resp = self.client.get(reverse("mozorg.about.webvision.full"), follow=True)
self.assertEqual(resp.status_code, 404)

Просмотреть файл

@ -15,13 +15,8 @@ from .base import * # noqa: F403, F405
# 1. OPERATION MODE SELECTION and specific config
# Which site do we want Bedrock to serve?
POCKET_SITE_MODE = "Pocket"
MOZORG_SITE_MODE = "Mozorg"
site_mode = config("SITE_MODE", default=MOZORG_SITE_MODE)
IS_POCKET_MODE = site_mode == POCKET_SITE_MODE
IS_MOZORG_MODE = not IS_POCKET_MODE
# IS_POCKET_MODE and IS_MOZORG_MODE are set in settings.base
if IS_POCKET_MODE:
ROOT_URLCONF = "bedrock.urls.pocket_mode"

Просмотреть файл

@ -56,6 +56,12 @@ DEV = config("DEV", parser=bool, default="false")
PROD = config("PROD", parser=bool, default="false")
DEBUG = config("DEBUG", parser=bool, default="false")
site_mode = config("SITE_MODE", default="Mozorg")
IS_POCKET_MODE = site_mode == "Pocket"
IS_MOZORG_MODE = not IS_POCKET_MODE
DATABASES = {
"default": {
"ENGINE": "django.db.backends.sqlite3",
@ -108,6 +114,10 @@ TIME_ZONE = config("TIME_ZONE", default="America/Los_Angeles")
# to load the internationalization machinery.
USE_I18N = True
# If you set this to False, Django will not format dates, numbers and
# calendars according to the current locale
USE_L10N = True
USE_TZ = True
USE_ETAGS = config("USE_ETAGS", default=str(not DEBUG), parser=bool)
@ -304,6 +314,11 @@ EXCLUDE_EDIT_TEMPLATES = [
"security/product-advisories.html",
"security/known-vulnerabilities.html",
]
# Also allow entire directories to be skipped
EXCLUDE_EDIT_TEMPLATES_DIRECTORIES = [
"cms",
]
IGNORE_LANG_DIRS = [
".git",
"configs",
@ -466,6 +481,7 @@ NOINDEX_URLS = [
r"^(404|500)/",
r"^firefox/welcome/",
r"^contribute/(embed|event)/",
r"^cms-admin/",
r"^firefox/set-as-default/thanks/",
r"^firefox/unsupported/",
r"^firefox/(sms-)?send-to-device-post",
@ -536,12 +552,15 @@ STORAGES = {
},
}
MEDIA_URL = config("MEDIA_URL", default="/user-media/")
MEDIA_ROOT = config("MEDIA_ROOT", default=path("media"))
MEDIA_URL = config("MEDIA_URL", default="/custom-media/")
MEDIA_ROOT = config("MEDIA_ROOT", default=path("custom-media"))
STATIC_URL = config("STATIC_URL", default="/media/")
STATIC_ROOT = config("STATIC_ROOT", default=path("static"))
STATICFILES_FINDERS = ("django.contrib.staticfiles.finders.FileSystemFinder",)
STATICFILES_DIRS = (path("assets"),)
STATICFILES_FINDERS = [
"django.contrib.staticfiles.finders.FileSystemFinder",
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
]
if DEBUG:
STATICFILES_DIRS += (path("media"),)
@ -592,6 +611,7 @@ BASIC_AUTH_CREDS = config("BASIC_AUTH_CREDS", default="")
ENABLE_METRICS_VIEW_TIMING_MIDDLEWARE = config("ENABLE_METRICS_VIEW_TIMING_MIDDLEWARE", default="false", parser=bool)
MIDDLEWARE = [
# IMPORTANT: this may be extended later in this file or via settings/__init__.py
"allow_cidr.middleware.AllowCIDRMiddleware",
"django.middleware.security.SecurityMiddleware",
"whitenoise.middleware.WhiteNoiseMiddleware",
@ -610,7 +630,9 @@ MIDDLEWARE = [
"bedrock.base.middleware.MetricsViewTimingMiddleware",
"django.middleware.common.CommonMiddleware",
"django.contrib.messages.middleware.MessageMiddleware",
"django.middleware.clickjacking.XFrameOptionsMiddleware",
"bedrock.mozorg.middleware.CacheMiddleware",
"wagtail.contrib.redirects.middleware.RedirectMiddleware",
]
ENABLE_CSP_MIDDLEWARE = config("ENABLE_CSP_MIDDLEWARE", default="true", parser=bool)
@ -619,6 +641,7 @@ if ENABLE_CSP_MIDDLEWARE:
INSTALLED_APPS = [
# Django contrib apps
"django.contrib.sessions",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.staticfiles",
@ -631,8 +654,24 @@ INSTALLED_APPS = [
"django_jinja_markdown",
"django_jinja",
"watchman",
# Wagtail CMS and related, necessary apps
"wagtail.contrib.redirects",
"wagtail.documents",
"wagtail.embeds",
"wagtail.sites",
"wagtail.users",
"wagtail.snippets",
"wagtail.images",
"wagtail_localize",
"wagtail_localize.locales", # This replaces "wagtail.locales"
"wagtail.search",
"wagtail.admin",
"wagtail",
"modelcluster",
"taggit",
# Local apps
"bedrock.base",
"bedrock.cms", # Wagtail-based CMS bases
"bedrock.firefox",
"bedrock.foundation",
"bedrock.legal",
@ -703,10 +742,16 @@ WATCHMAN_CHECKS = (
"watchman.checks.databases",
)
def _is_bedrock_custom_app(app_name):
return app_name.startswith("bedrock.")
TEMPLATES = [
{
"BACKEND": "django_jinja.jinja2.Jinja2",
"APP_DIRS": True,
"APP_DIRS": False,
"DIRS": [f"bedrock/{name.split('.')[1]}/templates" for name in INSTALLED_APPS if _is_bedrock_custom_app(name)],
"OPTIONS": {
"match_extension": None,
"finalize": lambda x: x if x is not None else "",
@ -733,6 +778,24 @@ TEMPLATES = [
"django_jinja.builtins.extensions.StaticFilesExtension",
"django_jinja.builtins.extensions.DjangoFiltersExtension",
"django_jinja_markdown.extensions.MarkdownExtension",
"wagtail.jinja2tags.core",
"wagtail.admin.jinja2tags.userbar",
"wagtail.images.jinja2tags.images",
],
},
},
{
# Wagtail needs the standard Django template backend
# https://docs.wagtail.org/en/stable/reference/jinja2.html#configuring-django
"BACKEND": "django.template.backends.django.DjangoTemplates",
"APP_DIRS": True,
"OPTIONS": {
"context_processors": [
"django.template.context_processors.debug",
"django.template.context_processors.request",
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"wagtail.contrib.settings.context_processors.settings",
],
},
},
@ -1103,7 +1166,7 @@ SENTRY_FRONTEND_DSN = config(
)
# Statsd metrics via markus
if DEBUG:
if DEBUG and not config("DISABLE_LOCAL_MARKUS", default="False", parser=bool):
MARKUS_BACKENDS = [
{"class": "markus.backends.logging.LoggingMetrics", "options": {"logger_name": "metrics"}},
]
@ -1796,3 +1859,108 @@ VPN_SUPPORTED_LOCALES = [
RELAY_PRODUCT_URL = config(
"RELAY_PRODUCT_URL", default="https://stage.fxprivaterelay.nonprod.cloudops.mozgcp.net/" if DEV else "https://relay.firefox.com/"
)
# WAGTAIL =======================================================================================
WAGTAIL_SITE_NAME = config(
"WAGTAIL_SITE_NAME",
default="Mozilla.org",
)
# Disable use of Gravatar URLs.
# Important: if this is enabled in the future, make sure you redact the
# `wagtailusers_profile.avatar` column when exporting the DB to sqlite
WAGTAIL_GRAVATAR_PROVIDER_URL = None
WAGTAILADMIN_BASE_URL = config(
"WAGTAILADMIN_BASE_URL",
default="",
)
# We're sticking to LTS releases of Wagtail, so we don't want to be told there's a new version if that's not LTS
WAGTAIL_ENABLE_UPDATE_CHECK = False
# Custom setting (not a Wagtail core one) that we use to plug in/unplug the admin UI entirely
WAGTAIL_ENABLE_ADMIN = config(
"WAGTAIL_ENABLE_ADMIN",
default="False",
parser=bool,
)
if WAGTAIL_ENABLE_ADMIN:
# Enable Middleware essential for admin
for midddleware_spec in [
"django.middleware.csrf.CsrfViewMiddleware",
"django.contrib.auth.middleware.AuthenticationMiddleware",
"django.contrib.sessions.middleware.SessionMiddleware",
]:
MIDDLEWARE.insert(3, midddleware_spec)
SUPPORTED_NONLOCALES.append(
"cms-admin",
)
def lazy_wagtail_langs():
enabled_wagtail_langs = [
("en-US", "English"),
# TODO: expand to other locales supported by our translation vendor
# ("de", "Deutsch"),
("fr", "Français"),
# ("es", "Español"),
# ("es", "Español mexicano"),
# ("it", "Italiano"),
# more to come
]
enabled_language_codes = [x[0] for x in LANGUAGES]
retval = [wagtail_lang for wagtail_lang in enabled_wagtail_langs if wagtail_lang[0] in enabled_language_codes]
return retval
WAGTAIL_I18N_ENABLED = True
if IS_MOZORG_MODE:
WAGTAIL_CONTENT_LANGUAGES = lazy(lazy_wagtail_langs, list)()
else:
# Note: we'll never actually use this as Pocket mode won't be
# Wagtailed, but we need something valid so Pocket mode will boot up
WAGTAIL_CONTENT_LANGUAGES = [("en", "English")]
# Custom settings, not a core Wagtail ones, to scope out RichText options
WAGTAIL_RICHEXT_FEATURES_FULL = [
# https://docs.wagtail.org/en/stable/advanced_topics/customisation/page_editing_interface.html#limiting-features-in-a-rich-text-field
# Order here is the order used in the editor UI
"h2",
"h3",
"hr",
"bold",
"italic",
"strikethrough",
"code",
"blockquote",
"link",
"ol",
"ul",
]
# Storage
# If config is available, we use Google Cloud Storage, else (for local dev)
# fall back to filesytem storage
GS_BUCKET_NAME = config("GS_BUCKET_NAME", default="", parser=str)
GS_PROJECT_ID = config("GS_PROJECT_ID", default="", parser=str)
GS_OBJECT_PARAMETERS = {
"cache_control": "max-age=2592000, public, immutable",
# 2592000 == 30 days / 1 month
}
if GS_BUCKET_NAME and GS_PROJECT_ID:
DEFAULT_FILE_STORAGE = "storages.backends.gcloud.GoogleCloudStorage"
GS_DEFAULT_ACL = "publicRead"
GS_FILE_OVERWRITE = False
else:
SUPPORTED_NONLOCALES += [
"custom-media", # using local filesystem storage (for dev)
]

Просмотреть файл

@ -6,6 +6,9 @@ from django.conf import settings
from django.urls import include, path
from django.utils.module_loading import import_string
from wagtail import urls as wagtail_urls
from wagtail.admin import urls as wagtailadmin_urls
from wagtail.documents import urls as wagtaildocs_urls
from watchman import views as watchman_views
from bedrock.base import views as base_views
@ -39,6 +42,7 @@ urlpatterns += (
path("healthz/", watchman_views.ping, name="watchman.ping"),
path("readiness/", watchman_views.status, name="watchman.status"),
path("healthz-cron/", base_views.cron_health_check),
path("_documents/", include(wagtaildocs_urls)),
)
if settings.DEV:
@ -52,3 +56,26 @@ if settings.DEBUG:
path("404/", import_string(handler404)),
path("500/", import_string(handler500)),
)
if settings.WAGTAIL_ENABLE_ADMIN:
urlpatterns += (path("cms-admin/", include(wagtailadmin_urls)),)
if settings.DEFAULT_FILE_STORAGE == "django.core.files.storage.FileSystemStorage":
# Serve media files from Django itself - production won't use this
from django.urls import re_path
from django.views.static import serve
urlpatterns += (
re_path(
r"^custom-media/(?P<path>.*)$",
serve,
{"document_root": settings.MEDIA_ROOT},
),
)
# Note that statics are handled via Whitenoise's middleware
# Wagtail is the catch-all route, and it will raise a 404 if needed.
# Note that we're also using localised URLs here
urlpatterns += bedrock_i18n_patterns(
path("", include(wagtail_urls)),
)

Просмотреть файл

@ -4,7 +4,7 @@
# If you need to add a secret, please consult with SRE or MEAO backend to
# learn how to do this.
# 
# If you are looking for BOUNCER_URL or the related STUB_ATTRIBUTION_HMAC_KEY,
# If you are looking for BOUNCER_URL or the related STUB_ATTRIBUTION_HMAC_KEY,
# please note that these are set in GCP Secrets, and never set here.
ALLOWED_HOSTS: .allizom.org,.moz.works,.run.app
@ -17,6 +17,7 @@ DEBUG: "False"
DEV: "True"
GTM_CONTAINER_ID: GTM-MW3R8V
LOG_LEVEL: INFO
LOCAL_DB_UPDATE: "True"
PROD_DETAILS_STORAGE: product_details.storage.PDDatabaseStorage
RUN_SUPERVISOR: "True"
SECURE_SSL_REDIRECT: "True"

Просмотреть файл

@ -15,6 +15,7 @@ DEV: "True"
GOOGLE_ANALYTICS_ID: "UA-370613-9"
GTM_CONTAINER_ID: "GTM-P4LPJ42"
LOG_LEVEL: INFO
LOCAL_DB_UPDATE: "True"
PROD_DETAILS_STORAGE: product_details.storage.PDDatabaseStorage
RUN_SUPERVISOR: "True"
SECURE_SSL_REDIRECT: "True"

Просмотреть файл

@ -24,6 +24,9 @@ def template_source_url(template):
if template in settings.EXCLUDE_EDIT_TEMPLATES:
return None
if template.split("/")[0] in settings.EXCLUDE_EDIT_TEMPLATES_DIRECTORIES:
return None
try:
absolute_path = loader.get_template(template).template.filename
except TemplateDoesNotExist:
@ -127,6 +130,9 @@ def render(request, template, context=None, ftl_files=None, activation_files=Non
name_prefix = request.path_info.split("/", 2)[1]
non_locale_url = name_prefix in settings.SUPPORTED_NONLOCALES or request.path_info in settings.SUPPORTED_LOCALE_IGNORE
# is this a CMS page?
is_cms_page = hasattr(request, "is_cms_page") and request.is_cms_page
# Make sure we have a single template
if isinstance(template, list):
template = template[0]
@ -147,9 +153,13 @@ def render(request, template, context=None, ftl_files=None, activation_files=Non
context["template"] = template
context["template_source_url"] = template_source_url(template)
# if it's a CMS page, draw the active locales from the Page data.
# if `active_locales` is given use it as the full list of active translations
translations = []
if "active_locales" in context:
if is_cms_page and request._locales_available_via_cms:
translations = request._locales_available_via_cms
elif "active_locales" in context:
translations = context["active_locales"]
del context["active_locales"]
else:
@ -196,7 +206,7 @@ def render(request, template, context=None, ftl_files=None, activation_files=Non
except TemplateDoesNotExist:
pass
# Render originally requested/default template
# Render originally requested/default template.
return django_render(request, template, context, **kwargs)

15
media/css/cms/base.scss Normal file
Просмотреть файл

@ -0,0 +1,15 @@
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at https://mozilla.org/MPL/2.0/.
// IMPORTANT: This CSS is only for the test/temporary simple_rich_text_page.html
// template. When we use CMS-based pages in future, they'll be interwoven into
// mozorg, firefox, etc, and so can use the CSS and JS bundles for those areas
// of the site.
$font-path: '/media/protocol/fonts';
$image-path: '/media/protocol/img';
@import '~@mozilla-protocol/core/protocol/css/includes/lib';
@import '~@mozilla-protocol/core/protocol/css/components/logos/logo';
@import '~@mozilla-protocol/core/protocol/css/components/logos/logo-product-firefox';

Просмотреть файл

@ -397,31 +397,31 @@
},
{
"files": [
"css/firefox/whatsnew/whatsnew-120-na.scss"
"css/firefox/whatsnew/whatsnew-120-na.scss"
],
"name": "firefox_whatsnew_120_na"
},
{
"files": [
"css/firefox/whatsnew/whatsnew-120-eu-vpn.scss"
"css/firefox/whatsnew/whatsnew-120-eu-vpn.scss"
],
"name": "firefox_whatsnew_120_eu_vpn"
},
{
"files": [
"css/firefox/whatsnew/whatsnew-120-eu.scss"
"css/firefox/whatsnew/whatsnew-120-eu.scss"
],
"name": "firefox_whatsnew_120_eu"
},
{
"files": [
"css/firefox/whatsnew/whatsnew-121.scss"
"css/firefox/whatsnew/whatsnew-121.scss"
],
"name": "firefox_whatsnew_121"
},
{
"files": [
"css/firefox/whatsnew/whatsnew-122-eu.scss"
"css/firefox/whatsnew/whatsnew-122-eu.scss"
],
"name": "firefox_whatsnew_122_eu"
},
@ -1190,25 +1190,25 @@
"name": "careers"
},
{
"files":[
"files": [
"css/mozorg/diversity/diversity.scss"
],
"name": "diversity"
},
{
"files":[
"files": [
"css/mozorg/sustainability.scss"
],
"name": "sustainability"
},
{
"files":[
"files": [
"css/mozorg/advertising.scss"
],
"name": "mozilla-ads"
},
{
"files":[
"files": [
"css/mozorg/webvision.scss"
],
"name": "webvision"
@ -1254,6 +1254,12 @@
"css/mozorg/rise25/rise25.scss"
],
"name": "rise25"
},
{
"files": [
"css/cms/base.scss"
],
"name": "cms-base"
}
],
"js": [
@ -1316,7 +1322,7 @@
],
"name": "firefox_welcome_page15_experiment"
},
{
{
"files": [
"js/firefox/welcome/welcome16.js"
],
@ -1653,7 +1659,6 @@
{
"files": [
"js/base/mozilla-article.js"
],
"name": "basic-article"
},

Просмотреть файл

@ -22,6 +22,7 @@ responses==0.25.0
ruff==0.4.2
selenium==4.9.1 # Pinned to 4.9.1 until https://github.com/pytest-dev/pytest-selenium/issues/315 is resolved
translate-toolkit==3.12.2
wagtail-factories==4.1.0
# Related to moz-l10n-lint, used in CI
cl-ext.lang==0.1.0
compare-locales==9.0.2

Просмотреть файл

@ -4,6 +4,12 @@
#
# $ make compile-requirements
#
anyascii==0.3.2 \
--hash=sha256:3b3beef6fc43d9036d3b0529050b0c48bfad8bc960e9e562d7223cfb94fe45d4 \
--hash=sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730
# via
# -r requirements/prod.txt
# wagtail
appdirs==1.4.4 \
--hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \
--hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
@ -45,10 +51,12 @@ basket-client==1.1.0 \
--hash=sha256:3e637824891cc7ff5262d3d57dc744c265becb295edfbec30223262e5544228d \
--hash=sha256:6477d29337d4a3a8843d88e25f679a348c8a26341370c508173548da9799c19d
# via -r requirements/prod.txt
beautifulsoup4==4.12.3 \
--hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
--hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
# via -r requirements/prod.txt
beautifulsoup4==4.11.2 \
--hash=sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39 \
--hash=sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106
# via
# -r requirements/prod.txt
# wagtail
bleach[css]==6.1.0 \
--hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \
--hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6
@ -61,9 +69,9 @@ boto3==1.34.101 \
--hash=sha256:1d854b5880e185db546b4c759fcb664bf3326275064d2b44229cc217e8be9d7e \
--hash=sha256:79b93f3370ea96ce838042bc2eac0c996aee204b01e7e6452eb77abcbe697d6a
# via -r requirements/prod.txt
botocore==1.34.101 \
--hash=sha256:01f3802d25558dd7945d83884bf6885e2f84e1ff27f90b5f09614966fe18c18f \
--hash=sha256:f145e8b4b8fc9968f5eb695bdc2fcc8e675df7fbc3c56102dc1f5471be6baf35
botocore==1.34.103 \
--hash=sha256:0330d139f18f78d38127e65361859e24ebd6a8bcba184f903c01bb999a3fa431 \
--hash=sha256:5f07e2c7302c0a9f469dcd08b4ddac152e9f5888b12220242c20056255010939
# via
# -r requirements/prod.txt
# boto3
@ -76,6 +84,12 @@ braceexpand==0.1.7 \
--hash=sha256:91332d53de7828103dcae5773fb43bc34950b0c8160e35e0f44c4427a3b85014 \
--hash=sha256:e6e539bd20eaea53547472ff94f4fb5c3d3bf9d0a89388c4b56663aba765f705
# via -r requirements/dev.in
cachetools==5.3.3 \
--hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \
--hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105
# via
# -r requirements/prod.txt
# google-auth
certifi==2024.2.2 \
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
@ -412,6 +426,12 @@ datadog==0.49.1 \
# via
# -r requirements/prod.txt
# markus
defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
# via
# -r requirements/prod.txt
# willow
deprecated==1.2.14 \
--hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \
--hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3
@ -437,10 +457,19 @@ django==4.2.11 \
# django-crum
# django-csp
# django-extensions
# django-filter
# django-jinja
# django-memoize
# django-modelcluster
# django-mozilla-product-details
# django-permissionedforms
# django-storages
# django-taggit
# django-treebeard
# django-watchman
# djangorestframework
# wagtail
# wagtail-localize
django-allow-cidr==0.7.1 \
--hash=sha256:11126c5bb9df3a61ff9d97304856ba7e5b26d46c6d456709a6d9e28483bff47f \
--hash=sha256:382c5d7a9807279e3e96e4f4892b59163a2b30128c596902bf5f80e133e1ccbb
@ -461,6 +490,12 @@ django-extensions==3.2.3 \
--hash=sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a \
--hash=sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401
# via -r requirements/prod.txt
django-filter==23.5 \
--hash=sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c \
--hash=sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400
# via
# -r requirements/prod.txt
# wagtail
django-jinja==2.11.0 \
--hash=sha256:47c06d3271e6b2f27d3596278af517bfe2e19c1eb36ae1c0b1cc302d7f0259af \
--hash=sha256:cc4c72246a6e346aa0574e0c56c3e534c1a20ef47b8476f05d7287781f69a0a9
@ -478,22 +513,68 @@ django-jsonview==2.0.0 \
django-memoize==2.3.1 \
--hash=sha256:62ac4807710ecf22a7397d008d64d0f798e7230482d4b6072d916cac852a47cd
# via -r requirements/prod.txt
django-modelcluster==6.3 \
--hash=sha256:0caed8a0e889f3abb92f144670878a466ef954ffa6c4c7b9c80e6426b720a49d \
--hash=sha256:a8783d6565a0663f41cd6003ea361c3a5711e8a2a326160f1ec1eceb3e973d4f
# via
# -r requirements/prod.txt
# wagtail
django-mozilla-product-details==1.0.3 \
--hash=sha256:1d139ba01f4484f3bb43b72864ce33f249835405449e0dc940217cfa42ce5b46 \
--hash=sha256:a4aba6a68b296dffe8c1afb95d236cdbd402bd855cd49eef4d8a1a610105fd36
# via -r requirements/prod.txt
django-permissionedforms==0.1 \
--hash=sha256:4340bb20c4477fffb13b4cc5cccf9f1b1010b64f79956c291c72d2ad2ed243f8 \
--hash=sha256:d341a961a27cc77fde8cc42141c6ab55cc1f0cb886963cc2d6967b9674fa47d6
# via
# -r requirements/prod.txt
# wagtail
django-storages[google]==1.14.2 \
--hash=sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad \
--hash=sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5
# via -r requirements/prod.txt
django-taggit==4.0.0 \
--hash=sha256:4d52de9d37245a9b9f98c0ec71fdccf1d2283e38e8866d40a7ae6a3b6787a161 \
--hash=sha256:eb800dabef5f0a4e047ab0751f82cf805bc4a9e972037ef12bf519f52cd92480
# via
# -r requirements/prod.txt
# wagtail
django-treebeard==4.7.1 \
--hash=sha256:846e462904b437155f76e04907ba4e48480716855f88b898df4122bdcfbd6e98 \
--hash=sha256:995c7120153ab999898fe3043bbdcd8a0fc77cc106eb94de7350e9d02c885135
# via
# -r requirements/prod.txt
# wagtail
django-watchman==1.3.0 \
--hash=sha256:33b5fc734d689b83cb96fc17beda624ae2955f4cede0856897d990c363eac962 \
--hash=sha256:5f04300bd7fbdd63b8a883b2730ed1e4d9b0f9991133b33a1281134b81f466eb
# via -r requirements/prod.txt
djangorestframework==3.15.1 \
--hash=sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6 \
--hash=sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1
# via
# -r requirements/prod.txt
# wagtail
docutils==0.21.2 \
--hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
--hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
# via -r requirements/prod.txt
draftjs-exporter==2.1.7 \
--hash=sha256:5839cbc29d7bce2fb99837a404ca40c3a07313f2a20e2700de7ad6aa9a9a18fb \
--hash=sha256:d415a9964690a2cddb66a31ef32dd46c277e9b80434b94e39e3043188ed83e33
# via
# -r requirements/prod.txt
# wagtail
envcat==0.1.1 \
--hash=sha256:3659c6bad8f47cd3c2691d754a5659c1953480c066718c8a1d87367b03f11bc8 \
--hash=sha256:6831806d205b7b1c8456bba5d9cd7ced90f52cf2fc8cfbe234d48d3fdb91111d
# via -r requirements/prod.txt
et-xmlfile==1.1.0 \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada
# via
# -r requirements/prod.txt
# openpyxl
everett==3.3.0 \
--hash=sha256:acb7b8f3c5fc9692a8ba14fb257e4649f87bea4856e7406c2e9b6c2cab889105 \
--hash=sha256:d3ecc55cc1bdf2408ca82bc8db5a3fc588fc4c0f236a6ab9599938f41970b814
@ -501,11 +582,19 @@ everett==3.3.0 \
factory-boy==3.3.0 \
--hash=sha256:a2cdbdb63228177aa4f1c52f4b6d83fab2b8623bf602c7dedd7eb83c0f69c04c \
--hash=sha256:bc76d97d1a65bbd9842a6d722882098eb549ec8ee1081f9fb2e8ff29f0c300f1
# via -r requirements/dev.in
# via
# -r requirements/dev.in
# wagtail-factories
faker==25.1.0 \
--hash=sha256:2107618cf306bb188dcfea3e5cfd94aa92d65c7293a2437c1e96a99c83274755 \
--hash=sha256:24e28dce0b89683bb9e017e042b971c8c4909cff551b6d46f1e207674c7c2526
# via factory-boy
filetype==1.2.0 \
--hash=sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb \
--hash=sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25
# via
# -r requirements/prod.txt
# willow
fluent-runtime==0.4.0 \
--hash=sha256:51fd02582c2363e1106d7051642967a1b7f406dd9c317bd4600a73ede40c5146 \
--hash=sha256:cb5ef96a58a3f67acaaca046d1201d202a1ebf2823e5e664370f359bae20574d
@ -568,6 +657,118 @@ glean-parser==10.0.3 \
--hash=sha256:d57359629d295f9ee570068a2846966892e3fedb722259ecbcd8cc376d299b51 \
--hash=sha256:f8fddd87b24552541318ac037e33750d27d0045131e4f8a60ec13a159fcbdd5c
# via -r requirements/prod.txt
google-api-core==2.19.0 \
--hash=sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251 \
--hash=sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10
# via
# -r requirements/prod.txt
# google-cloud-core
# google-cloud-storage
google-auth==2.29.0 \
--hash=sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360 \
--hash=sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415
# via
# -r requirements/prod.txt
# google-api-core
# google-cloud-core
# google-cloud-storage
google-cloud-core==2.4.1 \
--hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \
--hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61
# via
# -r requirements/prod.txt
# google-cloud-storage
google-cloud-storage==2.16.0 \
--hash=sha256:91a06b96fb79cf9cdfb4e759f178ce11ea885c79938f89590344d079305f5852 \
--hash=sha256:dda485fa503710a828d01246bd16ce9db0823dc51bbca742ce96a6817d58669f
# via
# -r requirements/prod.txt
# django-storages
google-crc32c==1.5.0 \
--hash=sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a \
--hash=sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876 \
--hash=sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c \
--hash=sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289 \
--hash=sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298 \
--hash=sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02 \
--hash=sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f \
--hash=sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2 \
--hash=sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a \
--hash=sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb \
--hash=sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210 \
--hash=sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5 \
--hash=sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee \
--hash=sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c \
--hash=sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a \
--hash=sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314 \
--hash=sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd \
--hash=sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65 \
--hash=sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37 \
--hash=sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4 \
--hash=sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13 \
--hash=sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894 \
--hash=sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31 \
--hash=sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e \
--hash=sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709 \
--hash=sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740 \
--hash=sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc \
--hash=sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d \
--hash=sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c \
--hash=sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c \
--hash=sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d \
--hash=sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906 \
--hash=sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61 \
--hash=sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57 \
--hash=sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c \
--hash=sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a \
--hash=sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438 \
--hash=sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946 \
--hash=sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7 \
--hash=sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96 \
--hash=sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091 \
--hash=sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae \
--hash=sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d \
--hash=sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88 \
--hash=sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2 \
--hash=sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd \
--hash=sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541 \
--hash=sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728 \
--hash=sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178 \
--hash=sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968 \
--hash=sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346 \
--hash=sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8 \
--hash=sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93 \
--hash=sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7 \
--hash=sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273 \
--hash=sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462 \
--hash=sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94 \
--hash=sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd \
--hash=sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e \
--hash=sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57 \
--hash=sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b \
--hash=sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9 \
--hash=sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a \
--hash=sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100 \
--hash=sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325 \
--hash=sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183 \
--hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \
--hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4
# via
# -r requirements/prod.txt
# google-cloud-storage
# google-resumable-media
google-resumable-media==2.7.0 \
--hash=sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b \
--hash=sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08
# via
# -r requirements/prod.txt
# google-cloud-storage
googleapis-common-protos==1.63.0 \
--hash=sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e \
--hash=sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632
# via
# -r requirements/prod.txt
# google-api-core
greenlet==3.0.3 \
--hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \
--hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \
@ -646,7 +847,9 @@ honcho==1.1.0 \
html5lib==1.1 \
--hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \
--hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f
# via -r requirements/prod.txt
# via
# -r requirements/prod.txt
# wagtail
idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
@ -761,6 +964,12 @@ jsonschema-specifications==2023.12.1 \
# via
# -r requirements/prod.txt
# jsonschema
l18n==2021.3 \
--hash=sha256:1956e890d673d17135cc20913253c154f6bc1c00266c22b7d503cc1a5a42d848 \
--hash=sha256:78495d1df95b6f7dcc694d1ba8994df709c463a1cbac1bf016e1b9a5ce7280b9
# via
# -r requirements/prod.txt
# wagtail
lxml==5.2.1 \
--hash=sha256:04ab5415bf6c86e0518d57240a96c4d1fcfc3cb370bb2ac2a732b67f579e5a04 \
--hash=sha256:057cdc6b86ab732cf361f8b4d8af87cf195a1f6dc5b0ff3de2dced242c2015e0 \
@ -1038,6 +1247,12 @@ newrelic==9.9.0 \
--hash=sha256:f0d8c8f66aba3629f0f17a1d2314beb2984ad7c485dd318ef2d5f257c040981d \
--hash=sha256:f48898e268dcaa14aa1b6d5c8b8d10f3f4396589a37be10a06bb5ba262ef0541
# via -r requirements/prod.txt
openpyxl==3.1.2 \
--hash=sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184 \
--hash=sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5
# via
# -r requirements/prod.txt
# wagtail
outcome==1.3.0.post0 \
--hash=sha256:9dcf02e65f2971b80047b377468e72a268e15c0af3cf1238e6ff14f7f91143b8 \
--hash=sha256:e771c5ce06d1415e356078d3bdd68523f284b4ce5419828922b6871e65eda82b
@ -1126,7 +1341,65 @@ pillow==10.3.0 \
--hash=sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f \
--hash=sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27 \
--hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a
# via -r requirements/prod.txt
# via
# -r requirements/prod.txt
# pillow-heif
# wagtail
pillow-heif==0.16.0 \
--hash=sha256:0075adeb324adb07ddbfbe8a5c79ed12e5d04e60e9a642ff9427e71b5b0adccd \
--hash=sha256:078bc74fd767625e465b2c107228f9c398b9a128bdf81b3f18812d7c07be660f \
--hash=sha256:1421d96aebdc9f5773213c8221ce547efb56e37a62da6698312edd4f281efb42 \
--hash=sha256:17963a73186961fe7792aef01c46e980635f3fcc1836393de39ec9c6776ca51e \
--hash=sha256:1f4293ecbb81d255d8d887dce4708a58e87c86e53c6f1b1affc4c3105e1bcb8c \
--hash=sha256:241cf6c510215c6df0ee948dfed06a20c099475250c5c6cac5e7a1ef9e0ec4c3 \
--hash=sha256:2673048f3cf1498327add70f16e1129be2a09cf4a31cbc02363f5760eb5ba955 \
--hash=sha256:28c980bf8d5239ee87986c9217a5954b07993d71d391949a9feafad0a9c5e9a7 \
--hash=sha256:2b7450303f08ec81d1a63a75052863bb687fc3be1fdd8a34d2c0fef627aacae5 \
--hash=sha256:331579ce4f5fa079595c529b06810886ff76f8ade3eb411a1c9c90853a708022 \
--hash=sha256:33e0b1549bcdfec363b3ba6fb55b3de882e1409b5b00f5a68a1a027f051e8ef2 \
--hash=sha256:3501f22985cbb427c76febf07a7e309cb828e485c0cf250a625733fc06fc1815 \
--hash=sha256:38fa2854ec7dbe6c875d64cc5b3cf5cc55f1c8a0248dc1c7c34e9d2505521b82 \
--hash=sha256:3a2681d4b62418813289987a9420059d724cd93542d0b05e0928fe4578517714 \
--hash=sha256:3f062c1be6f04804ffdf0bc452142eff38d7544c8655c04291d16e3b996e4dc4 \
--hash=sha256:40014105688478d6ca146fc04bff6c13f445d01bdea79417b34ee50c1e559190 \
--hash=sha256:4b6caa5b13b4dfc180507527254014530f6bedbeabc1de2238918bf5b2700c7e \
--hash=sha256:4d95004bb77aa640f80617716aa21bc092ec06307f6f2ad423deeeda07b4d29c \
--hash=sha256:502cebc90c11a6bffa2ea899088999c25fc99c8f322e047a266e541e3046b27c \
--hash=sha256:5c7f7a94fc2d08ddcf55a6834c4c55b7dea9605656c565ce11c82e3f6e0454a8 \
--hash=sha256:7794c1a8304eeb841d72cb73aa64cc60c9e5dccb2c7612f8caf528505f78581f \
--hash=sha256:792e5d88b7d016fe48ae2fd77a852ec8dcf9a7fad1f7f191d35bc173896fe378 \
--hash=sha256:7e424d6a34b9466d054706393e76b5abdd84fabdc0c72b19ca10435a76140de7 \
--hash=sha256:7ef47297d526147923f4ecc7ff681a5d5f4e6e3300017681f59968652a0d8afb \
--hash=sha256:7fabd6534a38078a66ce8b7a5ae8ad37afd9863c930abd3031fb553f1ab4f01a \
--hash=sha256:88ff22d2b162e7edd9cb9dd98de81455be04c40a99d1d3d3ebe1602b1a21c453 \
--hash=sha256:89ec30420ddc843c43916febbe31697552ed123396a1696715eea75169866c07 \
--hash=sha256:8e168d45b2ce63c1fe2334fd02927699b0097de72605f7571948010fd79e58f0 \
--hash=sha256:8f15dc73ced02a0ccfac93159d12deeaecfbe4335883a1a3309df0f01c26e6e6 \
--hash=sha256:9273af7224e0fb16c18637184a8ea9a8790105658daab04ad541982b8623e5c1 \
--hash=sha256:9923dfcc97ae9484d3514f2f6ec368e2ac97cd66f7b95359cc1b0ec0c1cd6157 \
--hash=sha256:9bf10a1686c2d51f4db8ebb78825f96f28d18d1878599e1c64e88cfbdb70a3d2 \
--hash=sha256:9fd829c257a763e3a2e8418a773c2808c90799ee3e6b405b5399cb4fdfbe336e \
--hash=sha256:a146be0c8e7bef204eeaa14799b2fca8a4a52ad972850975e23ef10cee4e7de7 \
--hash=sha256:a27abb523a07b17c118c09f1a00f92cde2295f8e997600024d4b57df3c5ba818 \
--hash=sha256:a8856cf5f0d53f83d814ae5c8d34433e5e5ad9f3e328480257cd6e9fbdb4a458 \
--hash=sha256:b50160331754b603524e6ed33c386f478fd66fb345fa6433a507a01c8de642c6 \
--hash=sha256:bbd9cc527bbd53c3e7588e16aad170e11cfd180b7e9bd84f18fb020ddec11408 \
--hash=sha256:be41b7fadd4a9355d24936f6fad83bb8130fe55ba228ec298ad316392bb6f38b \
--hash=sha256:beb6576cbe5a9404a8f2ad9ec68f6b0c406e5e9f5d5573722dc3244898dc9866 \
--hash=sha256:c2ad68e3e4be40adfc5290bf6daa1569dd7d18501e17779d217ce5cd8c1e338d \
--hash=sha256:c7db96ac172e2654676986e8c35fa32bffdd5b429a8c86b9d628c0333c570d82 \
--hash=sha256:d4595ec975db845d84ab90cbf0678f15b0068b8b83c01d1db7ea524e31bab4b4 \
--hash=sha256:d9e465d92cf01093e3e4c33776af97368add23ac1c8d0007f34b8d3e3390d6ad \
--hash=sha256:e0492e4fd6d3334b9eed3651058216ef62f04afa099cfc6b05815c1bf0da2c38 \
--hash=sha256:e5edd98192f74e4c7cffdd62953b2987e2b1e0d6a55d5c940306bed71f40206a \
--hash=sha256:f613dfd05fd62a8b7b57649bfa5db1501be41e18b5e15dd4a2fc12d3e3ddfdaa \
--hash=sha256:f63a1d8f95811569df5df9b6b11674038929c2f696221f2a393aee5ac1e535b4 \
--hash=sha256:fb3efbe8efd26203589794988b11ea9bf3dea2d3bcf218e658f779d526dfcf80 \
--hash=sha256:fba5c46f84031f1186bdea2a0c95f82958f8c29321200e73d7ac5e79ee460c83 \
--hash=sha256:fea4410ce02e295079db5b2617579ba016671d334ac1888a1d4b34aedb56b866
# via
# -r requirements/prod.txt
# willow
pipdeptree==2.19.1 \
--hash=sha256:9e68b1af1cef009e47763343fa3df795d14a367eb1b3d7c461d34a0887235d04 \
--hash=sha256:e342d7c13b3bb87f996607cf10514cc33da899c25b23220d7f0f0adcf48e1f67
@ -1137,10 +1410,52 @@ pluggy==1.5.0 \
# via
# pypom
# pytest
polib==1.2.0 \
--hash=sha256:1c77ee1b81feb31df9bca258cbc58db1bbb32d10214b173882452c73af06d62d \
--hash=sha256:f3ef94aefed6e183e342a8a269ae1fc4742ba193186ad76f175938621dbfc26b
# via
# -r requirements/prod.txt
# wagtail-localize
proto-plus==1.23.0 \
--hash=sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2 \
--hash=sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c
# via
# -r requirements/prod.txt
# google-api-core
protobuf==4.25.3 \
--hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \
--hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \
--hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \
--hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \
--hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \
--hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \
--hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \
--hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \
--hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \
--hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \
--hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2
# via
# -r requirements/prod.txt
# google-api-core
# googleapis-common-protos
# proto-plus
py==1.11.0 \
--hash=sha256:51c75c4126074b472f746a24399ad32f6053d1b34b68d2fa41e558e6f4a98719 \
--hash=sha256:607c53218732647dff4acdfcd50cb62615cedf612e72d1724fb1a0cc6405b378
# via -r requirements/dev.in
pyasn1==0.6.0 \
--hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \
--hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473
# via
# -r requirements/prod.txt
# pyasn1-modules
# rsa
pyasn1-modules==0.4.0 \
--hash=sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6 \
--hash=sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b
# via
# -r requirements/prod.txt
# google-auth
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
@ -1275,7 +1590,9 @@ pytz==2024.1 \
# via
# -r requirements/prod.txt
# apscheduler
# django-modelcluster
# fluent-runtime
# l18n
pyxdg==0.28 \
--hash=sha256:3267bb3074e934df202af2ee0868575484108581e6f3cb006af1da35395e88b4 \
--hash=sha256:bdaf595999a0178ecea4052b7f4195569c1ff4d344567bccdc12dfdf02d545ab
@ -1350,86 +1667,86 @@ referencing==0.35.1 \
# -r requirements/prod.txt
# jsonschema
# jsonschema-specifications
regex==2024.4.28 \
--hash=sha256:05d9b6578a22db7dedb4df81451f360395828b04f4513980b6bd7a1412c679cc \
--hash=sha256:08a1749f04fee2811c7617fdd46d2e46d09106fa8f475c884b65c01326eb15c5 \
--hash=sha256:0940038bec2fe9e26b203d636c44d31dd8766abc1fe66262da6484bd82461ccf \
--hash=sha256:0a2a512d623f1f2d01d881513af9fc6a7c46e5cfffb7dc50c38ce959f9246c94 \
--hash=sha256:0a54a047b607fd2d2d52a05e6ad294602f1e0dec2291152b745870afc47c1397 \
--hash=sha256:0dd3f69098511e71880fb00f5815db9ed0ef62c05775395968299cb400aeab82 \
--hash=sha256:1031a5e7b048ee371ab3653aad3030ecfad6ee9ecdc85f0242c57751a05b0ac4 \
--hash=sha256:108e2dcf0b53a7c4ab8986842a8edcb8ab2e59919a74ff51c296772e8e74d0ae \
--hash=sha256:144a1fc54765f5c5c36d6d4b073299832aa1ec6a746a6452c3ee7b46b3d3b11d \
--hash=sha256:19d6c11bf35a6ad077eb23852827f91c804eeb71ecb85db4ee1386825b9dc4db \
--hash=sha256:1f687a28640f763f23f8a9801fe9e1b37338bb1ca5d564ddd41619458f1f22d1 \
--hash=sha256:224803b74aab56aa7be313f92a8d9911dcade37e5f167db62a738d0c85fdac4b \
--hash=sha256:23a412b7b1a7063f81a742463f38821097b6a37ce1e5b89dd8e871d14dbfd86b \
--hash=sha256:25f87ae6b96374db20f180eab083aafe419b194e96e4f282c40191e71980c666 \
--hash=sha256:2630ca4e152c221072fd4a56d4622b5ada876f668ecd24d5ab62544ae6793ed6 \
--hash=sha256:28e1f28d07220c0f3da0e8fcd5a115bbb53f8b55cecf9bec0c946eb9a059a94c \
--hash=sha256:2b51739ddfd013c6f657b55a508de8b9ea78b56d22b236052c3a85a675102dc6 \
--hash=sha256:2cc1b87bba1dd1a898e664a31012725e48af826bf3971e786c53e32e02adae6c \
--hash=sha256:2fef0b38c34ae675fcbb1b5db760d40c3fc3612cfa186e9e50df5782cac02bcd \
--hash=sha256:36f392dc7763fe7924575475736bddf9ab9f7a66b920932d0ea50c2ded2f5636 \
--hash=sha256:374f690e1dd0dbdcddea4a5c9bdd97632cf656c69113f7cd6a361f2a67221cb6 \
--hash=sha256:3986217ec830c2109875be740531feb8ddafe0dfa49767cdcd072ed7e8927962 \
--hash=sha256:39fb166d2196413bead229cd64a2ffd6ec78ebab83fff7d2701103cf9f4dfd26 \
--hash=sha256:4290035b169578ffbbfa50d904d26bec16a94526071ebec3dadbebf67a26b25e \
--hash=sha256:43548ad74ea50456e1c68d3c67fff3de64c6edb85bcd511d1136f9b5376fc9d1 \
--hash=sha256:44a22ae1cfd82e4ffa2066eb3390777dc79468f866f0625261a93e44cdf6482b \
--hash=sha256:457c2cd5a646dd4ed536c92b535d73548fb8e216ebee602aa9f48e068fc393f3 \
--hash=sha256:459226445c7d7454981c4c0ce0ad1a72e1e751c3e417f305722bbcee6697e06a \
--hash=sha256:47af45b6153522733aa6e92543938e97a70ce0900649ba626cf5aad290b737b6 \
--hash=sha256:499334ad139557de97cbc4347ee921c0e2b5e9c0f009859e74f3f77918339257 \
--hash=sha256:57ba112e5530530fd175ed550373eb263db4ca98b5f00694d73b18b9a02e7185 \
--hash=sha256:5ce479ecc068bc2a74cb98dd8dba99e070d1b2f4a8371a7dfe631f85db70fe6e \
--hash=sha256:5dbc1bcc7413eebe5f18196e22804a3be1bfdfc7e2afd415e12c068624d48247 \
--hash=sha256:6277d426e2f31bdbacb377d17a7475e32b2d7d1f02faaecc48d8e370c6a3ff31 \
--hash=sha256:66372c2a01782c5fe8e04bff4a2a0121a9897e19223d9eab30c54c50b2ebeb7f \
--hash=sha256:670fa596984b08a4a769491cbdf22350431970d0112e03d7e4eeaecaafcd0fec \
--hash=sha256:6f435946b7bf7a1b438b4e6b149b947c837cb23c704e780c19ba3e6855dbbdd3 \
--hash=sha256:7413167c507a768eafb5424413c5b2f515c606be5bb4ef8c5dee43925aa5718b \
--hash=sha256:7c3d389e8d76a49923683123730c33e9553063d9041658f23897f0b396b2386f \
--hash=sha256:7d77b6f63f806578c604dca209280e4c54f0fa9a8128bb8d2cc5fb6f99da4150 \
--hash=sha256:7e76b9cfbf5ced1aca15a0e5b6f229344d9b3123439ffce552b11faab0114a02 \
--hash=sha256:7f3502f03b4da52bbe8ba962621daa846f38489cae5c4a7b5d738f15f6443d17 \
--hash=sha256:7fe9739a686dc44733d52d6e4f7b9c77b285e49edf8570754b322bca6b85b4cc \
--hash=sha256:83ab366777ea45d58f72593adf35d36ca911ea8bd838483c1823b883a121b0e4 \
--hash=sha256:84077821c85f222362b72fdc44f7a3a13587a013a45cf14534df1cbbdc9a6796 \
--hash=sha256:8bb381f777351bd534462f63e1c6afb10a7caa9fa2a421ae22c26e796fe31b1f \
--hash=sha256:92da587eee39a52c91aebea8b850e4e4f095fe5928d415cb7ed656b3460ae79a \
--hash=sha256:9301cc6db4d83d2c0719f7fcda37229691745168bf6ae849bea2e85fc769175d \
--hash=sha256:965fd0cf4694d76f6564896b422724ec7b959ef927a7cb187fc6b3f4e4f59833 \
--hash=sha256:99d6a550425cc51c656331af0e2b1651e90eaaa23fb4acde577cf15068e2e20f \
--hash=sha256:99ef6289b62042500d581170d06e17f5353b111a15aa6b25b05b91c6886df8fc \
--hash=sha256:a1409c4eccb6981c7baabc8888d3550df518add6e06fe74fa1d9312c1838652d \
--hash=sha256:a74fcf77d979364f9b69fcf8200849ca29a374973dc193a7317698aa37d8b01c \
--hash=sha256:aaa179975a64790c1f2701ac562b5eeb733946eeb036b5bcca05c8d928a62f10 \
--hash=sha256:ac69b394764bb857429b031d29d9604842bc4cbfd964d764b1af1868eeebc4f0 \
--hash=sha256:b45d4503de8f4f3dc02f1d28a9b039e5504a02cc18906cfe744c11def942e9eb \
--hash=sha256:b7d893c8cf0e2429b823ef1a1d360a25950ed11f0e2a9df2b5198821832e1947 \
--hash=sha256:b8eb28995771c087a73338f695a08c9abfdf723d185e57b97f6175c5051ff1ae \
--hash=sha256:b91d529b47798c016d4b4c1d06cc826ac40d196da54f0de3c519f5a297c5076a \
--hash=sha256:bc365ce25f6c7c5ed70e4bc674f9137f52b7dd6a125037f9132a7be52b8a252f \
--hash=sha256:bf29304a8011feb58913c382902fde3395957a47645bf848eea695839aa101b7 \
--hash=sha256:c06bf3f38f0707592898428636cbb75d0a846651b053a1cf748763e3063a6925 \
--hash=sha256:c77d10ec3c1cf328b2f501ca32583625987ea0f23a0c2a49b37a39ee5c4c4630 \
--hash=sha256:cd196d056b40af073d95a2879678585f0b74ad35190fac04ca67954c582c6b61 \
--hash=sha256:d7a353ebfa7154c871a35caca7bfd8f9e18666829a1dc187115b80e35a29393e \
--hash=sha256:d84308f097d7a513359757c69707ad339da799e53b7393819ec2ea36bc4beb58 \
--hash=sha256:dd7ef715ccb8040954d44cfeff17e6b8e9f79c8019daae2fd30a8806ef5435c0 \
--hash=sha256:e672cf9caaf669053121f1766d659a8813bd547edef6e009205378faf45c67b8 \
--hash=sha256:ecc6148228c9ae25ce403eade13a0961de1cb016bdb35c6eafd8e7b87ad028b1 \
--hash=sha256:f1c5742c31ba7d72f2dedf7968998730664b45e38827637e0f04a2ac7de2f5f1 \
--hash=sha256:f1d6e4b7b2ae3a6a9df53efbf199e4bfcff0959dbdb5fd9ced34d4407348e39a \
--hash=sha256:f2fc053228a6bd3a17a9b0a3f15c3ab3cf95727b00557e92e1cfe094b88cc662 \
--hash=sha256:f57515750d07e14743db55d59759893fdb21d2668f39e549a7d6cad5d70f9fea \
--hash=sha256:f85151ec5a232335f1be022b09fbbe459042ea1951d8a48fef251223fc67eee1 \
--hash=sha256:fb0315a2b26fde4005a7c401707c5352df274460f2f85b209cf6024271373013 \
--hash=sha256:fc0916c4295c64d6890a46e02d4482bb5ccf33bf1a824c0eaa9e83b148291f90 \
--hash=sha256:fd24fd140b69f0b0bcc9165c397e9b2e89ecbeda83303abf2a072609f60239e2 \
--hash=sha256:fdae0120cddc839eb8e3c15faa8ad541cc6d906d3eb24d82fb041cfe2807bc1e \
--hash=sha256:fe00f4fe11c8a521b173e6324d862ee7ee3412bf7107570c9b564fe1119b56fb
regex==2024.5.10 \
--hash=sha256:031219782d97550c2098d9a68ce9e9eaefe67d2d81d8ff84c8354f9c009e720c \
--hash=sha256:0709ba544cf50bd5cb843df4b8bb6701bae2b70a8e88da9add8386cbca5c1385 \
--hash=sha256:0a9f89d7db5ef6bdf53e5cc8e6199a493d0f1374b3171796b464a74ebe8e508a \
--hash=sha256:0bc94873ba11e34837bffd7e5006703abeffc4514e2f482022f46ce05bd25e67 \
--hash=sha256:0ce56a923f4c01d7568811bfdffe156268c0a7aae8a94c902b92fe34c4bde785 \
--hash=sha256:0faecb6d5779753a6066a3c7a0471a8d29fe25d9981ca9e552d6d1b8f8b6a594 \
--hash=sha256:1118ba9def608250250f4b3e3f48c62f4562ba16ca58ede491b6e7554bfa09ff \
--hash=sha256:12446827f43c7881decf2c126762e11425de5eb93b3b0d8b581344c16db7047a \
--hash=sha256:14905ed75c7a6edf423eb46c213ed3f4507c38115f1ed3c00f4ec9eafba50e58 \
--hash=sha256:15e593386ec6331e0ab4ac0795b7593f02ab2f4b30a698beb89fbdc34f92386a \
--hash=sha256:160ba087232c5c6e2a1e7ad08bd3a3f49b58c815be0504d8c8aacfb064491cd8 \
--hash=sha256:161a206c8f3511e2f5fafc9142a2cc25d7fe9a1ec5ad9b4ad2496a7c33e1c5d2 \
--hash=sha256:169fd0acd7a259f58f417e492e93d0e15fc87592cd1e971c8c533ad5703b5830 \
--hash=sha256:193b7c6834a06f722f0ce1ba685efe80881de7c3de31415513862f601097648c \
--hash=sha256:1a3903128f9e17a500618e80c68165c78c741ebb17dd1a0b44575f92c3c68b02 \
--hash=sha256:1d5bd666466c8f00a06886ce1397ba8b12371c1f1c6d1bef11013e9e0a1464a8 \
--hash=sha256:224a9269f133564109ce668213ef3cb32bc72ccf040b0b51c72a50e569e9dc9e \
--hash=sha256:236cace6c1903effd647ed46ce6dd5d76d54985fc36dafc5256032886736c85d \
--hash=sha256:249fbcee0a277c32a3ce36d8e36d50c27c968fdf969e0fbe342658d4e010fbc8 \
--hash=sha256:29d839829209f3c53f004e1de8c3113efce6d98029f044fa5cfee666253ee7e6 \
--hash=sha256:2c8982ee19ccecabbaeac1ba687bfef085a6352a8c64f821ce2f43e6d76a9298 \
--hash=sha256:2f30a5ab8902f93930dc6f627c4dd5da2703333287081c85cace0fc6e21c25af \
--hash=sha256:304e7e2418146ae4d0ef0e9ffa28f881f7874b45b4994cc2279b21b6e7ae50c8 \
--hash=sha256:32e5f3b8e32918bfbdd12eca62e49ab3031125c454b507127ad6ecbd86e62fca \
--hash=sha256:334b79ce9c08f26b4659a53f42892793948a613c46f1b583e985fd5a6bf1c149 \
--hash=sha256:33d19f0cde6838c81acffff25c7708e4adc7dd02896c9ec25c3939b1500a1778 \
--hash=sha256:3799e36d60a35162bb35b2246d8bb012192b7437dff807ef79c14e7352706306 \
--hash=sha256:42be5de7cc8c1edac55db92d82b68dc8e683b204d6f5414c5a51997a323d7081 \
--hash=sha256:44b3267cea873684af022822195298501568ed44d542f9a2d9bebc0212e99069 \
--hash=sha256:458d68d34fb74b906709735c927c029e62f7d06437a98af1b5b6258025223210 \
--hash=sha256:45cc13d398b6359a7708986386f72bd156ae781c3e83a68a6d4cee5af04b1ce9 \
--hash=sha256:4e7eaf9df15423d07b6050fb91f86c66307171b95ea53e2d87a7993b6d02c7f7 \
--hash=sha256:4fad420b14ae1970a1f322e8ae84a1d9d89375eb71e1b504060ab2d1bfe68f3c \
--hash=sha256:504b5116e2bd1821efd815941edff7535e93372a098e156bb9dffde30264e798 \
--hash=sha256:50e7e96a527488334379e05755b210b7da4a60fc5d6481938c1fa053e0c92184 \
--hash=sha256:51d27844763c273a122e08a3e86e7aefa54ee09fb672d96a645ece0454d8425e \
--hash=sha256:5253dcb0bfda7214523de58b002eb0090cb530d7c55993ce5f6d17faf953ece7 \
--hash=sha256:534efd2653ebc4f26fc0e47234e53bf0cb4715bb61f98c64d2774a278b58c846 \
--hash=sha256:560278c9975694e1f0bc50da187abf2cdc1e4890739ea33df2bc4a85eeef143e \
--hash=sha256:571452362d552de508c37191b6abbbb660028b8b418e2d68c20779e0bc8eaaa8 \
--hash=sha256:62b5f7910b639f3c1d122d408421317c351e213ca39c964ad4121f27916631c6 \
--hash=sha256:696639a73ca78a380acfaa0a1f6dd8220616a99074c05bba9ba8bb916914b224 \
--hash=sha256:6ccdeef4584450b6f0bddd5135354908dacad95425fcb629fe36d13e48b60f32 \
--hash=sha256:70364a097437dd0a90b31cd77f09f7387ad9ac60ef57590971f43b7fca3082a5 \
--hash=sha256:7117cb7d6ac7f2e985f3d18aa8a1728864097da1a677ffa69e970ca215baebf1 \
--hash=sha256:7467ad8b0eac0b28e52679e972b9b234b3de0ea5cee12eb50091d2b68145fe36 \
--hash=sha256:7d35d4cc9270944e95f9c88af757b0c9fc43f396917e143a5756608462c5223b \
--hash=sha256:7dda3091838206969c2b286f9832dff41e2da545b99d1cfaea9ebd8584d02708 \
--hash=sha256:853cc36e756ff673bf984e9044ccc8fad60b95a748915dddeab9488aea974c73 \
--hash=sha256:8722f72068b3e1156a4b2e1afde6810f1fc67155a9fa30a4b9d5b4bc46f18fb0 \
--hash=sha256:8c6c71cf92b09e5faa72ea2c68aa1f61c9ce11cb66fdc5069d712f4392ddfd00 \
--hash=sha256:903350bf44d7e4116b4d5898b30b15755d61dcd3161e3413a49c7db76f0bee5a \
--hash=sha256:91b53dea84415e8115506cc62e441a2b54537359c63d856d73cb1abe05af4c9a \
--hash=sha256:951be1eae7b47660412dc4938777a975ebc41936d64e28081bf2e584b47ec246 \
--hash=sha256:972b49f2fe1047b9249c958ec4fa1bdd2cf8ce305dc19d27546d5a38e57732d8 \
--hash=sha256:9a8625849387b9d558d528e263ecc9c0fbde86cfa5c2f0eef43fff480ae24d71 \
--hash=sha256:9cdbb1998da94607d5eec02566b9586f0e70d6438abf1b690261aac0edda7ab6 \
--hash=sha256:9e6d4d6ae1827b2f8c7200aaf7501c37cf3f3896c86a6aaf2566448397c823dd \
--hash=sha256:aab65121229c2ecdf4a31b793d99a6a0501225bd39b616e653c87b219ed34a49 \
--hash=sha256:ab98016541543692a37905871a5ffca59b16e08aacc3d7d10a27297b443f572d \
--hash=sha256:ad45f3bccfcb00868f2871dce02a755529838d2b86163ab8a246115e80cfb7d6 \
--hash=sha256:b43b78f9386d3d932a6ce5af4b45f393d2e93693ee18dc4800d30a8909df700e \
--hash=sha256:b66421f8878a0c82fc0c272a43e2121c8d4c67cb37429b764f0d5ad70b82993b \
--hash=sha256:ba034c8db4b264ef1601eb33cd23d87c5013b8fb48b8161debe2e5d3bd9156b0 \
--hash=sha256:bbdc5db2c98ac2bf1971ffa1410c87ca7a15800415f788971e8ba8520fc0fda9 \
--hash=sha256:bc0db93ad039fc2fe32ccd3dd0e0e70c4f3d6e37ae83f0a487e1aba939bd2fbd \
--hash=sha256:bf7c8ee4861d9ef5b1120abb75846828c811f932d63311596ad25fa168053e00 \
--hash=sha256:bf9596cba92ce7b1fd32c7b07c6e3212c7eed0edc271757e48bfcd2b54646452 \
--hash=sha256:c43395a3b7cc9862801a65c6994678484f186ce13c929abab44fb8a9e473a55a \
--hash=sha256:c46a76a599fcbf95f98755275c5527304cc4f1bb69919434c1e15544d7052910 \
--hash=sha256:ca23b41355ba95929e9505ee04e55495726aa2282003ed9b012d86f857d3e49b \
--hash=sha256:cd832bd9b6120d6074f39bdfbb3c80e416848b07ac72910f1c7f03131a6debc3 \
--hash=sha256:cfa6d61a76c77610ba9274c1a90a453062bdf6887858afbe214d18ad41cf6bde \
--hash=sha256:d8a0f0ab5453e409586b11ebe91c672040bc804ca98d03a656825f7890cbdf88 \
--hash=sha256:e91b1976358e17197157b405cab408a5f4e33310cda211c49fc6da7cffd0b2f0 \
--hash=sha256:ea057306ab469130167014b662643cfaed84651c792948891d003cf0039223a5 \
--hash=sha256:eda3dd46df535da787ffb9036b5140f941ecb91701717df91c9daf64cabef953 \
--hash=sha256:f03b1dbd4d9596dd84955bb40f7d885204d6aac0d56a919bb1e0ff2fb7e1735a \
--hash=sha256:fa9335674d7c819674467c7b46154196c51efbaf5f5715187fd366814ba3fa39
# via parsimonious
requests==2.31.0 \
--hash=sha256:58cd2187c01e70e6e26505bca751777aa9f2ee0b7f4300988b709f44e013003f \
@ -1441,10 +1758,13 @@ requests==2.31.0 \
# contentful
# datadog
# django-mozilla-product-details
# google-api-core
# google-cloud-storage
# pygithub
# pytest-base-url
# pytest-selenium
# responses
# wagtail
responses==0.25.0 \
--hash=sha256:01ae6a02b4f34e39bffceb0fc6786b67a25eae919c6368d05eabc8d9576c2a66 \
--hash=sha256:2f0b9c2b6437db4b528619a77e5d565e4ec2a9532162ac1a131a83529db7be1a
@ -1557,6 +1877,12 @@ rpds-py==0.18.1 \
# -r requirements/prod.txt
# jsonschema
# referencing
rsa==4.9 \
--hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \
--hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21
# via
# -r requirements/prod.txt
# google-auth
ruff==0.4.2 \
--hash=sha256:0e2e06459042ac841ed510196c350ba35a9b24a643e23db60d79b2db92af0c2b \
--hash=sha256:1f32cadf44c2020e75e0c56c3408ed1d32c024766bd41aedef92aa3ca28eef68 \
@ -1608,6 +1934,7 @@ six==1.16.0 \
# compare-locales
# dirsync
# html5lib
# l18n
# python-dateutil
sniffio==1.3.1 \
--hash=sha256:2f6da418d1f1e0fddd844478f41680e794e6051915791a034ff65e5f100525a2 \
@ -1637,6 +1964,12 @@ tblib==3.0.0 \
--hash=sha256:80a6c77e59b55e83911e1e607c649836a69c103963c5f28a46cbeef44acf8129 \
--hash=sha256:93622790a0a29e04f0346458face1e144dc4d32f493714c6c3dff82a4adb77e6
# via pytest-parallel
telepath==0.3.1 \
--hash=sha256:925c0609e0a8a6488ec4a55b19d485882cf72223b2b19fe2359a50fddd813c9c \
--hash=sha256:c280aa8e77ad71ce80e96500a4e4d4a32f35b7e0b52e896bb5fde9a5bcf0699a
# via
# -r requirements/prod.txt
# wagtail
tenacity==8.3.0 \
--hash=sha256:3649f6443dbc0d9b01b9d8020a9c4ec7a1ff5f6f3c6c8a036ef371f573fe9185 \
--hash=sha256:953d4e6ad24357bceffbc9707bc74349aca9d245f68eb65419cf0c249a1949a2
@ -1677,6 +2010,7 @@ typing-extensions==4.11.0 \
# fluent-syntax
# pygithub
# qrcode
# wagtail-localize
tzlocal==5.2 \
--hash=sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8 \
--hash=sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e
@ -1694,6 +2028,21 @@ urllib3[socks]==2.2.1 \
# responses
# selenium
# sentry-sdk
wagtail==5.2.3 \
--hash=sha256:7b186b37ba044fd68c1a3c584ac0d913daa4ea95b95aa4c80412e4a0cb04e563 \
--hash=sha256:ad64595124c84c4b00b73b863029a7722e06b4dba17b76177d2f4944f579bca7
# via
# -r requirements/prod.txt
# wagtail-factories
# wagtail-localize
wagtail-factories==4.1.0 \
--hash=sha256:067e3e1a30721a90eaa1514c8214aae7a171490bbedf026eeaa904a2ed9abcd0 \
--hash=sha256:6abd435518fdf0cdd3d9920acb2abbd9005936d6fecfdf6fdde3e404834d4b0c
# via -r requirements/dev.in
wagtail-localize==1.8 \
--hash=sha256:53f04de9bd0985b79c075c480572250fb65ba9f127d076c9e93d944e39b6ca47 \
--hash=sha256:66c3d86e994a6ac5acf1dd569cfd22f2661150abc6099cae2d6fa30a3495d0fc
# via -r requirements/prod.txt
wcwidth==0.2.13 \
--hash=sha256:3da69048e4540d84af32131829ff948f1e022c1c6bdb8d6102117aac784f6859 \
--hash=sha256:72ea0c06399eb286d978fdedb6923a9eb47e1c486ce63e9b4e64fc18303972b5
@ -1710,6 +2059,12 @@ whitenoise==6.6.0 \
--hash=sha256:8998f7370973447fac1e8ef6e8ded2c5209a7b1f67c1012866dbcd09681c3251 \
--hash=sha256:b1f9db9bf67dc183484d760b99f4080185633136a273a03f6436034a41064146
# via -r requirements/prod.txt
willow[heif]==1.6.3 \
--hash=sha256:143cefd30d3bb816cdff857c454da24991dda35a0315ea795101675e0b14262f \
--hash=sha256:f4b17a16c6315864604dadb6cdf2987d0b685e295cca74c6da28b94167a3126e
# via
# -r requirements/prod.txt
# wagtail
wrapt==1.16.0 \
--hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \
--hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \

Просмотреть файл

@ -237,9 +237,9 @@ markupsafe==2.1.4 \
# via
# -r requirements/docs.in
# jinja2
mdit-py-plugins==0.4.0 \
--hash=sha256:b51b3bb70691f57f974e257e367107857a93b36f322a9e6d44ca5bf28ec2def9 \
--hash=sha256:d8ab27e9aed6c38aa716819fedfde15ca275715955f8a185a8e1cf90fb1d2c1b
mdit-py-plugins==0.4.1 \
--hash=sha256:1020dfe4e6bfc2c79fb49ae4e3f5b297f5ccd20f010187acc52af2921e27dc6a \
--hash=sha256:834b8ac23d1cd60cec703646ffd22ae97b7955a6d596eb1d304be1e251ae499c
# via myst-parser
mdurl==0.1.2 \
--hash=sha256:84008a41e51615a49fc9966191ff91509e3c40b939176e643fd50a5c2196b8f8 \

Просмотреть файл

@ -1,7 +1,6 @@
APScheduler==3.10.4
babis==0.2.4
basket-client==1.1.0
beautifulsoup4==4.12.3
bleach[css]==6.1.0
boto3==1.34.101
certifi>=2023.7.22 # to bring it up to a secure version
@ -20,6 +19,7 @@ django-jinja==2.11.0
django-jsonview==2.0.0
django-memoize==2.3.1
django-mozilla-product-details==1.0.3
django-storages[google]==1.14.2
django-watchman==1.3.0
Django==4.2.11
docutils==0.21.2
@ -53,3 +53,5 @@ sentry-processor==0.0.1
supervisor==4.2.5
timeago==1.0.16
whitenoise==6.6.0
Wagtail==5.2.3
wagtail-localize==1.8

Просмотреть файл

@ -4,6 +4,10 @@
#
# $ make compile-requirements
#
anyascii==0.3.2 \
--hash=sha256:3b3beef6fc43d9036d3b0529050b0c48bfad8bc960e9e562d7223cfb94fe45d4 \
--hash=sha256:9d5d32ef844fe225b8bc7cba7f950534fae4da27a9bf3a6bea2cb0ea46ce4730
# via wagtail
appdirs==1.4.4 \
--hash=sha256:7d5d0167b2b1ba821647616af46a749d1c653740dd0d2415100fe26e27afdf41 \
--hash=sha256:a841dacd6b99318a741b166adb07e19ee71a274450e68237b4650ca1055ab128
@ -37,10 +41,10 @@ basket-client==1.1.0 \
--hash=sha256:3e637824891cc7ff5262d3d57dc744c265becb295edfbec30223262e5544228d \
--hash=sha256:6477d29337d4a3a8843d88e25f679a348c8a26341370c508173548da9799c19d
# via -r requirements/prod.in
beautifulsoup4==4.12.3 \
--hash=sha256:74e3d1928edc070d21748185c46e3fb33490f22f52a3addee9aee0f4f7781051 \
--hash=sha256:b80878c9f40111313e55da8ba20bdba06d8fa3969fc68304167741bbf9e082ed
# via -r requirements/prod.in
beautifulsoup4==4.11.2 \
--hash=sha256:0e79446b10b3ecb499c1556f7e228a53e64a2bfcebd455f370d8927cb5b59e39 \
--hash=sha256:bc4bdda6717de5a2987436fb8d72f45dc90dd856bdfd512a1314ce90349a0106
# via wagtail
bleach[css]==6.1.0 \
--hash=sha256:0a31f1837963c41d46bbf1331b8778e1308ea0791db03cc4e7357b97cf42a8fe \
--hash=sha256:3225f354cfc436b9789c66c4ee030194bee0568fbf9cbdad3bc8b5c26c5f12b6
@ -49,12 +53,16 @@ boto3==1.34.101 \
--hash=sha256:1d854b5880e185db546b4c759fcb664bf3326275064d2b44229cc217e8be9d7e \
--hash=sha256:79b93f3370ea96ce838042bc2eac0c996aee204b01e7e6452eb77abcbe697d6a
# via -r requirements/prod.in
botocore==1.34.101 \
--hash=sha256:01f3802d25558dd7945d83884bf6885e2f84e1ff27f90b5f09614966fe18c18f \
--hash=sha256:f145e8b4b8fc9968f5eb695bdc2fcc8e675df7fbc3c56102dc1f5471be6baf35
botocore==1.34.103 \
--hash=sha256:0330d139f18f78d38127e65361859e24ebd6a8bcba184f903c01bb999a3fa431 \
--hash=sha256:5f07e2c7302c0a9f469dcd08b4ddac152e9f5888b12220242c20056255010939
# via
# boto3
# s3transfer
cachetools==5.3.3 \
--hash=sha256:0abad1021d3f8325b2fc1d2e9c8b9c9d57b04c3932657a72465447332c24d945 \
--hash=sha256:ba29e2dfa0b8b556606f097407ed1aa62080ee108ab0dc5ec9d6a723a007d105
# via google-auth
certifi==2024.2.2 \
--hash=sha256:0569859f95fc761b18b45ef421b1290a0f65f147e92a1e5eb3e635f9a5e4e66f \
--hash=sha256:dc383c07b76109f368f6106eee2b593b04a011ea4d55f652c6ca24a754d1cdd1
@ -270,6 +278,10 @@ datadog==0.49.1 \
--hash=sha256:4a56d57490ea699a0dfd9253547485a57b4120e93489defadcf95c66272374d6 \
--hash=sha256:4cb7a7991af6cadb868fe450cd456473e65f11fc678b7d7cf61044ff1c6074d8
# via markus
defusedxml==0.7.1 \
--hash=sha256:1bb3032db185915b62d7c6209c5a8792be6a32ab2fedacc84e01b52c51aa3e69 \
--hash=sha256:a352e7e428770286cc899e2542b6cdaedb2b4953ff269a210103ec58f6198a61
# via willow
deprecated==1.2.14 \
--hash=sha256:6fac8b097794a90302bdbb17b9b815e732d3c4720583ff1b198499d78470466c \
--hash=sha256:e5323eb936458dccc2582dc6f9c322c852a775a27065ff2b0c4970b9d53d01b3
@ -291,10 +303,19 @@ django==4.2.11 \
# django-crum
# django-csp
# django-extensions
# django-filter
# django-jinja
# django-memoize
# django-modelcluster
# django-mozilla-product-details
# django-permissionedforms
# django-storages
# django-taggit
# django-treebeard
# django-watchman
# djangorestframework
# wagtail
# wagtail-localize
django-allow-cidr==0.7.1 \
--hash=sha256:11126c5bb9df3a61ff9d97304856ba7e5b26d46c6d456709a6d9e28483bff47f \
--hash=sha256:382c5d7a9807279e3e96e4f4892b59163a2b30128c596902bf5f80e133e1ccbb
@ -315,6 +336,10 @@ django-extensions==3.2.3 \
--hash=sha256:44d27919d04e23b3f40231c4ab7af4e61ce832ef46d610cc650d53e68328410a \
--hash=sha256:9600b7562f79a92cbf1fde6403c04fee314608fefbb595502e34383ae8203401
# via -r requirements/prod.in
django-filter==23.5 \
--hash=sha256:67583aa43b91fe8c49f74a832d95f4d8442be628fd4c6d65e9f811f5153a4e5c \
--hash=sha256:99122a201d83860aef4fe77758b69dda913e874cc5e0eaa50a86b0b18d708400
# via wagtail
django-jinja==2.11.0 \
--hash=sha256:47c06d3271e6b2f27d3596278af517bfe2e19c1eb36ae1c0b1cc302d7f0259af \
--hash=sha256:cc4c72246a6e346aa0574e0c56c3e534c1a20ef47b8476f05d7287781f69a0a9
@ -332,26 +357,62 @@ django-jsonview==2.0.0 \
django-memoize==2.3.1 \
--hash=sha256:62ac4807710ecf22a7397d008d64d0f798e7230482d4b6072d916cac852a47cd
# via -r requirements/prod.in
django-modelcluster==6.3 \
--hash=sha256:0caed8a0e889f3abb92f144670878a466ef954ffa6c4c7b9c80e6426b720a49d \
--hash=sha256:a8783d6565a0663f41cd6003ea361c3a5711e8a2a326160f1ec1eceb3e973d4f
# via wagtail
django-mozilla-product-details==1.0.3 \
--hash=sha256:1d139ba01f4484f3bb43b72864ce33f249835405449e0dc940217cfa42ce5b46 \
--hash=sha256:a4aba6a68b296dffe8c1afb95d236cdbd402bd855cd49eef4d8a1a610105fd36
# via -r requirements/prod.in
django-permissionedforms==0.1 \
--hash=sha256:4340bb20c4477fffb13b4cc5cccf9f1b1010b64f79956c291c72d2ad2ed243f8 \
--hash=sha256:d341a961a27cc77fde8cc42141c6ab55cc1f0cb886963cc2d6967b9674fa47d6
# via wagtail
django-storages[google]==1.14.2 \
--hash=sha256:1db759346b52ada6c2efd9f23d8241ecf518813eb31db9e2589207174f58f6ad \
--hash=sha256:51b36af28cc5813b98d5f3dfe7459af638d84428c8df4a03990c7d74d1bea4e5
# via -r requirements/prod.in
django-taggit==4.0.0 \
--hash=sha256:4d52de9d37245a9b9f98c0ec71fdccf1d2283e38e8866d40a7ae6a3b6787a161 \
--hash=sha256:eb800dabef5f0a4e047ab0751f82cf805bc4a9e972037ef12bf519f52cd92480
# via wagtail
django-treebeard==4.7.1 \
--hash=sha256:846e462904b437155f76e04907ba4e48480716855f88b898df4122bdcfbd6e98 \
--hash=sha256:995c7120153ab999898fe3043bbdcd8a0fc77cc106eb94de7350e9d02c885135
# via wagtail
django-watchman==1.3.0 \
--hash=sha256:33b5fc734d689b83cb96fc17beda624ae2955f4cede0856897d990c363eac962 \
--hash=sha256:5f04300bd7fbdd63b8a883b2730ed1e4d9b0f9991133b33a1281134b81f466eb
# via -r requirements/prod.in
djangorestframework==3.15.1 \
--hash=sha256:3ccc0475bce968608cf30d07fb17d8e52d1d7fc8bfe779c905463200750cbca6 \
--hash=sha256:f88fad74183dfc7144b2756d0d2ac716ea5b4c7c9840995ac3bfd8ec034333c1
# via wagtail
docutils==0.21.2 \
--hash=sha256:3a6b18732edf182daa3cd12775bbb338cf5691468f91eeeb109deff6ebfa986f \
--hash=sha256:dafca5b9e384f0e419294eb4d2ff9fa826435bf15f15b7bd45723e8ad76811b2
# via -r requirements/prod.in
draftjs-exporter==2.1.7 \
--hash=sha256:5839cbc29d7bce2fb99837a404ca40c3a07313f2a20e2700de7ad6aa9a9a18fb \
--hash=sha256:d415a9964690a2cddb66a31ef32dd46c277e9b80434b94e39e3043188ed83e33
# via wagtail
envcat==0.1.1 \
--hash=sha256:3659c6bad8f47cd3c2691d754a5659c1953480c066718c8a1d87367b03f11bc8 \
--hash=sha256:6831806d205b7b1c8456bba5d9cd7ced90f52cf2fc8cfbe234d48d3fdb91111d
# via -r requirements/prod.in
et-xmlfile==1.1.0 \
--hash=sha256:8eb9e2bc2f8c97e37a2dc85a09ecdcdec9d8a396530a6d5a33b30b9a92da0c5c \
--hash=sha256:a2ba85d1d6a74ef63837eed693bcb89c3f752169b0e3e7ae5b16ca5e1b3deada
# via openpyxl
everett==3.3.0 \
--hash=sha256:acb7b8f3c5fc9692a8ba14fb257e4649f87bea4856e7406c2e9b6c2cab889105 \
--hash=sha256:d3ecc55cc1bdf2408ca82bc8db5a3fc588fc4c0f236a6ab9599938f41970b814
# via -r requirements/prod.in
filetype==1.2.0 \
--hash=sha256:66b56cd6474bf41d8c54660347d37afcc3f7d1970648de365c102ef77548aadb \
--hash=sha256:7ce71b6880181241cf7ac8697a2f1eb6a8bd9b429f7ad6d27b8db9ba5f1c2d25
# via willow
fluent-runtime==0.4.0 \
--hash=sha256:51fd02582c2363e1106d7051642967a1b7f406dd9c317bd4600a73ede40c5146 \
--hash=sha256:cb5ef96a58a3f67acaaca046d1201d202a1ebf2823e5e664370f359bae20574d
@ -409,6 +470,107 @@ glean-parser==10.0.3 \
--hash=sha256:d57359629d295f9ee570068a2846966892e3fedb722259ecbcd8cc376d299b51 \
--hash=sha256:f8fddd87b24552541318ac037e33750d27d0045131e4f8a60ec13a159fcbdd5c
# via -r requirements/prod.in
google-api-core==2.19.0 \
--hash=sha256:8661eec4078c35428fd3f69a2c7ee29e342896b70f01d1a1cbcb334372dd6251 \
--hash=sha256:cf1b7c2694047886d2af1128a03ae99e391108a08804f87cfd35970e49c9cd10
# via
# google-cloud-core
# google-cloud-storage
google-auth==2.29.0 \
--hash=sha256:672dff332d073227550ffc7457868ac4218d6c500b155fe6cc17d2b13602c360 \
--hash=sha256:d452ad095688cd52bae0ad6fafe027f6a6d6f560e810fec20914e17a09526415
# via
# google-api-core
# google-cloud-core
# google-cloud-storage
google-cloud-core==2.4.1 \
--hash=sha256:9b7749272a812bde58fff28868d0c5e2f585b82f37e09a1f6ed2d4d10f134073 \
--hash=sha256:a9e6a4422b9ac5c29f79a0ede9485473338e2ce78d91f2370c01e730eab22e61
# via google-cloud-storage
google-cloud-storage==2.16.0 \
--hash=sha256:91a06b96fb79cf9cdfb4e759f178ce11ea885c79938f89590344d079305f5852 \
--hash=sha256:dda485fa503710a828d01246bd16ce9db0823dc51bbca742ce96a6817d58669f
# via django-storages
google-crc32c==1.5.0 \
--hash=sha256:024894d9d3cfbc5943f8f230e23950cd4906b2fe004c72e29b209420a1e6b05a \
--hash=sha256:02c65b9817512edc6a4ae7c7e987fea799d2e0ee40c53ec573a692bee24de876 \
--hash=sha256:02ebb8bf46c13e36998aeaad1de9b48f4caf545e91d14041270d9dca767b780c \
--hash=sha256:07eb3c611ce363c51a933bf6bd7f8e3878a51d124acfc89452a75120bc436289 \
--hash=sha256:1034d91442ead5a95b5aaef90dbfaca8633b0247d1e41621d1e9f9db88c36298 \
--hash=sha256:116a7c3c616dd14a3de8c64a965828b197e5f2d121fedd2f8c5585c547e87b02 \
--hash=sha256:19e0a019d2c4dcc5e598cd4a4bc7b008546b0358bd322537c74ad47a5386884f \
--hash=sha256:1c7abdac90433b09bad6c43a43af253e688c9cfc1c86d332aed13f9a7c7f65e2 \
--hash=sha256:1e986b206dae4476f41bcec1faa057851f3889503a70e1bdb2378d406223994a \
--hash=sha256:272d3892a1e1a2dbc39cc5cde96834c236d5327e2122d3aaa19f6614531bb6eb \
--hash=sha256:278d2ed7c16cfc075c91378c4f47924c0625f5fc84b2d50d921b18b7975bd210 \
--hash=sha256:2ad40e31093a4af319dadf503b2467ccdc8f67c72e4bcba97f8c10cb078207b5 \
--hash=sha256:2e920d506ec85eb4ba50cd4228c2bec05642894d4c73c59b3a2fe20346bd00ee \
--hash=sha256:3359fc442a743e870f4588fcf5dcbc1bf929df1fad8fb9905cd94e5edb02e84c \
--hash=sha256:37933ec6e693e51a5b07505bd05de57eee12f3e8c32b07da7e73669398e6630a \
--hash=sha256:398af5e3ba9cf768787eef45c803ff9614cc3e22a5b2f7d7ae116df8b11e3314 \
--hash=sha256:3b747a674c20a67343cb61d43fdd9207ce5da6a99f629c6e2541aa0e89215bcd \
--hash=sha256:461665ff58895f508e2866824a47bdee72497b091c730071f2b7575d5762ab65 \
--hash=sha256:4c6fdd4fccbec90cc8a01fc00773fcd5fa28db683c116ee3cb35cd5da9ef6c37 \
--hash=sha256:5829b792bf5822fd0a6f6eb34c5f81dd074f01d570ed7f36aa101d6fc7a0a6e4 \
--hash=sha256:596d1f98fc70232fcb6590c439f43b350cb762fb5d61ce7b0e9db4539654cc13 \
--hash=sha256:5ae44e10a8e3407dbe138984f21e536583f2bba1be9491239f942c2464ac0894 \
--hash=sha256:635f5d4dd18758a1fbd1049a8e8d2fee4ffed124462d837d1a02a0e009c3ab31 \
--hash=sha256:64e52e2b3970bd891309c113b54cf0e4384762c934d5ae56e283f9a0afcd953e \
--hash=sha256:66741ef4ee08ea0b2cc3c86916ab66b6aef03768525627fd6a1b34968b4e3709 \
--hash=sha256:67b741654b851abafb7bc625b6d1cdd520a379074e64b6a128e3b688c3c04740 \
--hash=sha256:6ac08d24c1f16bd2bf5eca8eaf8304812f44af5cfe5062006ec676e7e1d50afc \
--hash=sha256:6f998db4e71b645350b9ac28a2167e6632c239963ca9da411523bb439c5c514d \
--hash=sha256:72218785ce41b9cfd2fc1d6a017dc1ff7acfc4c17d01053265c41a2c0cc39b8c \
--hash=sha256:74dea7751d98034887dbd821b7aae3e1d36eda111d6ca36c206c44478035709c \
--hash=sha256:759ce4851a4bb15ecabae28f4d2e18983c244eddd767f560165563bf9aefbc8d \
--hash=sha256:77e2fd3057c9d78e225fa0a2160f96b64a824de17840351b26825b0848022906 \
--hash=sha256:7c074fece789b5034b9b1404a1f8208fc2d4c6ce9decdd16e8220c5a793e6f61 \
--hash=sha256:7c42c70cd1d362284289c6273adda4c6af8039a8ae12dc451dcd61cdabb8ab57 \
--hash=sha256:7f57f14606cd1dd0f0de396e1e53824c371e9544a822648cd76c034d209b559c \
--hash=sha256:83c681c526a3439b5cf94f7420471705bbf96262f49a6fe546a6db5f687a3d4a \
--hash=sha256:8485b340a6a9e76c62a7dce3c98e5f102c9219f4cfbf896a00cf48caf078d438 \
--hash=sha256:84e6e8cd997930fc66d5bb4fde61e2b62ba19d62b7abd7a69920406f9ecca946 \
--hash=sha256:89284716bc6a5a415d4eaa11b1726d2d60a0cd12aadf5439828353662ede9dd7 \
--hash=sha256:8b87e1a59c38f275c0e3676fc2ab6d59eccecfd460be267ac360cc31f7bcde96 \
--hash=sha256:8f24ed114432de109aa9fd317278518a5af2d31ac2ea6b952b2f7782b43da091 \
--hash=sha256:98cb4d057f285bd80d8778ebc4fde6b4d509ac3f331758fb1528b733215443ae \
--hash=sha256:998679bf62b7fb599d2878aa3ed06b9ce688b8974893e7223c60db155f26bd8d \
--hash=sha256:9ba053c5f50430a3fcfd36f75aff9caeba0440b2d076afdb79a318d6ca245f88 \
--hash=sha256:9c99616c853bb585301df6de07ca2cadad344fd1ada6d62bb30aec05219c45d2 \
--hash=sha256:a1fd716e7a01f8e717490fbe2e431d2905ab8aa598b9b12f8d10abebb36b04dd \
--hash=sha256:a2355cba1f4ad8b6988a4ca3feed5bff33f6af2d7f134852cf279c2aebfde541 \
--hash=sha256:b1f8133c9a275df5613a451e73f36c2aea4fe13c5c8997e22cf355ebd7bd0728 \
--hash=sha256:b8667b48e7a7ef66afba2c81e1094ef526388d35b873966d8a9a447974ed9178 \
--hash=sha256:ba1eb1843304b1e5537e1fca632fa894d6f6deca8d6389636ee5b4797affb968 \
--hash=sha256:be82c3c8cfb15b30f36768797a640e800513793d6ae1724aaaafe5bf86f8f346 \
--hash=sha256:c02ec1c5856179f171e032a31d6f8bf84e5a75c45c33b2e20a3de353b266ebd8 \
--hash=sha256:c672d99a345849301784604bfeaeba4db0c7aae50b95be04dd651fd2a7310b93 \
--hash=sha256:c6c777a480337ac14f38564ac88ae82d4cd238bf293f0a22295b66eb89ffced7 \
--hash=sha256:cae0274952c079886567f3f4f685bcaf5708f0a23a5f5216fdab71f81a6c0273 \
--hash=sha256:cd67cf24a553339d5062eff51013780a00d6f97a39ca062781d06b3a73b15462 \
--hash=sha256:d3515f198eaa2f0ed49f8819d5732d70698c3fa37384146079b3799b97667a94 \
--hash=sha256:d5280312b9af0976231f9e317c20e4a61cd2f9629b7bfea6a693d1878a264ebd \
--hash=sha256:de06adc872bcd8c2a4e0dc51250e9e65ef2ca91be023b9d13ebd67c2ba552e1e \
--hash=sha256:e1674e4307fa3024fc897ca774e9c7562c957af85df55efe2988ed9056dc4e57 \
--hash=sha256:e2096eddb4e7c7bdae4bd69ad364e55e07b8316653234a56552d9c988bd2d61b \
--hash=sha256:e560628513ed34759456a416bf86b54b2476c59144a9138165c9a1575801d0d9 \
--hash=sha256:edfedb64740750e1a3b16152620220f51d58ff1b4abceb339ca92e934775c27a \
--hash=sha256:f13cae8cc389a440def0c8c52057f37359014ccbc9dc1f0827936bcd367c6100 \
--hash=sha256:f314013e7dcd5cf45ab1945d92e713eec788166262ae8deb2cfacd53def27325 \
--hash=sha256:f583edb943cf2e09c60441b910d6a20b4d9d626c75a36c8fcac01a6c96c01183 \
--hash=sha256:fd8536e902db7e365f49e7d9029283403974ccf29b13fc7028b97e2295b33556 \
--hash=sha256:fe70e325aa68fa4b5edf7d1a4b6f691eb04bbccac0ace68e34820d283b5f80d4
# via
# google-cloud-storage
# google-resumable-media
google-resumable-media==2.7.0 \
--hash=sha256:5f18f5fa9836f4b083162064a1c2c98c17239bfda9ca50ad970ccf905f3e625b \
--hash=sha256:79543cfe433b63fd81c0844b7803aba1bb8950b47bedf7d980c38fa123937e08
# via google-cloud-storage
googleapis-common-protos==1.63.0 \
--hash=sha256:17ad01b11d5f1d0171c06d3ba5c04c54474e883b66b949722b4938ee2694ef4e \
--hash=sha256:ae45f75702f7c08b541f750854a678bd8f534a1a6bace6afe975f1d0a82d6632
# via google-api-core
greenlet==3.0.3 \
--hash=sha256:01bc7ea167cf943b4c802068e178bbf70ae2e8c080467070d01bfa02f337ee67 \
--hash=sha256:0448abc479fab28b00cb472d278828b3ccca164531daab4e970a0458786055d6 \
@ -482,7 +644,9 @@ honcho==1.1.0 \
html5lib==1.1 \
--hash=sha256:0d78f8fde1c230e99fe37986a60526d7049ed4bf8a9fadbad5f00e22e58e041d \
--hash=sha256:b2e5b40261e20f354d198eae92afc10d750afb487ed5e50f9c4eaf07c184146f
# via -r requirements/prod.in
# via
# -r requirements/prod.in
# wagtail
idna==3.7 \
--hash=sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc \
--hash=sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0
@ -584,6 +748,10 @@ jsonschema-specifications==2023.12.1 \
--hash=sha256:48a76787b3e70f5ed53f1160d2b81f586e4ca6d1548c5de7085d1682674764cc \
--hash=sha256:87e4fdf3a94858b8a2ba2778d9ba57d8a9cafca7c7489c46ba0d30a8bc6a9c3c
# via jsonschema
l18n==2021.3 \
--hash=sha256:1956e890d673d17135cc20913253c154f6bc1c00266c22b7d503cc1a5a42d848 \
--hash=sha256:78495d1df95b6f7dcc694d1ba8994df709c463a1cbac1bf016e1b9a5ce7280b9
# via wagtail
lxml==5.2.1 \
--hash=sha256:04ab5415bf6c86e0518d57240a96c4d1fcfc3cb370bb2ac2a732b67f579e5a04 \
--hash=sha256:057cdc6b86ab732cf361f8b4d8af87cf195a1f6dc5b0ff3de2dced242c2015e0 \
@ -849,6 +1017,10 @@ newrelic==9.9.0 \
--hash=sha256:f0d8c8f66aba3629f0f17a1d2314beb2984ad7c485dd318ef2d5f257c040981d \
--hash=sha256:f48898e268dcaa14aa1b6d5c8b8d10f3f4396589a37be10a06bb5ba262ef0541
# via -r requirements/prod.in
openpyxl==3.1.2 \
--hash=sha256:a6f5977418eff3b2d5500d54d9db50c8277a368436f4e4f8ddb1be3422870184 \
--hash=sha256:f91456ead12ab3c6c2e9491cf33ba6d08357d802192379bb482f1033ade496f5
# via wagtail
packaging==24.0 \
--hash=sha256:2ddfb553fdf02fb784c234c7ba6ccc288296ceabec964ad2eae3777778130bc5 \
--hash=sha256:eb82c5e3e56209074766e6885bb04b8c38a0c015d0a30036ebe7ece34c9989e9
@ -925,7 +1097,97 @@ pillow==10.3.0 \
--hash=sha256:f0d0591a0aeaefdaf9a5e545e7485f89910c977087e7de2b6c388aec32011e9f \
--hash=sha256:fdcbb4068117dfd9ce0138d068ac512843c52295ed996ae6dd1faf537b6dbc27 \
--hash=sha256:ff61bfd9253c3915e6d41c651d5f962da23eda633cf02262990094a18a55371a
# via -r requirements/prod.in
# via
# -r requirements/prod.in
# pillow-heif
# wagtail
pillow-heif==0.16.0 \
--hash=sha256:0075adeb324adb07ddbfbe8a5c79ed12e5d04e60e9a642ff9427e71b5b0adccd \
--hash=sha256:078bc74fd767625e465b2c107228f9c398b9a128bdf81b3f18812d7c07be660f \
--hash=sha256:1421d96aebdc9f5773213c8221ce547efb56e37a62da6698312edd4f281efb42 \
--hash=sha256:17963a73186961fe7792aef01c46e980635f3fcc1836393de39ec9c6776ca51e \
--hash=sha256:1f4293ecbb81d255d8d887dce4708a58e87c86e53c6f1b1affc4c3105e1bcb8c \
--hash=sha256:241cf6c510215c6df0ee948dfed06a20c099475250c5c6cac5e7a1ef9e0ec4c3 \
--hash=sha256:2673048f3cf1498327add70f16e1129be2a09cf4a31cbc02363f5760eb5ba955 \
--hash=sha256:28c980bf8d5239ee87986c9217a5954b07993d71d391949a9feafad0a9c5e9a7 \
--hash=sha256:2b7450303f08ec81d1a63a75052863bb687fc3be1fdd8a34d2c0fef627aacae5 \
--hash=sha256:331579ce4f5fa079595c529b06810886ff76f8ade3eb411a1c9c90853a708022 \
--hash=sha256:33e0b1549bcdfec363b3ba6fb55b3de882e1409b5b00f5a68a1a027f051e8ef2 \
--hash=sha256:3501f22985cbb427c76febf07a7e309cb828e485c0cf250a625733fc06fc1815 \
--hash=sha256:38fa2854ec7dbe6c875d64cc5b3cf5cc55f1c8a0248dc1c7c34e9d2505521b82 \
--hash=sha256:3a2681d4b62418813289987a9420059d724cd93542d0b05e0928fe4578517714 \
--hash=sha256:3f062c1be6f04804ffdf0bc452142eff38d7544c8655c04291d16e3b996e4dc4 \
--hash=sha256:40014105688478d6ca146fc04bff6c13f445d01bdea79417b34ee50c1e559190 \
--hash=sha256:4b6caa5b13b4dfc180507527254014530f6bedbeabc1de2238918bf5b2700c7e \
--hash=sha256:4d95004bb77aa640f80617716aa21bc092ec06307f6f2ad423deeeda07b4d29c \
--hash=sha256:502cebc90c11a6bffa2ea899088999c25fc99c8f322e047a266e541e3046b27c \
--hash=sha256:5c7f7a94fc2d08ddcf55a6834c4c55b7dea9605656c565ce11c82e3f6e0454a8 \
--hash=sha256:7794c1a8304eeb841d72cb73aa64cc60c9e5dccb2c7612f8caf528505f78581f \
--hash=sha256:792e5d88b7d016fe48ae2fd77a852ec8dcf9a7fad1f7f191d35bc173896fe378 \
--hash=sha256:7e424d6a34b9466d054706393e76b5abdd84fabdc0c72b19ca10435a76140de7 \
--hash=sha256:7ef47297d526147923f4ecc7ff681a5d5f4e6e3300017681f59968652a0d8afb \
--hash=sha256:7fabd6534a38078a66ce8b7a5ae8ad37afd9863c930abd3031fb553f1ab4f01a \
--hash=sha256:88ff22d2b162e7edd9cb9dd98de81455be04c40a99d1d3d3ebe1602b1a21c453 \
--hash=sha256:89ec30420ddc843c43916febbe31697552ed123396a1696715eea75169866c07 \
--hash=sha256:8e168d45b2ce63c1fe2334fd02927699b0097de72605f7571948010fd79e58f0 \
--hash=sha256:8f15dc73ced02a0ccfac93159d12deeaecfbe4335883a1a3309df0f01c26e6e6 \
--hash=sha256:9273af7224e0fb16c18637184a8ea9a8790105658daab04ad541982b8623e5c1 \
--hash=sha256:9923dfcc97ae9484d3514f2f6ec368e2ac97cd66f7b95359cc1b0ec0c1cd6157 \
--hash=sha256:9bf10a1686c2d51f4db8ebb78825f96f28d18d1878599e1c64e88cfbdb70a3d2 \
--hash=sha256:9fd829c257a763e3a2e8418a773c2808c90799ee3e6b405b5399cb4fdfbe336e \
--hash=sha256:a146be0c8e7bef204eeaa14799b2fca8a4a52ad972850975e23ef10cee4e7de7 \
--hash=sha256:a27abb523a07b17c118c09f1a00f92cde2295f8e997600024d4b57df3c5ba818 \
--hash=sha256:a8856cf5f0d53f83d814ae5c8d34433e5e5ad9f3e328480257cd6e9fbdb4a458 \
--hash=sha256:b50160331754b603524e6ed33c386f478fd66fb345fa6433a507a01c8de642c6 \
--hash=sha256:bbd9cc527bbd53c3e7588e16aad170e11cfd180b7e9bd84f18fb020ddec11408 \
--hash=sha256:be41b7fadd4a9355d24936f6fad83bb8130fe55ba228ec298ad316392bb6f38b \
--hash=sha256:beb6576cbe5a9404a8f2ad9ec68f6b0c406e5e9f5d5573722dc3244898dc9866 \
--hash=sha256:c2ad68e3e4be40adfc5290bf6daa1569dd7d18501e17779d217ce5cd8c1e338d \
--hash=sha256:c7db96ac172e2654676986e8c35fa32bffdd5b429a8c86b9d628c0333c570d82 \
--hash=sha256:d4595ec975db845d84ab90cbf0678f15b0068b8b83c01d1db7ea524e31bab4b4 \
--hash=sha256:d9e465d92cf01093e3e4c33776af97368add23ac1c8d0007f34b8d3e3390d6ad \
--hash=sha256:e0492e4fd6d3334b9eed3651058216ef62f04afa099cfc6b05815c1bf0da2c38 \
--hash=sha256:e5edd98192f74e4c7cffdd62953b2987e2b1e0d6a55d5c940306bed71f40206a \
--hash=sha256:f613dfd05fd62a8b7b57649bfa5db1501be41e18b5e15dd4a2fc12d3e3ddfdaa \
--hash=sha256:f63a1d8f95811569df5df9b6b11674038929c2f696221f2a393aee5ac1e535b4 \
--hash=sha256:fb3efbe8efd26203589794988b11ea9bf3dea2d3bcf218e658f779d526dfcf80 \
--hash=sha256:fba5c46f84031f1186bdea2a0c95f82958f8c29321200e73d7ac5e79ee460c83 \
--hash=sha256:fea4410ce02e295079db5b2617579ba016671d334ac1888a1d4b34aedb56b866
# via willow
polib==1.2.0 \
--hash=sha256:1c77ee1b81feb31df9bca258cbc58db1bbb32d10214b173882452c73af06d62d \
--hash=sha256:f3ef94aefed6e183e342a8a269ae1fc4742ba193186ad76f175938621dbfc26b
# via wagtail-localize
proto-plus==1.23.0 \
--hash=sha256:89075171ef11988b3fa157f5dbd8b9cf09d65fffee97e29ce403cd8defba19d2 \
--hash=sha256:a829c79e619e1cf632de091013a4173deed13a55f326ef84f05af6f50ff4c82c
# via google-api-core
protobuf==4.25.3 \
--hash=sha256:19b270aeaa0099f16d3ca02628546b8baefe2955bbe23224aaf856134eccf1e4 \
--hash=sha256:209ba4cc916bab46f64e56b85b090607a676f66b473e6b762e6f1d9d591eb2e8 \
--hash=sha256:25b5d0b42fd000320bd7830b349e3b696435f3b329810427a6bcce6a5492cc5c \
--hash=sha256:7c8daa26095f82482307bc717364e7c13f4f1c99659be82890dcfc215194554d \
--hash=sha256:c053062984e61144385022e53678fbded7aea14ebb3e0305ae3592fb219ccfa4 \
--hash=sha256:d4198877797a83cbfe9bffa3803602bbe1625dc30d8a097365dbc762e5790faa \
--hash=sha256:e3c97a1555fd6388f857770ff8b9703083de6bf1f9274a002a332d65fbb56c8c \
--hash=sha256:e7cb0ae90dd83727f0c0718634ed56837bfeeee29a5f82a7514c03ee1364c019 \
--hash=sha256:f0700d54bcf45424477e46a9f0944155b46fb0639d69728739c0e47bab83f2b9 \
--hash=sha256:f1279ab38ecbfae7e456a108c5c0681e4956d5b1090027c1de0f934dfdb4b35c \
--hash=sha256:f4f118245c4a087776e0a8408be33cf09f6c547442c00395fbfb116fac2f8ac2
# via
# google-api-core
# googleapis-common-protos
# proto-plus
pyasn1==0.6.0 \
--hash=sha256:3a35ab2c4b5ef98e17dfdec8ab074046fbda76e281c5a706ccd82328cfc8f64c \
--hash=sha256:cca4bb0f2df5504f02f6f8a775b6e416ff9b0b3b16f7ee80b5a3153d9b804473
# via
# pyasn1-modules
# rsa
pyasn1-modules==0.4.0 \
--hash=sha256:831dbcea1b177b28c9baddf4c6d1013c24c3accd14a1873fffaa6a2e905f17b6 \
--hash=sha256:be04f15b66c206eed667e0bb5ab27e2b1855ea54a842e5037738099e8ca4ae0b
# via google-auth
pycparser==2.22 \
--hash=sha256:491c8be9c040f5390f5bf44a5b07752bd07f56edf992381b05c701439eec10f6 \
--hash=sha256:c3702b6d3dd8c7abc1afa565d7e63d53a1d0bd86cdc24edd75470f4de499cfcc
@ -969,7 +1231,9 @@ pytz==2024.1 \
--hash=sha256:328171f4e3623139da4983451950b28e95ac706e13f3f2630a879749e7a8b319
# via
# apscheduler
# django-modelcluster
# fluent-runtime
# l18n
pyyaml==6.0.1 \
--hash=sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5 \
--hash=sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc \
@ -1047,7 +1311,10 @@ requests==2.31.0 \
# contentful
# datadog
# django-mozilla-product-details
# google-api-core
# google-cloud-storage
# pygithub
# wagtail
rich-text-renderer==0.2.8 \
--hash=sha256:74e28bde639f737e2bc50f3dfb147bdbad4b2d7ab3f8f76a9db2d444edb8d13b \
--hash=sha256:e4680109372b55611250ebe0745f59cbf3f8932afa6f5cb5d1f3cc282a4bf95c
@ -1155,6 +1422,10 @@ rpds-py==0.18.1 \
# via
# jsonschema
# referencing
rsa==4.9 \
--hash=sha256:90260d9058e514786967344d0ef75fa8727eed8a7d2e43ce9f4bcf1b536174f7 \
--hash=sha256:e38464a49c6c85d7f1351b0126661487a7e0a14a50f1675ec50eb34d4f20ef21
# via google-auth
s3transfer==0.10.1 \
--hash=sha256:5683916b4c724f799e600f41dd9e10a9ff19871bf87623cc8f491cb4f5fa0a19 \
--hash=sha256:ceb252b11bcf87080fb7850a224fb6e05c8a776bab8f2b64b7f25b969464839d
@ -1175,6 +1446,7 @@ six==1.16.0 \
# bleach
# dirsync
# html5lib
# l18n
# python-dateutil
soupsieve==2.5 \
--hash=sha256:5663d5a7b3bfaeee0bc4372e7fc48f9cff4940b3eec54a6451cc5299f1097690 \
@ -1188,6 +1460,10 @@ supervisor==4.2.5 \
--hash=sha256:2ecaede32fc25af814696374b79e42644ecaba5c09494c51016ffda9602d0f08 \
--hash=sha256:34761bae1a23c58192281a5115fb07fbf22c9b0133c08166beffc70fed3ebc12
# via -r requirements/prod.in
telepath==0.3.1 \
--hash=sha256:925c0609e0a8a6488ec4a55b19d485882cf72223b2b19fe2359a50fddd813c9c \
--hash=sha256:c280aa8e77ad71ce80e96500a4e4d4a32f35b7e0b52e896bb5fde9a5bcf0699a
# via wagtail
timeago==1.0.16 \
--hash=sha256:9b8cb2e3102b329f35a04aa4531982d867b093b19481cfbb1dac7845fa2f79b0
# via -r requirements/prod.in
@ -1203,6 +1479,7 @@ typing-extensions==4.11.0 \
# fluent-syntax
# pygithub
# qrcode
# wagtail-localize
tzlocal==5.2 \
--hash=sha256:49816ef2fe65ea8ac19d19aa7a1ae0551c834303d5014c6d5a62e4cbda8047b8 \
--hash=sha256:8d399205578f1a9342816409cc1e46a93ebd5755e39ea2d85334bea911bf0e6e
@ -1215,6 +1492,16 @@ urllib3==2.2.1 \
# pygithub
# requests
# sentry-sdk
wagtail==5.2.3 \
--hash=sha256:7b186b37ba044fd68c1a3c584ac0d913daa4ea95b95aa4c80412e4a0cb04e563 \
--hash=sha256:ad64595124c84c4b00b73b863029a7722e06b4dba17b76177d2f4944f579bca7
# via
# -r requirements/prod.in
# wagtail-localize
wagtail-localize==1.8 \
--hash=sha256:53f04de9bd0985b79c075c480572250fb65ba9f127d076c9e93d944e39b6ca47 \
--hash=sha256:66c3d86e994a6ac5acf1dd569cfd22f2661150abc6099cae2d6fa30a3495d0fc
# via -r requirements/prod.in
webencodings==0.5.1 \
--hash=sha256:a0af1213f3c2226497a97e2b3aa01a7e4bee4f403f95be16fc9acd2947514a78 \
--hash=sha256:b36a1c245f2d304965eb4e0a82848379241dc04b865afcc4aab16748587e1923
@ -1226,6 +1513,12 @@ whitenoise==6.6.0 \
--hash=sha256:8998f7370973447fac1e8ef6e8ded2c5209a7b1f67c1012866dbcd09681c3251 \
--hash=sha256:b1f9db9bf67dc183484d760b99f4080185633136a273a03f6436034a41064146
# via -r requirements/prod.in
willow[heif]==1.6.3 \
--hash=sha256:143cefd30d3bb816cdff857c454da24991dda35a0315ea795101675e0b14262f \
--hash=sha256:f4b17a16c6315864604dadb6cdf2987d0b685e295cca74c6da28b94167a3126e
# via
# wagtail
# willow
wrapt==1.16.0 \
--hash=sha256:0d2691979e93d06a95a26257adb7bfd0c93818e89b1406f5a28f36e0d8c1e1fc \
--hash=sha256:14d7dc606219cdd7405133c713f2c218d4252f2a469003f8c46bb92d5d095d81 \

Просмотреть файл

@ -23,7 +23,12 @@ def test_410_url(url, base_url):
@pytest.mark.nondestructive
@pytest.mark.django_db
def test_404_url(base_url):
assert_valid_url("/en-US/abck", status_code=requests.codes.not_found, base_url=base_url)
assert_valid_url(
"/en-US/abck",
base_url=base_url,
final_status_code=requests.codes.not_found,
follow_redirects=True,
)
@pytest.mark.headless