Switch from wagtail-modeltranslation to wagtail-localize (#7228)
This commit is contained in:
Родитель
a04bb196e3
Коммит
bd8214ea28
|
@ -81,10 +81,7 @@ jobs:
|
|||
python network-api/manage.py collectstatic --no-input --verbosity 0
|
||||
python network-api/manage.py migrate --no-input
|
||||
python network-api/manage.py block_inventory
|
||||
python network-api/manage.py sync_page_translation_fields
|
||||
python network-api/manage.py update_translation_fields
|
||||
python network-api/manage.py load_fake_data
|
||||
python network-api/manage.py compilemessages
|
||||
|
||||
- name: Configure AWS Credentials for visual diffing
|
||||
uses: aws-actions/configure-aws-credentials@v1
|
||||
|
|
|
@ -98,10 +98,7 @@ jobs:
|
|||
python network-api/manage.py collectstatic --no-input --verbosity 0
|
||||
python network-api/manage.py migrate --no-input
|
||||
python network-api/manage.py block_inventory
|
||||
python network-api/manage.py sync_page_translation_fields
|
||||
python network-api/manage.py update_translation_fields
|
||||
python network-api/manage.py load_fake_data
|
||||
python network-api/manage.py compilemessages
|
||||
|
||||
- name: Retrieving visual baseline
|
||||
run: |
|
||||
|
|
|
@ -86,8 +86,6 @@ jobs:
|
|||
python network-api/manage.py collectstatic --no-input --verbosity 0
|
||||
python network-api/manage.py migrate --no-input
|
||||
python network-api/manage.py block_inventory
|
||||
python network-api/manage.py sync_page_translation_fields
|
||||
python network-api/manage.py update_translation_fields
|
||||
python network-api/manage.py compilemessages
|
||||
- name: Run Tests
|
||||
run: |
|
||||
|
@ -151,10 +149,7 @@ jobs:
|
|||
python network-api/manage.py collectstatic --no-input --verbosity 0
|
||||
python network-api/manage.py migrate --no-input
|
||||
python network-api/manage.py block_inventory
|
||||
python network-api/manage.py sync_page_translation_fields
|
||||
python network-api/manage.py update_translation_fields
|
||||
python network-api/manage.py load_fake_data
|
||||
python network-api/manage.py compilemessages
|
||||
- name: Percy Test
|
||||
uses: ./.github/actions/percy-exec
|
||||
with:
|
||||
|
|
|
@ -68,8 +68,6 @@ jobs:
|
|||
python network-api/manage.py collectstatic --no-input --verbosity 0
|
||||
python network-api/manage.py migrate --no-input
|
||||
python network-api/manage.py block_inventory
|
||||
python network-api/manage.py sync_page_translation_fields
|
||||
python network-api/manage.py update_translation_fields
|
||||
python network-api/manage.py load_fake_data
|
||||
- name: Run URL tests
|
||||
run: |
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
#!/usr/bin/env bash
|
||||
|
||||
# Copy SSH private key to file, if set
|
||||
# This is used for talking to GitHub over an SSH connection
|
||||
if [ $WAGTAIL_LOCALIZE_PRIVATE_KEY ]; then
|
||||
echo "Generating SSH config"
|
||||
SSH_DIR=/app/.ssh
|
||||
|
||||
mkdir -p $SSH_DIR
|
||||
chmod 700 $SSH_DIR
|
||||
|
||||
echo $WAGTAIL_LOCALIZE_PRIVATE_KEY | base64 --decode > $SSH_DIR/id_rsa
|
||||
|
||||
chmod 400 $SSH_DIR/id_rsa
|
||||
|
||||
cat << EOF > $SSH_DIR/config
|
||||
StrictHostKeyChecking no
|
||||
EOF
|
||||
|
||||
chmod 600 $SSH_DIR/config
|
||||
|
||||
echo "Done!"
|
||||
fi
|
|
@ -4,38 +4,38 @@
|
|||
#
|
||||
# pip-compile dev-requirements.in
|
||||
#
|
||||
certifi==2020.4.5.1
|
||||
certifi==2021.5.30
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
# urllib3
|
||||
cffi==1.14.0
|
||||
cffi==1.14.6
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# cryptography
|
||||
chardet==3.0.4
|
||||
charset-normalizer==2.0.4
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
coverage==5.1
|
||||
coverage==5.5
|
||||
# via coveralls
|
||||
coveralls==3.0.1
|
||||
coveralls==3.2.0
|
||||
# via -r dev-requirements.in
|
||||
cryptography==3.2
|
||||
cryptography==3.4.7
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# pyopenssl
|
||||
# urllib3
|
||||
docopt==0.6.2
|
||||
# via coveralls
|
||||
flake8==3.8.4
|
||||
flake8==3.9.2
|
||||
# via -r dev-requirements.in
|
||||
idna==2.9
|
||||
idna==3.2
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
# urllib3
|
||||
importlib-metadata==3.10.1
|
||||
importlib-metadata==4.6.3
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# flake8
|
||||
|
@ -43,36 +43,35 @@ mccabe==0.6.1
|
|||
# via flake8
|
||||
ptvsd==4.3.2
|
||||
# via -r dev-requirements.in
|
||||
pycodestyle==2.6.0
|
||||
pycodestyle==2.7.0
|
||||
# via flake8
|
||||
pycparser==2.20
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# cffi
|
||||
pyflakes==2.2.0
|
||||
pyflakes==2.3.1
|
||||
# via flake8
|
||||
pyopenssl==20.0.1
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# urllib3
|
||||
requests==2.25.1
|
||||
requests==2.26.0
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# coveralls
|
||||
six==1.14.0
|
||||
six==1.16.0
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# cryptography
|
||||
# pyopenssl
|
||||
typing-extensions==3.7.4.3
|
||||
typing-extensions==3.10.0.0
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# importlib-metadata
|
||||
urllib3[secure]==1.25.9
|
||||
urllib3[secure]==1.26.6
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# requests
|
||||
zipp==3.4.1
|
||||
zipp==3.5.0
|
||||
# via
|
||||
# -c requirements.txt
|
||||
# importlib-metadata
|
||||
|
|
|
@ -26,9 +26,6 @@ To get a list of invoke commands available, run `invoke -l`:
|
|||
```
|
||||
catch-up (catchup, docker-catchup) Rebuild images, install dependencies, and apply migrations
|
||||
compilemessages (docker-compilemessages) Compile the latest translations
|
||||
l10n-sync (docker-l10n-sync) Sync localizable fields in the database
|
||||
l10n-update (docker-l10n-update) Update localizable field data (copies from original unlocalized to
|
||||
default localized field)
|
||||
makemessages (docker-makemessages) Extract all template messages in .po files for localization
|
||||
makemigrations (docker-makemigrations) Creates new migration(s) for apps
|
||||
manage (docker-manage) Shorthand to manage.py. inv docker-manage "[COMMAND] [ARG]"
|
||||
|
|
|
@ -26,7 +26,7 @@ If you are defining a new page class for the site, make sure it inherits both th
|
|||
|
||||
#### localization
|
||||
|
||||
We use [wagtail-modeltranslations](https://github.com/infoportugal/wagtail-modeltranslation) for CMS content localization. Please see its documentation for more information.
|
||||
We use [wagtail-localize](https://wagtail-localize.org/) for CMS content localization. Please see its documentation for more information.
|
||||
|
||||
#### A/B testing
|
||||
|
||||
|
|
|
@ -13,6 +13,14 @@ import json
|
|||
from networkapi.wagtailpages.models import Petition, Signup
|
||||
|
||||
|
||||
def process_lang_code(lang):
|
||||
# Salesforce expects "pt" instead of "pt-BR".
|
||||
# See https://github.com/mozilla/foundation.mozilla.org/issues/5993
|
||||
if lang == 'pt-BR':
|
||||
return 'pt'
|
||||
return lang
|
||||
|
||||
|
||||
class SQSProxy:
|
||||
"""
|
||||
We use a proxy class to make sure that code that
|
||||
|
@ -128,7 +136,7 @@ def signup_submission(request, signup):
|
|||
"format": "html",
|
||||
"source_url": source,
|
||||
"newsletters": signup.newsletter,
|
||||
"lang": rq.get('lang', 'en'),
|
||||
"lang": process_lang_code(rq.get('lang', 'en')),
|
||||
"country": rq.get('country', ''),
|
||||
# Empty string instead of None due to Basket issues
|
||||
"first_name": rq.get('givenNames', ''),
|
||||
|
@ -178,7 +186,7 @@ def petition_submission(request, petition):
|
|||
"email": request.data['email'],
|
||||
"email_subscription": request.data['newsletterSignup'],
|
||||
"source_url": request.data['source'],
|
||||
"lang": request.data['lang'],
|
||||
"lang": process_lang_code(request.data['lang']),
|
||||
}
|
||||
|
||||
if petition:
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
from datetime import timezone
|
||||
|
||||
from factory import (
|
||||
DjangoModelFactory,
|
||||
Faker,
|
||||
Trait,
|
||||
LazyAttribute,
|
||||
post_generation,
|
||||
)
|
||||
from factory.django import DjangoModelFactory
|
||||
from wagtail_factories import ImageFactory
|
||||
|
||||
from networkapi.utility.faker import generate_fake_data
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 17:35
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('highlights', '0004_remove_highlight_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='highlight',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='highlight',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,15 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 17:18
|
||||
|
||||
from django.db import migrations
|
||||
from wagtail.core.models import BootstrapTranslatableModel
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('highlights', '0005_auto_20210531_1735'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
BootstrapTranslatableModel('highlights.Highlight'),
|
||||
]
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 18:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('highlights', '0006_bootstrap_migration'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='highlight',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='highlight',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='highlight',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
]
|
|
@ -5,9 +5,12 @@ from django.db.models import Q
|
|||
from adminsortable.models import SortableMixin
|
||||
from wagtail.admin.edit_handlers import FieldPanel
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.core.models import TranslatableMixin
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
from wagtail_localize.fields import TranslatableField
|
||||
|
||||
from networkapi.utility.images import get_image_upload_path
|
||||
|
||||
|
||||
|
@ -33,7 +36,7 @@ class HighlightQuerySet(models.query.QuerySet):
|
|||
|
||||
|
||||
@register_snippet
|
||||
class Highlight(SortableMixin):
|
||||
class Highlight(TranslatableMixin, SortableMixin):
|
||||
"""
|
||||
An data type to highlight things like pulse
|
||||
projects, custom pages, etc
|
||||
|
@ -97,9 +100,16 @@ class Highlight(SortableMixin):
|
|||
FieldPanel("expires"),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField('title'),
|
||||
TranslatableField('description'),
|
||||
TranslatableField('link_label'),
|
||||
TranslatableField('footer'),
|
||||
]
|
||||
|
||||
objects = HighlightQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name_plural = 'highlights'
|
||||
ordering = ('order',)
|
||||
|
||||
|
|
|
@ -0,0 +1,13 @@
|
|||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from wagtail.core.models import Locale
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Look for and create locales if they do not exist. This can be run multiple times if needed.'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
for language_code, name in settings.WAGTAIL_CONTENT_LANGUAGES:
|
||||
locale, created = Locale.objects.get_or_create(language_code=language_code)
|
||||
if created:
|
||||
print(f"Create new locale: {name}")
|
|
@ -26,7 +26,7 @@ class Command(BaseCommand):
|
|||
digits=True,
|
||||
upper_case=True,
|
||||
lower_case=True
|
||||
).generate({})
|
||||
)
|
||||
User.objects.create_superuser('admin', 'admin@example.com', password)
|
||||
|
||||
reviewapp_name = settings.HEROKU_APP_NAME
|
||||
|
|
|
@ -0,0 +1,38 @@
|
|||
from django.conf import settings
|
||||
from django.core.management.base import BaseCommand
|
||||
from wagtail.core.models import Locale
|
||||
from wagtail_localize.models import LocaleSynchronization
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Sync pages with original English pages'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
print("Select a language code to sync with English. ie: de")
|
||||
|
||||
for language_code, name in settings.WAGTAIL_CONTENT_LANGUAGES:
|
||||
if language_code != 'en':
|
||||
print(f"{language_code} ({name})")
|
||||
|
||||
language_code = input("Language code: ")
|
||||
|
||||
# Confirm the language code is in the WAGTAIL_CONTENT_LANGUAGES
|
||||
language_codes_dict = dict(settings.WAGTAIL_CONTENT_LANGUAGES)
|
||||
if language_code not in language_codes_dict:
|
||||
print("Invalid language code")
|
||||
return
|
||||
|
||||
print("Getting both locales...")
|
||||
english_locale, _ = Locale.objects.get_or_create(language_code='en')
|
||||
locale, _ = Locale.objects.get_or_create(language_code=language_code)
|
||||
|
||||
print("Getting LocaleSynchronization object")
|
||||
sync, created = LocaleSynchronization.objects.get_or_create(
|
||||
locale=locale,
|
||||
sync_from=english_locale,
|
||||
)
|
||||
if created:
|
||||
print("\tNew LocaleSynchronization object created")
|
||||
|
||||
print(f"Syncing {locale} from {english_locale}")
|
||||
sync.sync_trees()
|
|
@ -0,0 +1,237 @@
|
|||
# Generated by Django 3.0.14 on 2021-05-25 15:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('mozfest', '0015_auto_20210805_1702'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_guide_text_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_heading_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='banner_video_url_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfesthomepage',
|
||||
name='cta_button_label_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='body_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='header_pt',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_de',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_es',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_fr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_fy_NL',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_nl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_pl',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='mozfestprimarypage',
|
||||
name='intro_pt',
|
||||
),
|
||||
]
|
|
@ -4,6 +4,8 @@ from wagtail.core.fields import StreamField, RichTextField
|
|||
from wagtail.core.models import Page
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
|
||||
from networkapi.wagtailpages.utils import (
|
||||
set_main_site_nav_information,
|
||||
|
@ -89,7 +91,7 @@ class MozfestPrimaryPage(FoundationMetadataPageMixin, FoundationBannerInheritanc
|
|||
context['menu_items'] = self.get_children().live().in_menu()
|
||||
|
||||
# Also make sure that these pages always tap into the mozfest newsletter for the footer!
|
||||
mozfest_footer = Signup.objects.filter(name_en__iexact='mozfest').first()
|
||||
mozfest_footer = Signup.objects.filter(name__iexact='mozfest').first()
|
||||
context['mozfest_footer'] = mozfest_footer
|
||||
|
||||
if not bypass_menu_buildstep:
|
||||
|
@ -167,10 +169,32 @@ class MozfestHomepage(MozfestPrimaryPage):
|
|||
else:
|
||||
content_panels = all_panels
|
||||
|
||||
# Because we inherit from PrimaryPage, but the "use_wide_templatae" property does nothing
|
||||
# Because we inherit from PrimaryPage, but the "use_wide_template" property does nothing
|
||||
# we should hide it and make sure we use the right template
|
||||
settings_panels = Page.settings_panels
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('cta_button_label'),
|
||||
SynchronizedField('cta_button_destination'),
|
||||
TranslatableField('banner_heading'),
|
||||
TranslatableField('banner_guide_text'),
|
||||
SynchronizedField('banner_video_url'),
|
||||
TranslatableField('title'),
|
||||
TranslatableField('search_description'),
|
||||
TranslatableField('search_image'),
|
||||
TranslatableField('signup'),
|
||||
TranslatableField('body'),
|
||||
TranslatableField('footnotes'),
|
||||
]
|
||||
|
||||
def get_context(self, request):
|
||||
context = super().get_context(request)
|
||||
context['banner_video_type'] = self.specific.banner_video_type
|
||||
|
|
|
@ -1,26 +0,0 @@
|
|||
from .models import (
|
||||
MozfestHomepage,
|
||||
MozfestPrimaryPage,
|
||||
)
|
||||
|
||||
from modeltranslation.translator import TranslationOptions
|
||||
from modeltranslation.decorators import register
|
||||
|
||||
|
||||
@register(MozfestPrimaryPage)
|
||||
class MozfestPrimaryPageTR(TranslationOptions):
|
||||
fields = (
|
||||
'header',
|
||||
'intro',
|
||||
'body',
|
||||
)
|
||||
|
||||
|
||||
@register(MozfestHomepage)
|
||||
class MozfestHomepageTR(TranslationOptions):
|
||||
fields = (
|
||||
'cta_button_label',
|
||||
'banner_heading',
|
||||
'banner_guide_text',
|
||||
'banner_video_url',
|
||||
)
|
|
@ -1,14 +1,15 @@
|
|||
from datetime import timezone
|
||||
from random import shuffle
|
||||
|
||||
from factory import (
|
||||
DjangoModelFactory,
|
||||
Faker,
|
||||
post_generation,
|
||||
Trait,
|
||||
LazyAttribute,
|
||||
)
|
||||
from factory.django import DjangoModelFactory
|
||||
|
||||
from networkapi.utility.faker import ImageProvider, generate_fake_data
|
||||
from networkapi.utility.faker import generate_fake_data
|
||||
from networkapi.utility.faker.helpers import reseed
|
||||
from networkapi.news.models import News
|
||||
|
||||
|
@ -17,7 +18,18 @@ from django.conf import settings
|
|||
RANDOM_SEED = settings.RANDOM_SEED
|
||||
TESTING = settings.TESTING
|
||||
|
||||
Faker.add_provider(ImageProvider)
|
||||
GENERIC_IMAGES = [
|
||||
'tigerparrot.jpg',
|
||||
'photographer.jpg',
|
||||
'windfarm.jpg',
|
||||
'hotair.jpg',
|
||||
'computerandcoffee.jpg',
|
||||
]
|
||||
|
||||
|
||||
def get_random_image():
|
||||
shuffle(GENERIC_IMAGES)
|
||||
return f'images/placeholders/generic/{GENERIC_IMAGES[0]}'
|
||||
|
||||
|
||||
class NewsFactory(DjangoModelFactory):
|
||||
|
@ -59,7 +71,7 @@ class NewsFactory(DjangoModelFactory):
|
|||
|
||||
@post_generation
|
||||
def set_thumbnail(self, create, extracted, **kwargs):
|
||||
self.thumbnail.name = Faker('generic_image').generate({})
|
||||
self.thumbnail.name = get_random_image()
|
||||
|
||||
|
||||
def generate(seed):
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 17:35
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('news', '0004_remove_news_featured'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='news',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='news',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,15 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 17:37
|
||||
|
||||
from django.db import migrations
|
||||
from wagtail.core.models import BootstrapTranslatableModel
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('news', '0005_auto_20210531_1735'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
BootstrapTranslatableModel('news.News')
|
||||
]
|
|
@ -0,0 +1,31 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-31 18:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('news', '0006_bootstrap_migration'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='news',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='news',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='news',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
]
|
|
@ -4,6 +4,7 @@ from django.db.models import Q
|
|||
|
||||
from networkapi.utility.images import get_image_upload_path
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtail.core.models import TranslatableMixin
|
||||
|
||||
|
||||
def get_thumbnail_upload_path(instance, filename):
|
||||
|
@ -29,7 +30,7 @@ class NewsQuerySet(models.query.QuerySet):
|
|||
|
||||
|
||||
@register_snippet
|
||||
class News(models.Model):
|
||||
class News(TranslatableMixin, models.Model):
|
||||
"""
|
||||
Medium blog posts, articles and other media
|
||||
"""
|
||||
|
@ -88,7 +89,7 @@ class News(models.Model):
|
|||
|
||||
objects = NewsQuerySet.as_manager()
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
"""Meta settings for news model"""
|
||||
|
||||
verbose_name = 'news article'
|
||||
|
|
|
@ -50,6 +50,7 @@ env = environ.Env(
|
|||
FEED_LIMIT=(int, 10),
|
||||
FILEBROWSER_DEBUG=(bool, False),
|
||||
FILEBROWSER_DIRECTORY=(str, ''),
|
||||
FORCE_500_STACK_TRACES=(bool, False),
|
||||
FRONTEND_CACHE_CLOUDFLARE_BEARER_TOKEN=(str, ''),
|
||||
FRONTEND_CACHE_CLOUDFLARE_ZONEID=(str, ''),
|
||||
GITHUB_TOKEN=(str, ''),
|
||||
|
@ -85,6 +86,9 @@ env = environ.Env(
|
|||
USE_S3=(bool, True),
|
||||
USE_X_FORWARDED_HOST=(bool, False),
|
||||
WAGTAILIMAGES_INDEX_PAGE_SIZE=(int, 60),
|
||||
WAGTAILLOCALIZE_GIT_URL=(str, ''),
|
||||
WAGTAILLOCALIZE_GIT_CLONE_DIR=(str, ''),
|
||||
WAGTAIL_LOCALIZE_PRIVATE_KEY=(str, ''),
|
||||
WEB_MONETIZATION_POINTER=(str, ''),
|
||||
XROBOTSTAG_ENABLED=(bool, False),
|
||||
XSS_PROTECTION=bool,
|
||||
|
@ -138,6 +142,9 @@ SECRET_KEY = env('DJANGO_SECRET_KEY')
|
|||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = FILEBROWSER_DEBUG = env('DEBUG')
|
||||
|
||||
# SECURITY WARNING: same as above!
|
||||
FORCE_500_STACK_TRACES = env('FORCE_500_STACK_TRACES')
|
||||
|
||||
# whether or not to send the X-Robots-Tag header
|
||||
XROBOTSTAG_ENABLED = env('XROBOTSTAG_ENABLED')
|
||||
|
||||
|
@ -222,6 +229,13 @@ INSTALLED_APPS = list(filter(None, [
|
|||
'modelcluster',
|
||||
'taggit',
|
||||
|
||||
# Base wagtail localization
|
||||
'wagtail_localize',
|
||||
'wagtail_localize.locales',
|
||||
|
||||
# git integration for localization
|
||||
'wagtail_localize_git',
|
||||
|
||||
'rest_framework',
|
||||
'django_filters',
|
||||
'gunicorn',
|
||||
|
@ -240,11 +254,6 @@ INSTALLED_APPS = list(filter(None, [
|
|||
# possibly still used?
|
||||
'networkapi.highlights',
|
||||
|
||||
# wagtail localisation app
|
||||
'wagtail_modeltranslation',
|
||||
'wagtail_modeltranslation.makemigrations',
|
||||
'wagtail_modeltranslation.migrate',
|
||||
|
||||
# wagtail to airtable integration
|
||||
'wagtail_airtable',
|
||||
|
||||
|
@ -332,6 +341,7 @@ TEMPLATES = [
|
|||
'blog_tags': 'networkapi.wagtailpages.templatetags.blog_tags',
|
||||
'card_tags': 'networkapi.wagtailpages.templatetags.card_tags',
|
||||
'class_tags': 'networkapi.wagtailpages.templatetags.class_tags',
|
||||
'debug_tags': 'networkapi.wagtailpages.templatetags.debug_tags',
|
||||
'homepage_tags': 'networkapi.wagtailpages.templatetags.homepage_tags',
|
||||
'localization': 'networkapi.wagtailpages.templatetags.localization',
|
||||
'mini_site_tags': 'networkapi.wagtailpages.templatetags.mini_site_tags',
|
||||
|
@ -430,10 +440,10 @@ AUTH_PASSWORD_VALIDATORS = [
|
|||
# https://docs.djangoproject.com/en/1.10/topics/i18n/
|
||||
|
||||
LANGUAGE_CODE = 'en'
|
||||
LANGUAGES = (
|
||||
WAGTAIL_CONTENT_LANGUAGES = LANGUAGES = (
|
||||
('en', gettext_lazy('English')),
|
||||
('de', gettext_lazy('German')),
|
||||
('pt', gettext_lazy('Portuguese')),
|
||||
('pt-BR', gettext_lazy('Portuguese (Brazil)')),
|
||||
('es', gettext_lazy('Spanish')),
|
||||
('fr', gettext_lazy('French')),
|
||||
('fy-NL', gettext_lazy('Frisian')),
|
||||
|
@ -441,6 +451,10 @@ LANGUAGES = (
|
|||
('pl', gettext_lazy('Polish')),
|
||||
)
|
||||
|
||||
WAGTAILLOCALIZE_GIT_URL = env('WAGTAILLOCALIZE_GIT_URL')
|
||||
WAGTAILLOCALIZE_GIT_CLONE_DIR = env('WAGTAILLOCALIZE_GIT_CLONE_DIR')
|
||||
WAGTAIL_LOCALIZE_PRIVATE_KEY = env('WAGTAIL_LOCALIZE_PRIVATE_KEY')
|
||||
|
||||
TIME_ZONE = 'UTC'
|
||||
USE_I18N = True
|
||||
USE_L10N = True
|
||||
|
@ -474,6 +488,7 @@ STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage'
|
|||
WAGTAIL_SITE_NAME = 'Mozilla Foundation'
|
||||
WAGTAILIMAGES_INDEX_PAGE_SIZE = env('WAGTAILIMAGES_INDEX_PAGE_SIZE')
|
||||
WAGTAIL_USAGE_COUNT_ENABLED = True
|
||||
WAGTAIL_I18N_ENABLED = True
|
||||
|
||||
# Wagtail Frontend Cache Invalidator Settings
|
||||
|
||||
|
@ -489,7 +504,7 @@ if env("FRONTEND_CACHE_CLOUDFLARE_BEARER_TOKEN"):
|
|||
# Rest Framework Settings
|
||||
REST_FRAMEWORK = {
|
||||
'DEFAULT_PERMISSION_CLASSES': [
|
||||
'rest_framework.permissions.DjangoModelPermissionsOrAnonReadOnly',
|
||||
'rest_framework.permissions.IsAuthenticatedOrReadOnly',
|
||||
]
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
# Solution came from Aleksi44 on Github:
|
||||
# https://github.com/wagtail/wagtail/issues/6583#issuecomment-798960446
|
||||
from django.contrib.sitemaps import views as sitemap_views
|
||||
from wagtail.contrib.sitemaps.sitemap_generator import Sitemap
|
||||
|
||||
|
||||
class CustomSitemap(Sitemap):
|
||||
|
||||
def items(self):
|
||||
return (
|
||||
self.get_wagtail_site()
|
||||
.root_page
|
||||
.localized # This is missing from sitemap_generator
|
||||
.get_descendants(inclusive=True)
|
||||
.live()
|
||||
.public()
|
||||
.order_by('path')
|
||||
.specific())
|
||||
|
||||
|
||||
def sitemap(request, **kwargs):
|
||||
sitemaps = {'wagtail': CustomSitemap(request)}
|
||||
return sitemap_views.sitemap(request, sitemaps, **kwargs)
|
|
@ -28,7 +28,7 @@
|
|||
{% elif CODE == 'pa-IN' %}
|
||||
<link rel="alternate" hreflang="pa" href="{{ CANONICAL_SITE_URL }}/{{ CODE }}{{ CANONICAL_PATH }}" title="{{ lang.name_local|safe }}">
|
||||
<link rel="alternate" hreflang="pa-IN" href="{{ CANONICAL_SITE_URL }}/{{ CODE }}{{ CANONICAL_PATH }}" title="{{ lang.name_local|safe }}">
|
||||
{% elif CODE == 'pt' %}
|
||||
{% elif CODE == 'pt-BR' %}
|
||||
<link rel="alternate" hreflang="pt" href="{{ CANONICAL_SITE_URL }}/{{ CODE }}{{ CANONICAL_PATH }}" title="{{ lang.name_local|safe }}">
|
||||
<link rel="alternate" hreflang="pt-PT" href="{{ CANONICAL_SITE_URL }}/{{ CODE }}{{ CANONICAL_PATH }}" title="{{ lang.name_local|safe }}">
|
||||
<link rel="alternate" hreflang="pt-BR" href="{{ CANONICAL_SITE_URL }}/{{ CODE }}{{ CANONICAL_PATH }}" title="{{ lang.name_local|safe }}">
|
||||
|
|
|
@ -1,15 +1,16 @@
|
|||
{% load i18n localization %}
|
||||
{% load i18n localization wagtailcore_tags %}
|
||||
|
||||
{% get_current_language as current_language %}
|
||||
{% get_local_language_names as languages %}
|
||||
|
||||
<form action="{% url 'set_language' %}" method="post">
|
||||
<input name="next" type="hidden" value="{{ request.path }}">
|
||||
<input name="next" type="hidden" value="{% get_unlocalized_url page current_language %}" />
|
||||
<div class="d-flex flex-column flex-md-row align-items-md-center justify-content-center mb-md-0">
|
||||
<label class="h5-heading mb-0 d-flex align-items-center globe-glyph medium" for="language-switcher">{% trans "Language" %}</label>
|
||||
<select name="language" id="language-switcher" class="mt-3 mt-md-0 ml-md-3 w-100 form-control" onchange="this.form.submit()">
|
||||
{% get_current_language as LANGUAGE_CODE %}
|
||||
{% get_local_language_names as LANGUAGES %}
|
||||
{% for CODE, NAME in LANGUAGES %}
|
||||
<option value="{{ CODE }}"{% if CODE == LANGUAGE_CODE %} selected{% endif %}>
|
||||
{{ NAME | capfirst }}
|
||||
{% for language_code, language_name in languages %}
|
||||
<option value="{{ language_code }}"{% if language_code == current_language %} selected{% endif %}>
|
||||
{{ language_name | capfirst }}
|
||||
</option>
|
||||
{% endfor %}
|
||||
</select>
|
||||
|
|
|
@ -21,8 +21,8 @@ from wagtail.documents import urls as wagtaildocs_urls
|
|||
|
||||
# from wagtail.core import urls as wagtail_urls
|
||||
from .utility import watail_core_url_override as wagtail_urls
|
||||
from .sitemaps import sitemap
|
||||
|
||||
from wagtail.contrib.sitemaps.views import sitemap
|
||||
from wagtail_footnotes import urls as footnotes_urls
|
||||
from networkapi.wagtailcustomization.image_url_tag_urls import urlpatterns as image_url_tag_urls
|
||||
from networkapi.views import EnvVariablesView, review_app_help_view
|
||||
|
@ -69,7 +69,6 @@ urlpatterns = list(filter(None, [
|
|||
re_path(r'^cms/', include(wagtailadmin_urls)),
|
||||
re_path(r'^en/cms/', RedirectView.as_view(url='/cms/')),
|
||||
re_path(r'^documents/', include(wagtaildocs_urls)),
|
||||
re_path(r'^sitemap.xml$', sitemap),
|
||||
|
||||
# Sentry test url
|
||||
path('sentry-debug', lambda r: 1 / 0) if settings.SENTRY_DSN and settings.DEBUG else None,
|
||||
|
@ -80,6 +79,9 @@ urlpatterns = list(filter(None, [
|
|||
|
||||
# Wagtail Footnotes package
|
||||
path("footnotes/", include(footnotes_urls)),
|
||||
|
||||
# redirect /pt to /pt-BR. See https://github.com/mozilla/foundation.mozilla.org/issues/5993
|
||||
re_path(r'^pt/(?P<rest>.*)', RedirectView.as_view(url='/pt-BR/%(rest)s', query_string=True, permanent=True)),
|
||||
]))
|
||||
|
||||
# Anything that needs to respect the localised
|
||||
|
@ -95,6 +97,8 @@ urlpatterns += i18n_patterns(
|
|||
|
||||
# wagtail-managed data
|
||||
re_path(r'', include(wagtail_urls)),
|
||||
|
||||
path('sitemap.xml', cache_page(86400)(sitemap)),
|
||||
)
|
||||
|
||||
if settings.USE_S3 is not True:
|
||||
|
@ -111,3 +115,8 @@ if settings.DEBUG:
|
|||
# Use a custom 404 handler so that we can serve distinct 404
|
||||
# pages for each "site" that wagtail services.
|
||||
handler404 = 'networkapi.wagtailpages.views.custom404_view'
|
||||
|
||||
# Use a custom 500 handler if and only if Django refuses to give any stack
|
||||
# traces for server error 500... And even then, do not use this on prod.
|
||||
if settings.FORCE_500_STACK_TRACES is True:
|
||||
handler500 = 'networkapi.utility.custom_url_handlers.server_error_500_handler'
|
||||
|
|
|
@ -0,0 +1,15 @@
|
|||
import sys
|
||||
import traceback
|
||||
from django.http import HttpResponse
|
||||
|
||||
|
||||
def server_error_500_handler(request):
|
||||
type, value, tb = sys.exc_info()
|
||||
|
||||
print('\n----intercepted 500 error stack trace----')
|
||||
print(value)
|
||||
print(type)
|
||||
print(traceback.format_exception(type, value, tb))
|
||||
print('----\n')
|
||||
|
||||
return HttpResponse(status=404)
|
|
@ -1,6 +1,8 @@
|
|||
from faker.providers import BaseProvider
|
||||
|
||||
|
||||
# FIXME: this code doesn't work at all, probably due to major version updates,
|
||||
# and this ImageProvider is basically dead code by now.
|
||||
class ImageProvider(BaseProvider):
|
||||
"""
|
||||
A custom Faker Provider for relative image urls, for use with factory_boy
|
||||
|
|
|
@ -1,42 +0,0 @@
|
|||
{% extends "modeltranslation_copy.html" %}
|
||||
|
||||
{% load static i18n %}
|
||||
|
||||
{% block content %}
|
||||
{% trans "Copy" as copy_str %}
|
||||
{% include "wagtailadmin/shared/header.html" with title=copy_str subtitle=page.get_admin_display_title icon="doc-empty-inverse" %}
|
||||
|
||||
<div class="nice-padding">
|
||||
<form action="{% url 'wagtailadmin_pages:copy' page.id %}" method="POST" novalidate>
|
||||
{% csrf_token %}
|
||||
<input type="hidden" name="next" value="{{ next }}" />
|
||||
|
||||
{% comment %}
|
||||
There is unfortunately no block that we can use to inject content in the right place here,
|
||||
so instead we've copied the entirety of https://github.com/infoportugal/wagtail-modeltranslation's
|
||||
templates/modeltranslation_copy.html so that we can add these buttons for staff to click:
|
||||
{% endcomment %}
|
||||
<div>
|
||||
<p><h2>{% trans "Locale synchronization options:" %}</h2></p>
|
||||
<p>
|
||||
<button type="button" class="locale helper button">{% trans "Show all locale fields" %}</button>
|
||||
<button type="button" class="synchronize helper button">{% trans "Synchronize" %}</button>
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<ul class="fields">
|
||||
{% for field in form.visible_fields %}
|
||||
{% include "wagtailadmin/shared/field_as_li.html" with field=field %}
|
||||
{% endfor %}
|
||||
</ul>
|
||||
|
||||
<input type="submit" value="{% trans 'Copy this page' %}" class="button">
|
||||
</form>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block extra_js %}
|
||||
{{ block.super }}
|
||||
|
||||
<script src="{% static "wagtailadmin/js/copy-helper.js" %}" async defer></script>
|
||||
{% endblock %}
|
|
@ -1,12 +1,15 @@
|
|||
from django.db import models
|
||||
|
||||
from wagtail.core.models import TranslatableMixin
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from modelcluster.fields import ParentalKey
|
||||
|
||||
from wagtail_localize.fields import TranslatableField
|
||||
|
||||
|
||||
@register_snippet
|
||||
class DonationModal(models.Model):
|
||||
class DonationModal(TranslatableMixin, models.Model):
|
||||
name = models.CharField(
|
||||
default='',
|
||||
max_length=100,
|
||||
|
@ -40,6 +43,13 @@ class DonationModal(models.Model):
|
|||
default="No thanks",
|
||||
)
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField('header'),
|
||||
TranslatableField('body'),
|
||||
TranslatableField('donate_text'),
|
||||
TranslatableField('dismiss_text'),
|
||||
]
|
||||
|
||||
def to_simple_dict(self):
|
||||
keys = ['name', 'header', 'body', 'donate_text', 'dismiss_text']
|
||||
values = map(lambda k: getattr(self, k), keys)
|
||||
|
@ -48,11 +58,11 @@ class DonationModal(models.Model):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name_plural = 'Donation CTA'
|
||||
|
||||
|
||||
class DonationModals(models.Model):
|
||||
class DonationModals(TranslatableMixin, models.Model):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.CampaignPage',
|
||||
related_name='donation_modals',
|
||||
|
@ -75,6 +85,6 @@ class DonationModals(models.Model):
|
|||
SnippetChooserPanel('donation_modal'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Donation Modals'
|
||||
verbose_name_plural = 'Donation Modals'
|
||||
|
|
|
@ -4,12 +4,13 @@ from random import randint, random, choice, randrange, shuffle
|
|||
from datetime import date, datetime, timezone, timedelta
|
||||
|
||||
from factory import (
|
||||
DjangoModelFactory,
|
||||
Faker,
|
||||
post_generation,
|
||||
LazyAttribute,
|
||||
LazyFunction,
|
||||
)
|
||||
from factory.django import DjangoModelFactory
|
||||
|
||||
|
||||
from wagtail.images.models import Image
|
||||
from wagtail_factories import PageFactory
|
||||
|
@ -38,6 +39,10 @@ def get_random_option(options=[]):
|
|||
return choice(options)
|
||||
|
||||
|
||||
def get_extended_boolean_value():
|
||||
return get_random_option(['Yes', 'No', 'U'])
|
||||
|
||||
|
||||
def get_extended_yes_no_value():
|
||||
return get_random_option(['Yes', 'No', 'NA', 'CD'])
|
||||
|
||||
|
@ -173,18 +178,10 @@ class SoftwareProductPageFactory(ProductPageFactory):
|
|||
handles_recordings_how = Faker('sentence')
|
||||
recording_alert = LazyFunction(get_extended_yes_no_value)
|
||||
recording_alert_helptext = Faker('sentence')
|
||||
medical_privacy_compliant = Faker('boolean')
|
||||
medical_privacy_compliant = LazyFunction(get_extended_boolean_value)
|
||||
medical_privacy_compliant_helptext = Faker('sentence')
|
||||
host_controls = Faker('sentence')
|
||||
easy_to_learn_and_use = Faker('boolean')
|
||||
easy_to_learn_and_use_helptext = Faker('sentence')
|
||||
handles_recordings_how = Faker('sentence')
|
||||
recording_alert = LazyFunction(get_extended_yes_no_value)
|
||||
recording_alert_helptext = Faker('sentence')
|
||||
medical_privacy_compliant = Faker('boolean')
|
||||
medical_privacy_compliant_helptext = Faker('sentence')
|
||||
host_controls = Faker('sentence')
|
||||
easy_to_learn_and_use = Faker('boolean')
|
||||
easy_to_learn_and_use = LazyFunction(get_extended_boolean_value)
|
||||
easy_to_learn_and_use_helptext = Faker('sentence')
|
||||
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
from factory import DjangoModelFactory
|
||||
from factory import Faker
|
||||
from factory.django import DjangoModelFactory
|
||||
|
||||
from networkapi.wagtailpages.models import ContentAuthor
|
||||
from networkapi.utility.faker import generate_fake_data
|
||||
|
|
|
@ -2,8 +2,8 @@ from networkapi.wagtailpages.donation_modal import (
|
|||
DonationModal,
|
||||
DonationModals
|
||||
)
|
||||
from factory.django import DjangoModelFactory
|
||||
from factory import Faker, SubFactory
|
||||
from factory.django import DjangoModelFactory
|
||||
|
||||
|
||||
class DonationModalFactory(DjangoModelFactory):
|
||||
|
|
|
@ -10,7 +10,7 @@ def generate(seed):
|
|||
|
||||
reseed(seed)
|
||||
|
||||
home_page.cause_statement_link_text = Faker('text', max_nb_chars=80).generate()
|
||||
home_page.cause_statement_link_text = Faker('text', max_nb_chars=80)
|
||||
|
||||
all_children = list(home_page.get_descendants())
|
||||
|
||||
|
|
|
@ -27,8 +27,8 @@ def generate(seed):
|
|||
partner_logo_orderable = PartnerLogos.objects.create(
|
||||
page=home_page,
|
||||
logo=choice(all_images),
|
||||
link=Faker('url').generate(),
|
||||
name=Faker('text', max_nb_chars=30).generate(),
|
||||
link=Faker('url'),
|
||||
name=Faker('text', max_nb_chars=30),
|
||||
)
|
||||
home_page.partner_logos.add(partner_logo_orderable)
|
||||
|
||||
|
|
|
@ -21,7 +21,7 @@ def generate(seed):
|
|||
take_action_orderable = HomepageTakeActionCards.objects.create(
|
||||
page=home_page,
|
||||
image=choice(all_images),
|
||||
text=Faker('text', max_nb_chars=255).generate(),
|
||||
text=Faker('text', max_nb_chars=255),
|
||||
internal_link=choice(all_pages),
|
||||
)
|
||||
home_page.take_action_cards.add(take_action_orderable)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import factory
|
||||
from factory.django import DjangoModelFactory, ImageField
|
||||
from wagtail.images import get_image_model
|
||||
from wagtail.core.models import Collection
|
||||
|
||||
|
@ -6,7 +6,7 @@ from wagtail.core.models import Collection
|
|||
# Slightly modify the wagtail_factories ImageFactory so that it
|
||||
# always generates images in the Root collection:
|
||||
|
||||
class CollectionMemberFactory(factory.DjangoModelFactory):
|
||||
class CollectionMemberFactory(DjangoModelFactory):
|
||||
collection = Collection.objects.get(name='Root')
|
||||
|
||||
|
||||
|
@ -21,4 +21,4 @@ class ImageFactory(CollectionMemberFactory):
|
|||
model = get_image_model()
|
||||
|
||||
title = "An image"
|
||||
file = factory.django.ImageField()
|
||||
file = ImageField()
|
||||
|
|
|
@ -12,8 +12,8 @@ from factory import (
|
|||
Faker,
|
||||
SubFactory,
|
||||
django,
|
||||
DjangoModelFactory,
|
||||
)
|
||||
from factory.django import DjangoModelFactory
|
||||
|
||||
from networkapi.wagtailpages.pagemodels.publications.article import ArticleAuthors
|
||||
|
||||
|
|
|
@ -1,6 +1,39 @@
|
|||
from django.db import models
|
||||
|
||||
|
||||
class ExtendedBoolean(models.CharField):
|
||||
"""
|
||||
TODO: unify this with the ExtendedYesNoField below. Because this would
|
||||
introduce a superclass hierarchy change, and Django is notoriously
|
||||
bad at those, this is a separate task.
|
||||
|
||||
See https://github.com/mozilla/foundation.mozilla.org/issues/6929
|
||||
"""
|
||||
|
||||
description = "Yes, No, Unknown"
|
||||
|
||||
choice_list = [
|
||||
('Yes', 'Yes'),
|
||||
('No', 'No'),
|
||||
('U', 'Unknown'),
|
||||
]
|
||||
|
||||
default_choice = 'U'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
kwargs['choices'] = self.choice_list
|
||||
kwargs['default'] = self.default_choice
|
||||
kwargs['max_length'] = 3
|
||||
super().__init__(*args, **kwargs)
|
||||
|
||||
def deconstruct(self):
|
||||
name, path, args, kwargs = super().deconstruct()
|
||||
del kwargs['choices']
|
||||
del kwargs['default']
|
||||
del kwargs['max_length']
|
||||
return name, path, args, kwargs
|
||||
|
||||
|
||||
class ExtendedYesNoField(models.CharField):
|
||||
description = "Yes, No, Not Applicable, or Can’t Determine"
|
||||
|
||||
|
|
Разница между файлами не показана из-за своего большого размера
Загрузить разницу
|
@ -0,0 +1,23 @@
|
|||
# Generated by Django 3.1.11 on 2021-05-25 17:16
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0020_auto_20210525_1516'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='easy_to_learn_and_use',
|
||||
field=models.BooleanField(help_text='Is it easy to learn & use the features?', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='medical_privacy_compliant',
|
||||
field=models.BooleanField(help_text='Compliant with US medical privacy laws?', null=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,266 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-04 16:01
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('wagtailpages', '0021_auto_20210525_1716'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='blogpagecategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='blogpagecategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='buyersguideproductcategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='buyersguideproductcategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contentauthor',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='contentauthor',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cta',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cta',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='donationmodal',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='donationmodal',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='focusarea',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='focusarea',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='update',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='update',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='homepagefocusareas',
|
||||
options={'verbose_name': 'Homepage Focus Area'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagefocusareas',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagefocusareas',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagetakeactioncards',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagetakeactioncards',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='partnerlogos',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='partnerlogos',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='donationmodals',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='donationmodals',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='excludedcategories',
|
||||
options={'verbose_name': 'Excluded Category'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='productpageprivacypolicylink',
|
||||
options={'verbose_name': 'Privacy Link'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='productupdates',
|
||||
options={'verbose_name': 'Product Update'},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='relatedproducts',
|
||||
options={'verbose_name': 'Related Product'},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='excludedcategories',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='excludedcategories',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productpagecategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productpagecategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productpageprivacypolicylink',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productpageprivacypolicylink',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productupdates',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='productupdates',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='relatedproducts',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='relatedproducts',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cta4',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='cta4',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagenewsyoucanuse',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagenewsyoucanuse',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagespotlightposts',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='homepagespotlightposts',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='initiativesection',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='initiativesection',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='initiativeshighlights',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='initiativeshighlights',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='participatehighlights',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='participatehighlights',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='participatehighlights2',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='participatehighlights2',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
|
||||
]
|
|
@ -0,0 +1,38 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-04 16:02
|
||||
|
||||
from django.db import migrations
|
||||
from wagtail.core.models import BootstrapTranslatableModel
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0022_bootstrap_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
BootstrapTranslatableModel('wagtailpages.PartnerLogos'),
|
||||
BootstrapTranslatableModel('wagtailpages.HomepageTakeActionCards'),
|
||||
BootstrapTranslatableModel('wagtailpages.HomepageFocusAreas'),
|
||||
BootstrapTranslatableModel('wagtailpages.DonationModals'),
|
||||
BootstrapTranslatableModel('wagtailpages.DonationModal'),
|
||||
BootstrapTranslatableModel('wagtailpages.ProductPageCategory'),
|
||||
BootstrapTranslatableModel('wagtailpages.RelatedProducts'),
|
||||
BootstrapTranslatableModel('wagtailpages.ProductPagePrivacyPolicyLink'),
|
||||
BootstrapTranslatableModel('wagtailpages.ProductUpdates'),
|
||||
BootstrapTranslatableModel('wagtailpages.ExcludedCategories'),
|
||||
BootstrapTranslatableModel('wagtailpages.FocusArea'),
|
||||
BootstrapTranslatableModel('wagtailpages.Petition'),
|
||||
BootstrapTranslatableModel('wagtailpages.Signup'),
|
||||
BootstrapTranslatableModel('wagtailpages.ContentAuthor'),
|
||||
BootstrapTranslatableModel('wagtailpages.BuyersGuideProductCategory'),
|
||||
BootstrapTranslatableModel('wagtailpages.Update'),
|
||||
BootstrapTranslatableModel('wagtailpages.BlogPageCategory'),
|
||||
BootstrapTranslatableModel('wagtailpages.InitiativeSection'),
|
||||
BootstrapTranslatableModel('wagtailpages.HomepageSpotlightPosts'),
|
||||
BootstrapTranslatableModel('wagtailpages.HomepageNewsYouCanUse'),
|
||||
BootstrapTranslatableModel('wagtailpages.InitiativesHighlights'),
|
||||
BootstrapTranslatableModel('wagtailpages.CTA4'),
|
||||
BootstrapTranslatableModel('wagtailpages.ParticipateHighlights'),
|
||||
BootstrapTranslatableModel('wagtailpages.ParticipateHighlights2'),
|
||||
|
||||
]
|
|
@ -0,0 +1,374 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-04 16:17
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('wagtailpages', '0023_bootstrap_migrations'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='homepagefocusareas',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagefocusareas',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagetakeactioncards',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagetakeactioncards',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='partnerlogos',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='partnerlogos',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='homepagefocusareas',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='homepagetakeactioncards',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='partnerlogos',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='donationmodals',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='donationmodals',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='donationmodals',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='excludedcategories',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='excludedcategories',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productpagecategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productpagecategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productpageprivacypolicylink',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productpageprivacypolicylink',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productupdates',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='productupdates',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='relatedproducts',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='relatedproducts',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='excludedcategories',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='productpagecategory',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='productpageprivacypolicylink',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='productupdates',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='relatedproducts',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='blogpagecategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='blogpagecategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='buyersguideproductcategory',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='buyersguideproductcategory',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='donationmodal',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='donationmodal',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='donationmodal',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='focusarea',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='focusarea',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='update',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='update',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='blogpagecategory',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='buyersguideproductcategory',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='focusarea',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='update',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='contentauthor',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='contentauthor',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cta',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cta',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='contentauthor',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cta',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cta4',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='cta4',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagenewsyoucanuse',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagenewsyoucanuse',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagespotlightposts',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='homepagespotlightposts',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='initiativesection',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='initiativesection',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='initiativeshighlights',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='initiativeshighlights',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='participatehighlights',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='participatehighlights',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='participatehighlights2',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='participatehighlights2',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cta4',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='homepagenewsyoucanuse',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='homepagespotlightposts',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='initiativesection',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='initiativeshighlights',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='participatehighlights',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='participatehighlights2',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
# Meta classes from TranslatableMixin's
|
||||
migrations.AlterModelOptions(
|
||||
name='cta4',
|
||||
options={},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='participatehighlights',
|
||||
options={},
|
||||
),
|
||||
migrations.AlterModelOptions(
|
||||
name='participatehighlights2',
|
||||
options={},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,25 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-10 16:53
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0024_translation_mixin_migration'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterUniqueTogether(
|
||||
name='cta',
|
||||
unique_together=set(),
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cta',
|
||||
name='locale',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='cta',
|
||||
name='translation_key',
|
||||
),
|
||||
]
|
|
@ -0,0 +1,35 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-10 16:55
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('wagtailpages', '0025_remove_localization_from_cta_model'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='petition',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='petition',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='locale',
|
||||
field=models.ForeignKey(editable=False, null=True, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(editable=False, null=True),
|
||||
),
|
||||
]
|
|
@ -0,0 +1,16 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-10 16:55
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
from wagtail.core.models import BootstrapTranslatableModel
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0026_add_localization_to_subclasses'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
BootstrapTranslatableModel('wagtailpages.Petition'),
|
||||
BootstrapTranslatableModel('wagtailpages.Signup'),
|
||||
]
|
|
@ -0,0 +1,46 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-10 18:23
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailcore', '0062_comment_models_and_pagesubscription'),
|
||||
('wagtailpages', '0027_bootstrap_subclassed_cta_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='petition',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='petition',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='signup',
|
||||
name='locale',
|
||||
field=models.ForeignKey(default=1, editable=False, on_delete=django.db.models.deletion.PROTECT, related_name='+', to='wagtailcore.locale'),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='signup',
|
||||
name='translation_key',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='petition',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
migrations.AlterUniqueTogether(
|
||||
name='signup',
|
||||
unique_together={('translation_key', 'locale')},
|
||||
),
|
||||
]
|
|
@ -0,0 +1,55 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-23 21:40
|
||||
|
||||
from django.db import migrations
|
||||
import networkapi.wagtailpages.fields
|
||||
|
||||
|
||||
def update_software_product_fields(apps, schema_editor):
|
||||
SoftwareProductPage = apps.get_model("wagtailpages", "SoftwareProductPage")
|
||||
|
||||
# ExtendedBoolean is char(3), so the original boolean
|
||||
# values True/False become the string values 'tru'/'fal'.
|
||||
|
||||
for product in SoftwareProductPage.objects.all():
|
||||
if product.easy_to_learn_and_use == 'tru':
|
||||
product.easy_to_learn_and_use = 'Yes'
|
||||
|
||||
if product.easy_to_learn_and_use == 'fal':
|
||||
product.easy_to_learn_and_use = 'No'
|
||||
|
||||
if product.easy_to_learn_and_use == None:
|
||||
product.easy_to_learn_and_use = 'U'
|
||||
|
||||
if product.medical_privacy_compliant == 'tru':
|
||||
product.medical_privacy_compliant = 'Yes'
|
||||
|
||||
if product.medical_privacy_compliant == 'fal':
|
||||
product.medical_privacy_compliant = 'No'
|
||||
|
||||
if product.medical_privacy_compliant == None:
|
||||
product.medical_privacy_compliant = 'U'
|
||||
|
||||
product.save()
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0028_translation_mixin_migration_for_cta_models'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='easy_to_learn_and_use',
|
||||
field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Is it easy to learn & use the features?', null=True, default='U'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='medical_privacy_compliant',
|
||||
field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Compliant with US medical privacy laws?', null=True, default='U'),
|
||||
),
|
||||
migrations.RunPython(
|
||||
code=update_software_product_fields
|
||||
),
|
||||
]
|
|
@ -0,0 +1,24 @@
|
|||
# Generated by Django 3.1.11 on 2021-06-23 22:05
|
||||
|
||||
from django.db import migrations
|
||||
import networkapi.wagtailpages.fields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('wagtailpages', '0029_fix_software_fields_part_1'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='easy_to_learn_and_use',
|
||||
field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Is it easy to learn & use the features?'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='softwareproductpage',
|
||||
name='medical_privacy_compliant',
|
||||
field=networkapi.wagtailpages.fields.ExtendedBoolean(help_text='Compliant with US medical privacy laws?'),
|
||||
),
|
||||
]
|
|
@ -2,13 +2,16 @@ from django.conf import settings
|
|||
from django.db import models
|
||||
|
||||
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, MultiFieldPanel
|
||||
from wagtail.core.models import Page, Orderable as WagtailOrderable
|
||||
from wagtail.core.models import TranslatableMixin, Page, Orderable as WagtailOrderable
|
||||
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail.admin.edit_handlers import PageChooserPanel
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from modelcluster.fields import ParentalKey
|
||||
|
||||
from .primary import PrimaryPage
|
||||
|
@ -22,7 +25,7 @@ class NewsPage(PrimaryPage):
|
|||
template = 'wagtailpages/static/news_page.html'
|
||||
|
||||
|
||||
class InitiativeSection(models.Model):
|
||||
class InitiativeSection(TranslatableMixin, models.Model):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.InitiativesPage',
|
||||
related_name='initiative_sections',
|
||||
|
@ -76,6 +79,16 @@ class InitiativeSection(models.Model):
|
|||
FieldPanel('sectionButtonURL2'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
SynchronizedField('sectionImage'),
|
||||
TranslatableField('sectionHeader'),
|
||||
TranslatableField('sectionCopy'),
|
||||
TranslatableField('sectionButtonTitle'),
|
||||
SynchronizedField('sectionButtonURL'),
|
||||
TranslatableField('sectionButtonTitle2'),
|
||||
SynchronizedField('sectionButtonURL2'),
|
||||
]
|
||||
|
||||
|
||||
class InitiativesPage(PrimaryPage):
|
||||
template = 'wagtailpages/static/initiatives_page.html'
|
||||
|
@ -125,6 +138,24 @@ class InitiativesPage(PrimaryPage):
|
|||
InlinePanel('featured_highlights', label='Highlights', max_num=9),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
SynchronizedField('primaryHero'),
|
||||
TranslatableField('header'),
|
||||
TranslatableField('subheader'),
|
||||
TranslatableField('h3'),
|
||||
TranslatableField('sub_h3'),
|
||||
TranslatableField('featured_highlights'),
|
||||
TranslatableField('initiative_sections'),
|
||||
]
|
||||
|
||||
|
||||
class ParticipatePage2(PrimaryPage):
|
||||
template = 'wagtailpages/static/participate_page2.html'
|
||||
|
@ -236,6 +267,39 @@ class ParticipatePage2(PrimaryPage):
|
|||
verbose_name='H2 Subheader',
|
||||
)
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
SynchronizedField('ctaHero'),
|
||||
TranslatableField('ctaHeroHeader'),
|
||||
TranslatableField('ctaHeroSubhead'),
|
||||
TranslatableField('ctaButtonTitle'),
|
||||
TranslatableField('ctaButtonURL'),
|
||||
SynchronizedField('ctaHero2'),
|
||||
TranslatableField('ctaHeroHeader2'),
|
||||
TranslatableField('ctaHeroSubhead2'),
|
||||
TranslatableField('ctaButtonTitle2'),
|
||||
TranslatableField('ctaButtonURL2'),
|
||||
SynchronizedField('ctaHero3'),
|
||||
TranslatableField('ctaHeroHeader3'),
|
||||
TranslatableField('ctaHeroSubhead3'),
|
||||
TranslatableField('ctaFacebook3'),
|
||||
TranslatableField('ctaTwitter3'),
|
||||
TranslatableField('ctaEmailShareBody3'),
|
||||
TranslatableField('ctaEmailShareSubject3'),
|
||||
TranslatableField('h2'),
|
||||
TranslatableField('h2Subheader'),
|
||||
TranslatableField('featured_highlights'),
|
||||
TranslatableField('featured_highlights2'),
|
||||
TranslatableField('cta4'),
|
||||
]
|
||||
|
||||
content_panels = Page.content_panels + [
|
||||
MultiFieldPanel(
|
||||
[
|
||||
|
@ -284,7 +348,7 @@ class Styleguide(PrimaryPage):
|
|||
template = 'wagtailpages/static/styleguide.html'
|
||||
|
||||
|
||||
class HomepageSpotlightPosts(WagtailOrderable):
|
||||
class HomepageSpotlightPosts(TranslatableMixin, WagtailOrderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.Homepage',
|
||||
related_name='spotlight_posts',
|
||||
|
@ -294,7 +358,7 @@ class HomepageSpotlightPosts(WagtailOrderable):
|
|||
PageChooserPanel('blog'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'blog'
|
||||
verbose_name_plural = 'blogs'
|
||||
ordering = ['sort_order'] # not automatically inherited!
|
||||
|
@ -303,7 +367,7 @@ class HomepageSpotlightPosts(WagtailOrderable):
|
|||
return self.page.title + '->' + self.blog.title
|
||||
|
||||
|
||||
class HomepageNewsYouCanUse(WagtailOrderable):
|
||||
class HomepageNewsYouCanUse(TranslatableMixin, WagtailOrderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.Homepage',
|
||||
related_name='news_you_can_use',
|
||||
|
@ -313,7 +377,7 @@ class HomepageNewsYouCanUse(WagtailOrderable):
|
|||
PageChooserPanel('blog'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'blog'
|
||||
verbose_name_plural = 'blogs'
|
||||
ordering = ['sort_order'] # not automatically inherited!
|
||||
|
@ -322,7 +386,7 @@ class HomepageNewsYouCanUse(WagtailOrderable):
|
|||
return self.page.title + '->' + self.blog.title
|
||||
|
||||
|
||||
class InitiativesHighlights(WagtailOrderable, models.Model):
|
||||
class InitiativesHighlights(TranslatableMixin, WagtailOrderable, models.Model):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.InitiativesPage',
|
||||
related_name='featured_highlights',
|
||||
|
@ -332,7 +396,7 @@ class InitiativesHighlights(WagtailOrderable, models.Model):
|
|||
SnippetChooserPanel('highlight'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'highlight'
|
||||
verbose_name_plural = 'highlights'
|
||||
ordering = ['sort_order'] # not automatically inherited!
|
||||
|
@ -381,7 +445,7 @@ class CTABase(WagtailOrderable, models.Model):
|
|||
FieldPanel('buttonURL'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
abstract = True
|
||||
verbose_name = 'cta'
|
||||
verbose_name_plural = 'ctas'
|
||||
|
@ -391,14 +455,17 @@ class CTABase(WagtailOrderable, models.Model):
|
|||
return self.page.title + '->' + self.highlight.title
|
||||
|
||||
|
||||
class CTA4(CTABase):
|
||||
class CTA4(TranslatableMixin, CTABase):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.ParticipatePage2',
|
||||
related_name='cta4',
|
||||
)
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
pass
|
||||
|
||||
class ParticipateHighlightsBase(WagtailOrderable, models.Model):
|
||||
|
||||
class ParticipateHighlightsBase(TranslatableMixin, WagtailOrderable, models.Model):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.ParticipatePage2',
|
||||
related_name='featured_highlights',
|
||||
|
@ -424,6 +491,9 @@ class ParticipateHighlights(ParticipateHighlightsBase):
|
|||
related_name='featured_highlights',
|
||||
)
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
pass
|
||||
|
||||
|
||||
class ParticipateHighlights2(ParticipateHighlightsBase):
|
||||
page = ParentalKey(
|
||||
|
@ -431,9 +501,12 @@ class ParticipateHighlights2(ParticipateHighlightsBase):
|
|||
related_name='featured_highlights2',
|
||||
)
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
pass
|
||||
|
||||
|
||||
@register_snippet
|
||||
class FocusArea(models.Model):
|
||||
class FocusArea(TranslatableMixin, models.Model):
|
||||
interest_icon = models.ForeignKey(
|
||||
'wagtailimages.Image',
|
||||
null=True,
|
||||
|
@ -466,15 +539,21 @@ class FocusArea(models.Model):
|
|||
PageChooserPanel('page'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
SynchronizedField('interest_icon'),
|
||||
TranslatableField('name'),
|
||||
TranslatableField('description'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Area of focus'
|
||||
verbose_name_plural = 'Areas of focus'
|
||||
|
||||
|
||||
class HomepageFocusAreas(WagtailOrderable):
|
||||
class HomepageFocusAreas(TranslatableMixin, WagtailOrderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.Homepage',
|
||||
related_name='focus_areas',
|
||||
|
@ -486,8 +565,11 @@ class HomepageFocusAreas(WagtailOrderable):
|
|||
SnippetChooserPanel('area'),
|
||||
]
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Homepage Focus Area'
|
||||
|
||||
class HomepageTakeActionCards(WagtailOrderable):
|
||||
|
||||
class HomepageTakeActionCards(TranslatableMixin, WagtailOrderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.Homepage',
|
||||
related_name='take_action_cards',
|
||||
|
@ -512,15 +594,21 @@ class HomepageTakeActionCards(WagtailOrderable):
|
|||
PageChooserPanel('internal_link'),
|
||||
]
|
||||
|
||||
# translatable_fields = [
|
||||
# SynchronizedField('image'),
|
||||
# TranslatableField('text'),
|
||||
# SynchronizedField('internal_link'),
|
||||
# ]
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Take Action Card"
|
||||
ordering = ['sort_order'] # not automatically inherited!
|
||||
|
||||
|
||||
class PartnerLogos(WagtailOrderable):
|
||||
class PartnerLogos(TranslatableMixin, WagtailOrderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.Homepage',
|
||||
related_name='partner_logos',
|
||||
|
@ -549,12 +637,19 @@ class PartnerLogos(WagtailOrderable):
|
|||
FieldPanel('width'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
SynchronizedField('logo'),
|
||||
TranslatableField('name'),
|
||||
SynchronizedField('link'),
|
||||
SynchronizedField('width'),
|
||||
]
|
||||
|
||||
@property
|
||||
def image_rendition(self):
|
||||
width = self.width * 2
|
||||
return self.logo.get_rendition(f'width-{width}')
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Partner Logo'
|
||||
ordering = ['sort_order'] # not automatically inherited!
|
||||
|
||||
|
@ -736,6 +831,41 @@ class Homepage(FoundationMetadataPageMixin, Page):
|
|||
),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('hero_headline'),
|
||||
SynchronizedField('hero_image'),
|
||||
TranslatableField('hero_button_text'),
|
||||
SynchronizedField('hero_button_url'),
|
||||
SynchronizedField('spotlight_image'),
|
||||
TranslatableField('spotlight_headline'),
|
||||
TranslatableField('cause_statement'),
|
||||
TranslatableField('cause_statement_link_text'),
|
||||
TranslatableField('cause_statement_link_page'),
|
||||
SynchronizedField('quote_image'),
|
||||
TranslatableField('quote_text'),
|
||||
TranslatableField('quote_source_name'),
|
||||
TranslatableField('quote_source_job_title'),
|
||||
TranslatableField('partner_heading'),
|
||||
TranslatableField('partner_intro_text'),
|
||||
TranslatableField('partner_page_text'),
|
||||
SynchronizedField('partner_page'),
|
||||
SynchronizedField('partner_background_image'),
|
||||
TranslatableField('take_action_title'),
|
||||
TranslatableField('focus_areas'),
|
||||
TranslatableField('take_action_cards'),
|
||||
TranslatableField('partner_logos'),
|
||||
TranslatableField('spotlight_posts'),
|
||||
TranslatableField('news_you_can_use'),
|
||||
]
|
||||
|
||||
subpage_types = [
|
||||
'BanneredCampaignPage',
|
||||
'BlogIndexPage',
|
||||
|
|
|
@ -11,11 +11,13 @@ from wagtail.admin.edit_handlers import (
|
|||
StreamFieldPanel,
|
||||
)
|
||||
from wagtail.core import blocks
|
||||
from wagtail.core.models import Orderable, Page
|
||||
from wagtail.core.models import Orderable, Locale, Page
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
|
||||
from wagtail_localize.fields import TranslatableField, SynchronizedField
|
||||
|
||||
from taggit.models import TaggedItemBase
|
||||
from modelcluster.fields import ParentalKey, ParentalManyToManyField
|
||||
from modelcluster.contrib.taggit import ClusterTaggableManager
|
||||
|
@ -177,6 +179,18 @@ class BlogPage(FoundationMetadataPageMixin, Page):
|
|||
PrivacyModalPanel(),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('body'),
|
||||
TranslatableField('title'),
|
||||
]
|
||||
|
||||
subpage_types = [
|
||||
'ArticlePage'
|
||||
]
|
||||
|
@ -194,11 +208,8 @@ class BlogPage(FoundationMetadataPageMixin, Page):
|
|||
context['related_posts'] = related_posts
|
||||
|
||||
# Pull this object specifically using the English page title
|
||||
blog_page = BlogIndexPage.objects.get(title_en__iexact='Blog')
|
||||
|
||||
# If that doesn't yield the blog page, pull using the universal title
|
||||
if blog_page is None:
|
||||
blog_page = BlogIndexPage.objects.get(title__iexact='Blog')
|
||||
default_locale = Locale.objects.get(language_code=settings.LANGUAGE_CODE)
|
||||
blog_page = BlogIndexPage.objects.get(title__iexact='Blog', locale=default_locale)
|
||||
|
||||
if blog_page:
|
||||
context['blog_index'] = blog_page
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
from django.db import models
|
||||
from django.template.defaultfilters import slugify
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.core.models import TranslatableMixin
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
|
||||
@register_snippet
|
||||
class BlogPageCategory(models.Model):
|
||||
class BlogPageCategory(TranslatableMixin, models.Model):
|
||||
name = models.CharField(
|
||||
max_length=50
|
||||
)
|
||||
|
@ -41,6 +42,6 @@ class BlogPageCategory(models.Model):
|
|||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Blog Page Category"
|
||||
verbose_name_plural = "Blog Page Categories"
|
||||
|
|
|
@ -54,11 +54,14 @@ class BlogIndexPage(IndexPage):
|
|||
'featured_pages',
|
||||
label='Featured',
|
||||
help_text='Choose two blog pages to feature',
|
||||
min_num=2,
|
||||
min_num=0,
|
||||
max_num=2,
|
||||
)
|
||||
]
|
||||
|
||||
# Empty translatable fields
|
||||
translatable_fields = IndexPage.translatable_fields
|
||||
|
||||
template = 'wagtailpages/blog_index_page.html'
|
||||
|
||||
def get_all_entries(self):
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
from .index import IndexPage
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from networkapi.wagtailpages.pagemodels.publications.publication import PublicationPage
|
||||
|
||||
|
||||
|
@ -19,6 +21,20 @@ class CampaignIndexPage(IndexPage):
|
|||
'ArticlePage'
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields from IndexPage
|
||||
TranslatableField('title'),
|
||||
TranslatableField('intro'),
|
||||
TranslatableField('header'),
|
||||
SynchronizedField('page_size'),
|
||||
]
|
||||
|
||||
template = 'wagtailpages/index_page.html'
|
||||
|
||||
def get_context(self, request):
|
||||
|
|
|
@ -3,11 +3,13 @@ import json
|
|||
from django.db import models
|
||||
|
||||
from wagtail.admin.edit_handlers import FieldPanel, InlinePanel, StreamFieldPanel
|
||||
from wagtail.core.models import Page
|
||||
from wagtail.core.models import TranslatableMixin, Page
|
||||
from wagtail.core.fields import RichTextField
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from taggit.models import TaggedItemBase
|
||||
from modelcluster.fields import ParentalKey
|
||||
from modelcluster.contrib.taggit import ClusterTaggableManager
|
||||
|
@ -53,7 +55,7 @@ class CTA(models.Model):
|
|||
|
||||
|
||||
@register_snippet
|
||||
class Signup(CTA):
|
||||
class Signup(TranslatableMixin, CTA):
|
||||
campaign_id = models.CharField(
|
||||
max_length=20,
|
||||
help_text='Which campaign identifier should this petition be tied to?',
|
||||
|
@ -66,7 +68,13 @@ class Signup(CTA):
|
|||
default=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
translatable_fields = [
|
||||
# Fields from the CTA model
|
||||
TranslatableField('header'),
|
||||
TranslatableField('description'),
|
||||
]
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'signup snippet'
|
||||
|
||||
|
||||
|
@ -82,7 +90,17 @@ class OpportunityPage(MiniSiteNameSpace):
|
|||
'RedirectingPage',
|
||||
'PublicationPage',
|
||||
'ArticlePage'
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
TranslatableField('seo_title'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('header'),
|
||||
TranslatableField('body'),
|
||||
]
|
||||
|
||||
class Meta:
|
||||
|
@ -91,7 +109,7 @@ class OpportunityPage(MiniSiteNameSpace):
|
|||
|
||||
|
||||
@register_snippet
|
||||
class Petition(CTA):
|
||||
class Petition(TranslatableMixin, CTA):
|
||||
campaign_id = models.CharField(
|
||||
max_length=20,
|
||||
help_text='Which campaign identifier should this petition be tied to?',
|
||||
|
@ -175,7 +193,23 @@ class Petition(CTA):
|
|||
default='Thank you for signing too!',
|
||||
)
|
||||
|
||||
class Meta:
|
||||
translatable_fields = [
|
||||
# This models fields
|
||||
SynchronizedField('requires_country_code'),
|
||||
SynchronizedField('requires_postal_code'),
|
||||
TranslatableField('comment_requirements'),
|
||||
TranslatableField('checkbox_1'),
|
||||
TranslatableField('checkbox_2'),
|
||||
SynchronizedField('share_twitter'),
|
||||
SynchronizedField('share_facebook'),
|
||||
SynchronizedField('share_email'),
|
||||
TranslatableField('thank_you'),
|
||||
# Fields from the CTA model
|
||||
TranslatableField('header'),
|
||||
TranslatableField('description'),
|
||||
]
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'petition snippet'
|
||||
|
||||
|
||||
|
@ -208,6 +242,23 @@ class CampaignPage(MiniSiteNameSpace):
|
|||
StreamFieldPanel('body'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('cta'),
|
||||
TranslatableField('title'),
|
||||
TranslatableField('header'),
|
||||
SynchronizedField('narrowed_page_content'),
|
||||
SynchronizedField('zen_nav'),
|
||||
TranslatableField('body'),
|
||||
TranslatableField('donation_modals'),
|
||||
]
|
||||
|
||||
subpage_types = [
|
||||
'CampaignPage',
|
||||
'RedirectingPage',
|
||||
|
@ -264,6 +315,25 @@ class BanneredCampaignPage(PrimaryPage):
|
|||
FieldPanel('tags'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('header'),
|
||||
TranslatableField('intro'),
|
||||
TranslatableField('body'),
|
||||
TranslatableField("title"),
|
||||
SynchronizedField("banner"),
|
||||
SynchronizedField("narrowed_page_content"),
|
||||
SynchronizedField("zen_nav"),
|
||||
TranslatableField("cta"),
|
||||
TranslatableField("signup"),
|
||||
]
|
||||
|
||||
subpage_types = [
|
||||
'BanneredCampaignPage',
|
||||
'RedirectingPage',
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
from django.db import models
|
||||
|
||||
from wagtail.admin.edit_handlers import FieldPanel
|
||||
from wagtail.core.models import TranslatableMixin
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
|
||||
@register_snippet
|
||||
class ContentAuthor(models.Model):
|
||||
class ContentAuthor(TranslatableMixin, models.Model):
|
||||
name = models.CharField(max_length=70, blank=False)
|
||||
|
||||
image = models.ForeignKey(
|
||||
|
|
|
@ -40,7 +40,7 @@ class RecentBlogEntries(blocks.StructBlock):
|
|||
def get_context(self, value, parent_context=None):
|
||||
context = super().get_context(value, parent_context=parent_context)
|
||||
BlogIndexPage = apps.get_model('wagtailpages.BlogIndexPage')
|
||||
blogpage = BlogIndexPage.objects.get(title_en__iexact="blog")
|
||||
blogpage = BlogIndexPage.objects.get(title__iexact="blog")
|
||||
|
||||
tag = value.get("tag_filter", False)
|
||||
category = value.get("category_filter", False)
|
||||
|
|
|
@ -4,6 +4,8 @@ from wagtail.admin.edit_handlers import StreamFieldPanel, MultiFieldPanel, Field
|
|||
from wagtail.core.models import Page
|
||||
from wagtail.core.fields import StreamField
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from wagtail.core import blocks
|
||||
from . import customblocks
|
||||
from .mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
|
@ -53,6 +55,23 @@ class DearInternetPage(FoundationMetadataPageMixin, Page):
|
|||
),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('intro_texts'),
|
||||
TranslatableField('letters_section_heading'),
|
||||
TranslatableField('letters'),
|
||||
TranslatableField('cta'),
|
||||
TranslatableField('cta_button_text'),
|
||||
SynchronizedField('cta_button_link'),
|
||||
]
|
||||
|
||||
zen_nav = True
|
||||
|
||||
def get_context(self, request):
|
||||
|
|
|
@ -13,6 +13,8 @@ from wagtail.admin.edit_handlers import FieldPanel
|
|||
from wagtail.core.models import Page
|
||||
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from .mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
|
||||
from networkapi.wagtailpages.utils import (
|
||||
|
@ -61,6 +63,20 @@ class IndexPage(FoundationMetadataPageMixin, RoutablePageMixin, Page):
|
|||
FieldPanel('page_size'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('intro'),
|
||||
TranslatableField('header'),
|
||||
SynchronizedField('page_size'),
|
||||
]
|
||||
|
||||
def get_context(self, request):
|
||||
# bootstrap the render context
|
||||
context = super().get_context(request)
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
from taggit.models import Tag
|
||||
|
||||
from wagtailmetadata.models import MetadataPageMixin
|
||||
from wagtail.images.models import Image
|
||||
|
||||
|
@ -69,5 +70,11 @@ class FoundationMetadataPageMixin(MetadataPageMixin):
|
|||
# whatever is the default social share image. Which could be `None`!
|
||||
return default_social_share_image
|
||||
|
||||
def get_admin_display_title(self):
|
||||
title = self.draft_title or self.title
|
||||
if self.locale:
|
||||
return f"({self.locale.language_code}) {title}"
|
||||
return title
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
from django.conf import settings
|
||||
from wagtail.core.models import Locale
|
||||
|
||||
|
||||
class LocalizedSnippet():
|
||||
|
||||
DEFAULT_LOCALE = None
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super().__init__(*args, **kwargs)
|
||||
if self.DEFAULT_LOCALE is None:
|
||||
self.DEFAULT_LOCALE = Locale.objects.get(language_code=settings.LANGUAGE_CODE)
|
||||
|
||||
@property
|
||||
def original(self):
|
||||
try:
|
||||
return self.get_translation(self.DEFAULT_LOCALE)
|
||||
except AttributeError:
|
||||
return self
|
|
@ -3,6 +3,7 @@ from django.db import models
|
|||
from wagtail.admin.edit_handlers import FieldPanel, MultiFieldPanel, StreamFieldPanel
|
||||
from wagtail.core.models import Page
|
||||
from wagtail.core.fields import StreamField
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from .base_fields import base_fields
|
||||
from .mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
|
@ -56,6 +57,19 @@ class ModularPage(FoundationMetadataPageMixin, Page):
|
|||
StreamFieldPanel('body'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('header'),
|
||||
SynchronizedField('narrowed_page_content'),
|
||||
SynchronizedField('zen_nav'),
|
||||
]
|
||||
|
||||
show_in_menus_default = True
|
||||
|
||||
def get_context(self, request):
|
||||
|
|
|
@ -5,6 +5,8 @@ from wagtail.core.models import Page
|
|||
from wagtail.core.fields import StreamField
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from .base_fields import base_fields
|
||||
from .mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
from .mixin.foundation_banner_inheritance import FoundationBannerInheritanceMixin
|
||||
|
@ -78,6 +80,23 @@ class PrimaryPage(FoundationMetadataPageMixin, FoundationBannerInheritanceMixin,
|
|||
StreamFieldPanel('body'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('header'),
|
||||
SynchronizedField('banner'),
|
||||
TranslatableField('intro'),
|
||||
TranslatableField('body'),
|
||||
SynchronizedField('narrowed_page_content'),
|
||||
SynchronizedField('zen_nav'),
|
||||
]
|
||||
|
||||
subpage_types = [
|
||||
'PrimaryPage',
|
||||
'RedirectingPage',
|
||||
|
|
|
@ -17,15 +17,17 @@ from modelcluster.fields import ParentalKey
|
|||
|
||||
from wagtail.admin.edit_handlers import InlinePanel, FieldPanel, MultiFieldPanel, PageChooserPanel
|
||||
from wagtail.contrib.routable_page.models import RoutablePageMixin, route
|
||||
from wagtail.core.models import Orderable, Page
|
||||
from wagtail.core.models import Locale, Orderable, Page, TranslatableMixin
|
||||
|
||||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.search import index
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
from wagtail.snippets.models import register_snippet
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
from wagtail_airtable.mixins import AirtableMixin
|
||||
|
||||
from networkapi.wagtailpages.fields import ExtendedYesNoField
|
||||
from networkapi.wagtailpages.fields import ExtendedBoolean, ExtendedYesNoField
|
||||
from networkapi.wagtailpages.pagemodels.mixin.foundation_metadata import (
|
||||
FoundationMetadataPageMixin
|
||||
)
|
||||
|
@ -33,7 +35,7 @@ from networkapi.wagtailpages.utils import insert_panels_after
|
|||
|
||||
# TODO: Move this util function
|
||||
from networkapi.buyersguide.utils import get_category_og_image_upload_path
|
||||
|
||||
from .mixin.snippets import LocalizedSnippet
|
||||
|
||||
TRACK_RECORD_CHOICES = [
|
||||
('Great', 'Great'),
|
||||
|
@ -43,16 +45,63 @@ TRACK_RECORD_CHOICES = [
|
|||
]
|
||||
|
||||
|
||||
def get_product_subset(cutoff_date, authenticated, key, products):
|
||||
def get_language_code_from_request(request):
|
||||
"""
|
||||
Accepts a request. Returns a language code (string) if there is one. Falls back to English.
|
||||
"""
|
||||
language_code = settings.LANGUAGE_CODE
|
||||
if hasattr(request, 'LANGUAGE_CODE'):
|
||||
language_code = request.LANGUAGE_CODE
|
||||
return language_code
|
||||
|
||||
|
||||
def get_categories_for_locale(language_code):
|
||||
"""
|
||||
Start with the English list of categories, and replace any of them
|
||||
with their localized counterpart, where possible, so that we don't
|
||||
end up with an incomplete category list due to missing locale records.
|
||||
"""
|
||||
DEFAULT_LANGUAGE_CODE = settings.LANGUAGE_CODE
|
||||
DEFAULT_LOCALE = Locale.objects.get(language_code=DEFAULT_LANGUAGE_CODE)
|
||||
|
||||
default_locale_list = BuyersGuideProductCategory.objects.filter(
|
||||
hidden=False,
|
||||
locale=DEFAULT_LOCALE,
|
||||
)
|
||||
|
||||
if language_code == DEFAULT_LANGUAGE_CODE:
|
||||
return default_locale_list
|
||||
|
||||
try:
|
||||
actual_locale = Locale.objects.get(language_code=language_code)
|
||||
except Locale.DoesNotExist:
|
||||
actual_locale = Locale.objects.get(language_code=settings.LANGUAGE_CODE)
|
||||
|
||||
return [
|
||||
BuyersGuideProductCategory.objects.filter(
|
||||
translation_key=cat.translation_key,
|
||||
locale=actual_locale,
|
||||
).first() or cat for cat in default_locale_list
|
||||
]
|
||||
|
||||
|
||||
def get_product_subset(cutoff_date, authenticated, key, products, language_code='en'):
|
||||
"""
|
||||
filter a queryset based on our current cutoff date,
|
||||
as well as based on whether a user is authenticated
|
||||
to the system or not (authenticated users get to
|
||||
see all products, including draft products)
|
||||
"""
|
||||
products = products.filter(review_date__gte=cutoff_date)
|
||||
try:
|
||||
locale = Locale.objects.get(language_code=language_code)
|
||||
except Locale.DoesNotExist:
|
||||
locale = Locale.objects.get(language_code=settings.LANGUAGE_CODE)
|
||||
|
||||
products = products.filter(review_date__gte=cutoff_date, locale=locale)
|
||||
|
||||
if not authenticated:
|
||||
products = products.live()
|
||||
|
||||
products = sort_average(products)
|
||||
return cache.get_or_set(key, products, 86400)
|
||||
|
||||
|
@ -65,7 +114,7 @@ def sort_average(products):
|
|||
|
||||
|
||||
@register_snippet
|
||||
class BuyersGuideProductCategory(models.Model):
|
||||
class BuyersGuideProductCategory(TranslatableMixin, LocalizedSnippet, models.Model):
|
||||
"""
|
||||
A simple category class for use with Buyers Guide products,
|
||||
registered as snippet so that we can moderate them if and
|
||||
|
@ -105,29 +154,33 @@ class BuyersGuideProductCategory(models.Model):
|
|||
blank=True,
|
||||
)
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField('name'),
|
||||
TranslatableField('description'),
|
||||
SynchronizedField('slug'),
|
||||
]
|
||||
|
||||
@property
|
||||
def published_product_page_count(self):
|
||||
return ProductPage.objects.filter(product_categories__category=self).live().count()
|
||||
|
||||
@property
|
||||
def published_product_count(self):
|
||||
# TODO: REMOVE: LEGACY FUNCTION
|
||||
return ProductPage.objects.filter(product_category=self, draft=False).count()
|
||||
|
||||
def __str__(self):
|
||||
return self.name
|
||||
|
||||
def save(self, *args, **kwargs):
|
||||
self.slug = slugify(self.name_en if self.name_en else self.name)
|
||||
self.slug = slugify(self.name)
|
||||
super().save(*args, **kwargs)
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Buyers Guide Product Category"
|
||||
verbose_name_plural = "Buyers Guide Product Categories"
|
||||
ordering = ['sort_order', 'name', ]
|
||||
|
||||
|
||||
class ProductPageVotes(models.Model):
|
||||
"""
|
||||
PNI product voting bins. This does not need translating.
|
||||
"""
|
||||
vote_bins = models.CharField(default="0,0,0,0,0", max_length=50, validators=[int_list_validator])
|
||||
|
||||
def set_votes(self, bin_list):
|
||||
|
@ -145,7 +198,7 @@ class ProductPageVotes(models.Model):
|
|||
return votes
|
||||
|
||||
|
||||
class ProductPageCategory(Orderable):
|
||||
class ProductPageCategory(TranslatableMixin, Orderable):
|
||||
product = ParentalKey(
|
||||
'wagtailpages.ProductPage',
|
||||
related_name='product_categories',
|
||||
|
@ -165,11 +218,11 @@ class ProductPageCategory(Orderable):
|
|||
def __str__(self):
|
||||
return self.category.name
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Product Category"
|
||||
|
||||
|
||||
class RelatedProducts(Orderable):
|
||||
class RelatedProducts(TranslatableMixin, Orderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.ProductPage',
|
||||
related_name='related_product_pages',
|
||||
|
@ -187,8 +240,11 @@ class RelatedProducts(Orderable):
|
|||
PageChooserPanel('related_product')
|
||||
]
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Related Product'
|
||||
|
||||
class ProductPagePrivacyPolicyLink(Orderable):
|
||||
|
||||
class ProductPagePrivacyPolicyLink(TranslatableMixin, Orderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.ProductPage',
|
||||
related_name='privacy_policy_links',
|
||||
|
@ -211,12 +267,20 @@ class ProductPagePrivacyPolicyLink(Orderable):
|
|||
FieldPanel('url'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField('label'),
|
||||
SynchronizedField('url'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return f'{self.page.title}: {self.label} ({self.url})'
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Privacy Link'
|
||||
|
||||
|
||||
@register_snippet
|
||||
class Update(index.Indexed, models.Model):
|
||||
class Update(TranslatableMixin, index.Indexed, models.Model):
|
||||
source = models.URLField(
|
||||
max_length=2048,
|
||||
help_text='Link to source',
|
||||
|
@ -258,15 +322,22 @@ class Update(index.Indexed, models.Model):
|
|||
index.SearchField('title', partial_match=True),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
SynchronizedField('source'),
|
||||
SynchronizedField('title'),
|
||||
SynchronizedField('author'),
|
||||
SynchronizedField('snippet'),
|
||||
]
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
||||
class Meta:
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = "Buyers Guide Product Update"
|
||||
verbose_name_plural = "Buyers Guide Product Updates"
|
||||
|
||||
|
||||
class ProductUpdates(Orderable):
|
||||
class ProductUpdates(TranslatableMixin, Orderable):
|
||||
page = ParentalKey(
|
||||
'wagtailpages.ProductPage',
|
||||
related_name='updates',
|
||||
|
@ -281,10 +352,17 @@ class ProductUpdates(Orderable):
|
|||
null=True
|
||||
)
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField("update"),
|
||||
]
|
||||
|
||||
panels = [
|
||||
SnippetChooserPanel('update'),
|
||||
]
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Product Update'
|
||||
|
||||
|
||||
class ProductPage(AirtableMixin, FoundationMetadataPageMixin, Page):
|
||||
"""
|
||||
|
@ -698,6 +776,54 @@ class ProductPage(AirtableMixin, FoundationMetadataPageMixin, Page):
|
|||
),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('privacy_ding'),
|
||||
SynchronizedField('adult_content'),
|
||||
SynchronizedField('uses_wifi'),
|
||||
SynchronizedField('uses_bluetooth'),
|
||||
SynchronizedField('review_date'),
|
||||
SynchronizedField('company'),
|
||||
TranslatableField('blurb'),
|
||||
SynchronizedField('product_url'),
|
||||
TranslatableField('price'),
|
||||
SynchronizedField('image'),
|
||||
TranslatableField('worst_case'),
|
||||
SynchronizedField('signup_requires_email'),
|
||||
SynchronizedField('signup_requires_phone'),
|
||||
SynchronizedField('signup_requires_third_party_account'),
|
||||
TranslatableField('signup_requirement_explanation'),
|
||||
SynchronizedField('signup_requires_third_party_account'),
|
||||
TranslatableField('how_does_it_use_data_collected'),
|
||||
SynchronizedField('data_collection_policy_is_bad'),
|
||||
SynchronizedField('user_friendly_privacy_policy'),
|
||||
TranslatableField('user_friendly_privacy_policy_helptext'),
|
||||
SynchronizedField('show_ding_for_minimum_security_standards'),
|
||||
SynchronizedField('meets_minimum_security_standards'),
|
||||
SynchronizedField('uses_encryption'),
|
||||
TranslatableField('uses_encryption_helptext'),
|
||||
SynchronizedField('security_updates'),
|
||||
TranslatableField('security_updates_helptext'),
|
||||
SynchronizedField('strong_password'),
|
||||
TranslatableField('strong_password_helptext'),
|
||||
SynchronizedField('manage_vulnerabilities'),
|
||||
TranslatableField('manage_vulnerabilities_helptext'),
|
||||
SynchronizedField('privacy_policy'),
|
||||
TranslatableField('privacy_policy_helptext'),
|
||||
SynchronizedField('phone_number'),
|
||||
SynchronizedField('live_chat'),
|
||||
SynchronizedField('email'),
|
||||
SynchronizedField('twitter'),
|
||||
]
|
||||
|
||||
@property
|
||||
def product_type(self):
|
||||
return "unknown"
|
||||
|
@ -717,7 +843,8 @@ class ProductPage(AirtableMixin, FoundationMetadataPageMixin, Page):
|
|||
def get_context(self, request, *args, **kwargs):
|
||||
context = super().get_context(request, *args, **kwargs)
|
||||
context['product'] = self
|
||||
context['categories'] = BuyersGuideProductCategory.objects.filter(hidden=False)
|
||||
language_code = get_language_code_from_request(request)
|
||||
context['categories'] = get_categories_for_locale(language_code)
|
||||
context['mediaUrl'] = settings.MEDIA_URL
|
||||
context['use_commento'] = settings.USE_COMMENTO
|
||||
context['pageTitle'] = f'{self.title} | ' + gettext("Privacy & security guide") + ' | Mozilla Foundation'
|
||||
|
@ -813,11 +940,8 @@ class SoftwareProductPage(ProductPage):
|
|||
max_length=5000,
|
||||
blank=True
|
||||
)
|
||||
# NullBooleanField is deprecated as of Django 3.1.
|
||||
# We're using it here primarily for a data migration, but we should
|
||||
# move to BooleanField as soon as it's safe to do so with the content we have
|
||||
medical_privacy_compliant = models.NullBooleanField(
|
||||
null=True,
|
||||
|
||||
medical_privacy_compliant = ExtendedBoolean(
|
||||
help_text='Compliant with US medical privacy laws?'
|
||||
)
|
||||
|
||||
|
@ -832,11 +956,8 @@ class SoftwareProductPage(ProductPage):
|
|||
max_length=5000,
|
||||
blank=True
|
||||
)
|
||||
# NullBooleanField is deprecated as of Django 3.1.
|
||||
# We're using it here primarily for a data migration, but we should
|
||||
# move to BooleanField as soon as it's safe to do so with the content we have
|
||||
easy_to_learn_and_use = models.NullBooleanField(
|
||||
null=True,
|
||||
|
||||
easy_to_learn_and_use = ExtendedBoolean(
|
||||
help_text='Is it easy to learn & use the features?',
|
||||
)
|
||||
|
||||
|
@ -909,10 +1030,22 @@ class SoftwareProductPage(ProductPage):
|
|||
],
|
||||
)
|
||||
|
||||
translatable_fields = ProductPage.translatable_fields + [
|
||||
TranslatableField('handles_recordings_how'),
|
||||
SynchronizedField('recording_alert'),
|
||||
TranslatableField('recording_alert_helptext'),
|
||||
SynchronizedField('medical_privacy_compliant'),
|
||||
TranslatableField('medical_privacy_compliant_helptext'),
|
||||
TranslatableField('host_controls'),
|
||||
SynchronizedField('easy_to_learn_and_use'),
|
||||
TranslatableField('easy_to_learn_and_use_helptext'),
|
||||
]
|
||||
|
||||
@property
|
||||
def product_type(self):
|
||||
return "software"
|
||||
|
||||
# TODO: Needs translatable_fields
|
||||
class Meta:
|
||||
verbose_name = "Software Product Page"
|
||||
|
||||
|
@ -1171,6 +1304,23 @@ class GeneralProductPage(ProductPage):
|
|||
],
|
||||
)
|
||||
|
||||
translatable_fields = ProductPage.translatable_fields + [
|
||||
TranslatableField('personal_data_collected'),
|
||||
TranslatableField('biometric_data_collected'),
|
||||
TranslatableField('social_data_collected'),
|
||||
TranslatableField('how_can_you_control_your_data'),
|
||||
SynchronizedField('data_control_policy_is_bad'),
|
||||
SynchronizedField('company_track_record'),
|
||||
SynchronizedField('track_record_is_bad'),
|
||||
TranslatableField('track_record_details'),
|
||||
SynchronizedField('offline_capable'),
|
||||
TranslatableField('offline_use_description'),
|
||||
SynchronizedField('uses_ai'),
|
||||
SynchronizedField('ai_uses_personal_data'),
|
||||
SynchronizedField('ai_is_transparent'),
|
||||
TranslatableField('ai_helptext'),
|
||||
]
|
||||
|
||||
@property
|
||||
def product_type(self):
|
||||
return "general"
|
||||
|
@ -1179,8 +1329,10 @@ class GeneralProductPage(ProductPage):
|
|||
verbose_name = "General Product Page"
|
||||
|
||||
|
||||
class ExcludedCategories(Orderable):
|
||||
"""This allows us to select one or more blog authors from Snippets."""
|
||||
class ExcludedCategories(TranslatableMixin, Orderable):
|
||||
"""
|
||||
This allows us to filter categories from showing up on the PNI site
|
||||
"""
|
||||
|
||||
page = ParentalKey("wagtailpages.BuyersGuidePage", related_name="excluded_categories")
|
||||
category = models.ForeignKey(
|
||||
|
@ -1195,6 +1347,9 @@ class ExcludedCategories(Orderable):
|
|||
def __str__(self):
|
||||
return self.category.name
|
||||
|
||||
class Meta(TranslatableMixin.Meta):
|
||||
verbose_name = 'Excluded Category'
|
||||
|
||||
|
||||
class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
||||
"""
|
||||
|
@ -1254,6 +1409,18 @@ class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
|||
),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
TranslatableField('title'),
|
||||
SynchronizedField('hero_image'),
|
||||
TranslatableField('header'),
|
||||
TranslatableField('intro_text'),
|
||||
SynchronizedField('dark_theme'),
|
||||
# Promote tab fields
|
||||
TranslatableField('seo_title'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
]
|
||||
|
||||
@route(r'^about/$', name='how-to-use-view')
|
||||
def about_page(self, request):
|
||||
context = self.get_context(request)
|
||||
|
@ -1327,16 +1494,35 @@ class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
|||
@route(r'^categories/(?P<slug>[\w\W]+)/', name='category-view')
|
||||
def categories_page(self, request, slug):
|
||||
context = self.get_context(request, bypass_products=True)
|
||||
language_code = get_language_code_from_request(request)
|
||||
locale_id = Locale.objects.get(language_code=language_code).id
|
||||
slug = slugify(slug)
|
||||
|
||||
# If getting by slug fails, also try to get it by name.
|
||||
DEFAULT_LOCALE = Locale.objects.get(language_code=settings.LANGUAGE_CODE)
|
||||
DEFAULT_LOCALE_ID = DEFAULT_LOCALE.id
|
||||
|
||||
# because we may be working with localized content, and the slug
|
||||
# will always be our english slug, we need to find the english
|
||||
# category first, and then find its corresponding localized version
|
||||
try:
|
||||
category = BuyersGuideProductCategory.objects.get(slug=slug)
|
||||
original_category = BuyersGuideProductCategory.objects.get(slug=slug, locale_id=DEFAULT_LOCALE_ID)
|
||||
except BuyersGuideProductCategory.DoesNotExist:
|
||||
category = get_object_or_404(BuyersGuideProductCategory, name__iexact=slug)
|
||||
original_category = get_object_or_404(BuyersGuideProductCategory, name__iexact=slug)
|
||||
|
||||
if locale_id != DEFAULT_LOCALE_ID:
|
||||
try:
|
||||
category = BuyersGuideProductCategory.objects.get(
|
||||
translation_key=original_category.translation_key,
|
||||
locale_id=DEFAULT_LOCALE_ID,
|
||||
)
|
||||
except BuyersGuideProductCategory.DoesNotExist:
|
||||
category = original_category
|
||||
else:
|
||||
category = original_category
|
||||
|
||||
authenticated = request.user.is_authenticated
|
||||
key = f'cat_product_dicts_{slug}_auth' if authenticated else f'cat_product_dicts_{slug}_live'
|
||||
key = f'{language_code}_{key}'
|
||||
products = cache.get(key)
|
||||
exclude_cat_ids = [excats.category.id for excats in self.excluded_categories.all()]
|
||||
|
||||
|
@ -1345,11 +1531,13 @@ class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
|||
self.cutoff_date,
|
||||
authenticated,
|
||||
key,
|
||||
ProductPage.objects.filter(product_categories__category__in=[category])
|
||||
.exclude(product_categories__category__id__in=exclude_cat_ids)
|
||||
ProductPage.objects.filter(product_categories__category__in=[original_category])
|
||||
.exclude(product_categories__category__id__in=exclude_cat_ids),
|
||||
language_code=language_code
|
||||
)
|
||||
|
||||
context['category'] = category.slug
|
||||
context['category'] = slug
|
||||
context['current_category'] = category
|
||||
context['products'] = products
|
||||
context['pageTitle'] = f'{category} | ' + gettext("Privacy & security guide") + ' | Mozilla Foundation'
|
||||
context['template_cache_key_fragment'] = f'{category.slug}_{request.LANGUAGE_CODE}'
|
||||
|
@ -1389,9 +1577,11 @@ class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
|||
|
||||
def get_context(self, request, *args, **kwargs):
|
||||
context = super().get_context(request, *args, **kwargs)
|
||||
language_code = get_language_code_from_request(request)
|
||||
|
||||
authenticated = request.user.is_authenticated
|
||||
key = 'home_product_dicts_authed' if authenticated else 'home_product_dicts_live'
|
||||
key = f'{key}_{language_code}'
|
||||
products = cache.get(key)
|
||||
exclude_cat_ids = [excats.category.id for excats in self.excluded_categories.all()]
|
||||
|
||||
|
@ -1400,10 +1590,11 @@ class BuyersGuidePage(RoutablePageMixin, FoundationMetadataPageMixin, Page):
|
|||
self.cutoff_date,
|
||||
authenticated,
|
||||
key,
|
||||
ProductPage.objects.exclude(product_categories__category__id__in=exclude_cat_ids)
|
||||
ProductPage.objects.exclude(product_categories__category__id__in=exclude_cat_ids),
|
||||
language_code=language_code
|
||||
)
|
||||
|
||||
context['categories'] = BuyersGuideProductCategory.objects.filter(hidden=False)
|
||||
context['categories'] = get_categories_for_locale(language_code)
|
||||
context['products'] = products
|
||||
context['web_monetization_pointer'] = settings.WEB_MONETIZATION_POINTER
|
||||
pni_home_page = BuyersGuidePage.objects.first()
|
||||
|
|
|
@ -8,6 +8,8 @@ from wagtail.documents.edit_handlers import DocumentChooserPanel
|
|||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from networkapi.wagtailpages.models import ContentAuthor, PublicationPage
|
||||
from networkapi.wagtailpages.utils import get_plaintext_titles, set_main_site_nav_information, TitleWidget
|
||||
|
||||
|
@ -115,6 +117,23 @@ class ArticlePage(FoundationMetadataPageMixin, Page):
|
|||
InlinePanel("footnotes", label="Footnotes"),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
SynchronizedField('toc_thumbnail_image'),
|
||||
SynchronizedField('hero_image'),
|
||||
TranslatableField('subtitle'),
|
||||
SynchronizedField('article_file'),
|
||||
TranslatableField('body'),
|
||||
TranslatableField('footnotes'),
|
||||
]
|
||||
|
||||
@property
|
||||
def is_publication_article(self):
|
||||
parent = self.get_parent().specific
|
||||
|
|
|
@ -9,6 +9,8 @@ from wagtail.documents.edit_handlers import DocumentChooserPanel
|
|||
from wagtail.images.edit_handlers import ImageChooserPanel
|
||||
from wagtail.snippets.edit_handlers import SnippetChooserPanel
|
||||
|
||||
from wagtail_localize.fields import SynchronizedField, TranslatableField
|
||||
|
||||
from networkapi.wagtailpages.models import ContentAuthor
|
||||
from networkapi.wagtailpages.utils import set_main_site_nav_information
|
||||
from ..mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
|
@ -117,6 +119,27 @@ class PublicationPage(FoundationMetadataPageMixin, Page):
|
|||
FieldPanel('notes'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField("title"),
|
||||
TranslatableField("subtitle"),
|
||||
TranslatableField('secondary_subtitle'),
|
||||
SynchronizedField('toc_thumbnail_image'),
|
||||
SynchronizedField('hero_image'),
|
||||
SynchronizedField('publication_date'),
|
||||
SynchronizedField('publication_file'),
|
||||
TranslatableField('additional_author_copy'),
|
||||
TranslatableField('intro_notes'),
|
||||
TranslatableField('contents_title'),
|
||||
TranslatableField('notes'),
|
||||
]
|
||||
|
||||
@property
|
||||
def is_publication_page(self):
|
||||
"""
|
||||
|
|
|
@ -5,6 +5,8 @@ from wagtail.core import blocks
|
|||
from wagtail.core.models import Page
|
||||
from wagtail.core.fields import StreamField
|
||||
|
||||
from wagtail_localize.fields import TranslatableField, SynchronizedField
|
||||
|
||||
from . import customblocks
|
||||
from .mixin.foundation_metadata import FoundationMetadataPageMixin
|
||||
from ..utils import set_main_site_nav_information
|
||||
|
@ -51,6 +53,22 @@ class YoutubeRegretsPage(FoundationMetadataPageMixin, Page):
|
|||
StreamFieldPanel('regret_stories'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('headline'),
|
||||
TranslatableField('intro_text'),
|
||||
TranslatableField('intro_images'),
|
||||
TranslatableField('faq'),
|
||||
TranslatableField('regret_stories'),
|
||||
]
|
||||
|
||||
zen_nav = True
|
||||
|
||||
def get_context(self, request):
|
||||
|
@ -81,6 +99,20 @@ class YoutubeRegretsReporterPage(FoundationMetadataPageMixin, Page):
|
|||
StreamFieldPanel('intro_images'),
|
||||
]
|
||||
|
||||
translatable_fields = [
|
||||
# Promote tab fields
|
||||
SynchronizedField('slug'),
|
||||
TranslatableField('seo_title'),
|
||||
SynchronizedField('show_in_menus'),
|
||||
TranslatableField('search_description'),
|
||||
SynchronizedField('search_image'),
|
||||
# Content tab fields
|
||||
TranslatableField('title'),
|
||||
TranslatableField('headline'),
|
||||
TranslatableField('intro_text'),
|
||||
TranslatableField('intro_images'),
|
||||
]
|
||||
|
||||
zen_nav = True
|
||||
|
||||
def get_context(self, request):
|
||||
|
|
|
@ -26,7 +26,7 @@ class RSSFeed(Feed):
|
|||
# as a BlogIndexPage, to make sure we're not filtering out all the
|
||||
# "featured" posts (which we need to do for site content purposes).
|
||||
try:
|
||||
index = IndexPage.objects.get(title_en__iexact='Blog')
|
||||
index = IndexPage.objects.get(title__iexact='Blog')
|
||||
|
||||
except IndexPage.DoesNotExist:
|
||||
# If that doesn't yield the blog page, pull using the universal title
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{% extends "pages/base.html" %}
|
||||
|
||||
{% load bg_nav_tags localization i18n static wagtailroutablepage_tags wagtailmetadata_tags %}
|
||||
{% load bg_nav_tags localization i18n static wagtailroutablepage_tags wagtailmetadata_tags debug_tags %}
|
||||
|
||||
{% get_current_language as lang_code %}
|
||||
|
||||
|
@ -85,15 +85,18 @@
|
|||
<div class="row">
|
||||
<div class="col">
|
||||
{% if pagetype == "product" or pagetype == "about" %}
|
||||
<a class="multipage-link active" href="{{ home_page.url }}">{% trans "All" %}</a>
|
||||
<a class="multipage-link active" href="{% relocalized_url home_page.localized.url lang_code %}">{% trans "All" %}</a>
|
||||
{% else %}
|
||||
<a class="multipage-link {% if not category %} active{% endif %}" href="{{ home_page.url }}">{% trans "All" %}</a>
|
||||
<a class="multipage-link {% if not category %} active{% endif %}" href="{% relocalized_url home_page.localized.url lang_code %}">{% trans "All" %}</a>
|
||||
{% endif %}
|
||||
|
||||
{% for cat in categories %}
|
||||
{% if cat.published_product_page_count > 0 %}
|
||||
{% routablepageurl home_page 'category-view' cat.slug as cat_url %}
|
||||
<a class="multipage-link {% check_active_category current_category cat %}{% if cat.featured is True %} featured{% endif %}{% if category == cat.slug %} active{% endif %}" href="{{ cat_url }}" data-name="{{ cat.name }}">{{ cat.name }}</a>
|
||||
{% with original=cat.original %}
|
||||
{% if original.published_product_page_count > 0 %}
|
||||
{% localizedroutablepageurl home_page 'category-view' lang_code original.slug as cat_url %}
|
||||
<a class="multipage-link {% check_active_category current_category cat %}{% if original.featured is True %} featured{% endif %}" href="{{ cat_url }}" data-name="{{ original.name }}">{{ cat.name }}</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -68,13 +68,13 @@
|
|||
{# User is not logged in. Return cached results. 24 hour caching applied. #}
|
||||
{% cache 86400 pni_home_page template_cache_key_fragment %}
|
||||
{% for product in products %}
|
||||
{% include "../fragments/buyersguide_item.html" with product=product %}
|
||||
{% include "../fragments/buyersguide_item.html" with product=product.localized %}
|
||||
{% endfor %}
|
||||
{% endcache %}
|
||||
{% else %}
|
||||
{# User is logged in. Don't cache their results so they can see live and draft products here. #}
|
||||
{% for product in products %}
|
||||
{% include "../fragments/buyersguide_item.html" with product=product %}
|
||||
{% include "../fragments/buyersguide_item.html" with product=product.localized %}
|
||||
{% endfor %}
|
||||
{% endif %}
|
||||
</div>
|
||||
|
|
|
@ -5,13 +5,15 @@
|
|||
{% endcomment %}
|
||||
|
||||
{% for cat in sorted_categories %}
|
||||
{% with original=cat.original %}
|
||||
{% if cat.hidden == False and cat.published_product_page_count > 0 %}
|
||||
{% url 'category-view' cat.slug as cat_url %}
|
||||
{% localizedroutablepageurl home_page 'category-view' lang_code original.slug as cat_url %}
|
||||
<a
|
||||
class="multipage-link {% check_active_category current_category cat %}{% if cat.featured is True %} featured{% endif %}"
|
||||
class="multipage-link {% check_active_category current_category cat %}{% if original.featured is True %} featured{% endif %}"
|
||||
href="{{ cat_url }}"
|
||||
data-name="{{ cat.name }}">
|
||||
data-name="{{ original.name }}">
|
||||
{{ cat.name }}
|
||||
</a>
|
||||
{% endif %}
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
{% extends "partials/primary_nav.html" %}
|
||||
|
||||
{% load bg_nav_tags i18n %}
|
||||
{% load bg_nav_tags i18n localization %}
|
||||
|
||||
{% get_current_language as lang_code %}
|
||||
|
||||
{% block nav_logo %}
|
||||
<div class="d-flex align-items-center logo-section">
|
||||
<a href="/" class="moz-logo mb-0 mr-3"><span class="sr-only">Mozilla</span></a>
|
||||
<p class="mb-0 h3-heading flex-wrap">
|
||||
<a class="link-back" href="{{ home_page.url }}">{% trans "*privacy not included" context 'Buyer’s guide name. This can be localized. This is a reference to the “*batteries not included” mention on toys.' %}</a>
|
||||
<a class="link-back" href="{% relocalized_url home_page.url lang_code %}">{% trans "*privacy not included" context 'Buyer’s guide name. This can be localized. This is a reference to the “*batteries not included” mention on toys.' %}</a>
|
||||
</p>
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
||||
{% block narrow_screen_nav_links %}
|
||||
{% url 'buyersguide-home' as home_url %}
|
||||
<div><a class="{% bg_active_nav request.get_full_path home_url %}" href="{{ home_url }}">{% trans "Privacy Not Included" %}</a></div>
|
||||
<div><a class="{% bg_active_nav request.get_full_path home_url %}" href="{% relocalized_url home_url lang_code %}">{% trans "Privacy Not Included" %}</a></div>
|
||||
{% include "buyersguide/fragments/pni_nav_links.html" with pre="<div>" post="</div>" %}
|
||||
{% endblock %}
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
{% extends "buyersguide/bg_base.html" %}
|
||||
|
||||
{% load bg_selector_tags env l10n i18n static wagtailimages_tags %}
|
||||
{% load bg_selector_tags env l10n i18n localization static wagtailimages_tags %}
|
||||
|
||||
{% get_current_language as lang_code %}
|
||||
|
||||
{% block head_extra %}
|
||||
<meta property="og:title" content="{% blocktrans context "This can be localized. This is a reference to the “*batteries not included” mention on toys." %}privacy not included - {{ product.title }}{% endblocktrans %}" />
|
||||
|
@ -295,9 +297,9 @@
|
|||
<h3 class="h2-heading mb-4">{% trans "Related products" %}</h3>
|
||||
<div class="row">
|
||||
{% for related_product_page in product.related_product_pages.all %}
|
||||
{% with related_product=related_product_page.related_product %}
|
||||
{% with related_product=related_product_page.related_product.localized %}
|
||||
<div class="related-product col-6 col-md-3 mb-3 mb-md-0">
|
||||
<a class="d-block{% if related_product.adult_content %} adult-content{% endif %}" href="{{ related_product.url }}">
|
||||
<a class="d-block{% if related_product.adult_content %} adult-content{% endif %}" href="{% relocalized_url related_product.url lang_code %}">
|
||||
<div class="img-container">
|
||||
{% image related_product.image width-600 as img %}
|
||||
<img
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
{% load static i18n wagtailimages_tags %}
|
||||
{% load static i18n wagtailimages_tags localization %}
|
||||
|
||||
{% get_current_language as lang_code %}
|
||||
|
||||
<figure class="product-box d-flex flex-column justify-content-between{% if product.draft %} draft-product{% endif %}{% if product.adult_content %} adult-content{% endif %}{% if product.privacy_ding %} privacy-ding{% endif%}" data-creepiness="{{ product.creepiness }}">
|
||||
<div class="top-left-badge-container">
|
||||
|
@ -15,7 +16,7 @@
|
|||
|
||||
{% include "fragments/adult_content_badge.html" with product=product %}
|
||||
|
||||
<a class="product-image text-center mt-4 h-100 d-flex flex-column justify-content-between" href="{{ product.url }}">
|
||||
<a class="product-image text-center mt-4 h-100 d-flex flex-column justify-content-between" href="{% relocalized_url product.url lang_code %}">
|
||||
<picture class="product-thumbnail">
|
||||
<source
|
||||
{% image product.image fill-360x360 as img_1x %}
|
||||
|
@ -32,7 +33,7 @@
|
|||
</a>
|
||||
|
||||
<figcaption class="d-block mt-md-2 text-left">
|
||||
<a class="product-links" href="{{ product.url }}">
|
||||
<a class="product-links" href="{% relocalized_url product.url lang_code %}">
|
||||
<div class="product-company body-small">{{product.company}}</div>
|
||||
<div class="product-name body">{{product.title}}</div>
|
||||
</a>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
</div>
|
||||
<div class="col-12">
|
||||
{% for child_page in child_pages %}
|
||||
{% with child=child_page.child %}
|
||||
{% with child=child_page.child.localized %}
|
||||
<div class="row publication-row pt-3 pb-3 d-flex align-items-center">
|
||||
<div class="col-sm-1 d-md-block d-none"> </div>
|
||||
<div class="col-auto">
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
</div>
|
||||
<div class="col-12">
|
||||
{% for child_page in child_pages %}
|
||||
{% with child=child_page.child %}
|
||||
{% with child=child_page.child.localized %}
|
||||
<div class="row publication-row pt-3 pb-sm-4 pb-0">
|
||||
<div class="col-auto">
|
||||
<div class="publication-chapter-number"
|
||||
|
@ -44,24 +44,28 @@
|
|||
{{ child.title }} {% if child.has_unpublished_changes %}🐣{% endif %}
|
||||
{% endif %}
|
||||
</h3>
|
||||
{% for grandchild in child_page.grandchildren %}
|
||||
{% for ancestor in child_page.grandchildren %}
|
||||
{% with grandchild=ancestor.localized %}
|
||||
<h4 class="d-sm-block d-none body">
|
||||
<a href="{{ grandchild.url }}" class="d-block w-75 publication-chapter-article-link">
|
||||
{{ grandchild.title }}
|
||||
</a>
|
||||
</h4>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
{% if child_page.grandchildren %}
|
||||
{# Child listings on mobile. #}
|
||||
<div class="pt-2 d-sm-none d-block">
|
||||
{% for grandchild in child_page.grandchildren %}
|
||||
{% for ancestor in child_page.grandchildren %}
|
||||
{% with grandchild=ancestor.localized %}
|
||||
<h4 class="body">
|
||||
<a href="{{ grandchild.url }}" class="d-block publication-chapter-article-link">
|
||||
{{ grandchild.title }} {% if child.has_unpublished_changes %}🐣{% endif %}
|
||||
</a>
|
||||
</h4>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -8,5 +8,5 @@
|
|||
{% include "./product_criterion.html" with label=handles_recordings_how value=product.handles_recordings_how %}
|
||||
{% endif %}
|
||||
|
||||
{% include "./product_criterion.html" with label=recording_alert value=product.recording_alert|extended_yes_no help=product.recording_alert_helptext %}
|
||||
{% include "./product_criterion.html" with label=medical_privacy_compliant value=product.medical_privacy_compliant|yes_no help=product.medical_privacy_compliant_helptext %}
|
||||
{% include "./product_criterion.html" with label=recording_alert value=product.recording_alert|extended_yes_no help=product.recording_alert_helptext %}
|
||||
{% include "./product_criterion.html" with label=medical_privacy_compliant value=product.medical_privacy_compliant|extended_boolean help=product.medical_privacy_compliant_helptext %}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
<div class="section-cause-statement dark-theme p-5 text-center">
|
||||
<p class="h4-heading">{{ page.cause_statement }}</p>
|
||||
{% if page.cause_statement_link_text and page.cause_statement_link_page %}
|
||||
<a href="{{page.cause_statement_link_page.url}}" class="cta-link" id="homepage-cause-statement-cta">{{page.cause_statement_link_text}}</a>
|
||||
<a href="{{page.cause_statement_link_page.localized.url}}" class="cta-link" id="homepage-cause-statement-cta">{{page.cause_statement_link_text}}</a>
|
||||
{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
<p>{{ area.description }}</p>
|
||||
|
||||
{% if area.page %}<div class="mb-4 learn-more-link">
|
||||
<a href="{{ area.page.url }}" aria-label="{% blocktrans with name=area.name %}Learn more about: {{ name }}{% endblocktrans %}">{% trans "Learn more →" %}</a>
|
||||
<a href="{{ area.page.localized.url }}" aria-label="{% blocktrans with name=area.name %}Learn more about: {{ name }}{% endblocktrans %}">{% trans "Learn more →" %}</a>
|
||||
</div>{% endif %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
|
||||
{% endcomment %}
|
||||
|
||||
{% with first=items.first.blog %}
|
||||
{% with first=items.first.blog.localized %}
|
||||
<div class="d-none d-xl-block col-xl-12 feature mb-md-5">
|
||||
<div class="position-relative h-100 d-flex justify-content-end">
|
||||
<div class="feature-image">
|
||||
|
@ -56,22 +56,24 @@
|
|||
|
||||
{% with item_1_class="d-xl-none mb-5 mb-xl-0" item_2_class="mb-5 mb-xl-0" item_3_class="mb-5 mb-md-0" %}
|
||||
{% for item in items %}
|
||||
{% with localized=item.blog.localized %}
|
||||
<div class="col-12 col-md-6 col-xl-4 d-flex {% if forloop.counter == 1 %} {{item_1_class}}{% endif %} {% if forloop.counter == 2 %} {{item_2_class}}{% endif %} {% if forloop.counter == 3 %} {{item_3_class}}{% endif %}">
|
||||
<div class="bg-white">
|
||||
<img src="{% image_url item.blog.get_meta_image "fill-700x394" %}" alt="" class="embed-responsive-item">
|
||||
<img src="{% image_url localized.get_meta_image "fill-700x394" %}" alt="" class="embed-responsive-item">
|
||||
<div class="p-4">
|
||||
{% if item.blog.category.count %}
|
||||
{% with category=item.blog.category.first %}
|
||||
{% if localized.category.count %}
|
||||
{% with category=localized.category.first %}
|
||||
<a class="h6-heading d-block mb-1" href="/blog/category/{{ category.slug }}">{{ category }}</a>
|
||||
{% endwith %}
|
||||
{% else %}
|
||||
<div class="h6-heading d-md-block d-none mb-1"> </div>
|
||||
{% endif %}
|
||||
<h3 class="h4-heading"><a href="{{item.blog.url}}">{{ item.blog.title }}</a></h3>
|
||||
<h3 class="h4-heading"><a href="{{localized.url}}">{{ localized.title }}</a></h3>
|
||||
{% include "./blog_authors.html" with blog_page=item.blog %}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
{% endwith %}
|
||||
|
||||
|
|
|
@ -11,7 +11,7 @@
|
|||
{{ page.partner_intro_text }}
|
||||
</p>
|
||||
{% endif %}
|
||||
<a href="{{ page.partner_page.url }}" class="text-white cta-link font-weight-bold" id="partner-cta">
|
||||
<a href="{{ page.partner_page.localized.url }}" class="text-white cta-link font-weight-bold" id="partner-cta">
|
||||
{{ page.partner_page_text }}
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
@ -14,9 +14,11 @@
|
|||
<div class="col-lg-8 offset-lg-2 dark-theme">
|
||||
{% if is_publication_article or is_publication_page %}
|
||||
<div class="mb-2 body-small publication-breadcrumb">
|
||||
{% for parent_page in self.breadcrumb_list %}
|
||||
{% for entry in self.breadcrumb_list %}
|
||||
{% with parent_page=entry.localized %}
|
||||
<a href="{{ parent_page.url }}" class="body-small">{{ parent_page.title }}</a>
|
||||
<span class='body-small'> › </span>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
|
|
@ -13,12 +13,14 @@
|
|||
|
||||
<div class="col-12 col-lg-6">
|
||||
{% for post in page.spotlight_posts.all %}
|
||||
{% with localized=post.blog.localized %}
|
||||
<div class="spotlight-post">
|
||||
<h4 class="mb-2 h5-heading">
|
||||
<a href="{{post.blog.url}}">{{post.blog.title}}</a>
|
||||
<a href="{{localized.url}}">{{localized.title}}</a>
|
||||
</h4>
|
||||
{% include "./blog_authors.html" with blog_page=post.blog %}
|
||||
{% include "./blog_authors.html" with blog_page=localized %}
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
|
||||
|
|
|
@ -9,18 +9,20 @@
|
|||
<div class="col-lg-8 col-md-12">
|
||||
<div class="row">
|
||||
{% for item in page.take_action_cards.all %}
|
||||
{% with target=item.internal_link.localized %}
|
||||
<div class="col-md-6 d-flex">
|
||||
<div class="card flex-grow-1 mb-4">
|
||||
<a href="{{ item.internal_link.url }}">
|
||||
<a href="{{ target.url }}">
|
||||
<img src="{% image_url item.image "fill-350x130" %}" class="card-img-top" alt="{{ img.alt }}" aria-label="{{ item.text }}">
|
||||
</a>
|
||||
<div class="card-body">
|
||||
<a href="{{ item.internal_link.url }}" class="h5-heading d-inline-block my-2">
|
||||
<a href="{{ target.url }}" class="h5-heading d-inline-block my-2">
|
||||
{{ item.text }}
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% endwith %}
|
||||
{% endfor %}
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
@ -7,6 +7,10 @@ register = template.Library()
|
|||
# Determine if a category nav link should be marked active
|
||||
@register.simple_tag(name='check_active_category')
|
||||
def check_active_category(current_category, target_category):
|
||||
# because we're working with potentially localized data,
|
||||
# make sure to compare the linguistic originals.
|
||||
current_category = getattr(current_category, 'original', current_category)
|
||||
target_category = getattr(target_category, 'original', target_category)
|
||||
return 'active' if current_category == target_category else ''
|
||||
|
||||
|
||||
|
@ -16,6 +20,7 @@ def bg_active_nav(current, target):
|
|||
return 'active' if urlparse(current).path == urlparse(target).path else ''
|
||||
|
||||
|
||||
"""
|
||||
# Instantiate a list of category page links based on the current page's relation to them
|
||||
# NOTE: this points to the new, namespaced category_nav_links. If we need to revert to the old app, change this back.
|
||||
@register.inclusion_tag('buyersguide/fragments/category_nav_links.html', takes_context=True)
|
||||
|
@ -25,3 +30,4 @@ def category_nav(context, current_url, current_category, all_categories):
|
|||
'current_category': current_category,
|
||||
'sorted_categories': all_categories.order_by('-featured', 'sort_order', 'name'), # featured categories first
|
||||
}
|
||||
"""
|
||||
|
|
|
@ -9,13 +9,22 @@ def yes_no(value):
|
|||
"""Converts nullish boolean to yes or no string"""
|
||||
if value is False:
|
||||
return gettext('No')
|
||||
|
||||
if value is True:
|
||||
return gettext('Yes')
|
||||
|
||||
return gettext('Unknown')
|
||||
|
||||
|
||||
@register.filter
|
||||
def extended_boolean(value):
|
||||
if value == 'Yes':
|
||||
return gettext('Yes')
|
||||
if value == 'No':
|
||||
return gettext('No')
|
||||
if value == 'U':
|
||||
return gettext('Unknown')
|
||||
return value
|
||||
|
||||
|
||||
@register.filter
|
||||
def extended_yes_no(value):
|
||||
"""Converts quad-state to human readable string"""
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
from django.template import Library
|
||||
from django.conf import settings
|
||||
register = Library()
|
||||
|
||||
if settings.DEBUG:
|
||||
print('→ Running in DEBUG mode: enabling debug template tag "inspect_object" in tag collection "debug_tags".\n')
|
||||
|
||||
@register.simple_tag
|
||||
def inspect_object(instance, prefix_label=""):
|
||||
output = str(dir(instance)).replace(', ', ',\n')
|
||||
prefix_label = str(prefix_label)
|
||||
return f'<pre>{prefix_label} {output}</pre>'
|
|
@ -4,11 +4,10 @@ import unicodedata
|
|||
from django import template
|
||||
from django.conf import settings
|
||||
from django.utils.translation import get_language_info
|
||||
from wagtail.contrib.routable_page.templatetags.wagtailroutablepage_tags import routablepageurl
|
||||
|
||||
register = template.Library()
|
||||
|
||||
DEFAULT_LOCALE = 'en_US'
|
||||
|
||||
mappings = {
|
||||
'en': 'en_US',
|
||||
'de': 'de_DE',
|
||||
|
@ -17,9 +16,12 @@ mappings = {
|
|||
'fy-NL': 'fy_NL',
|
||||
'nl': 'nl_NL',
|
||||
'pl': 'pl_PL',
|
||||
'pt': 'pt_BR', # our main focus is Brazilian Portuguese
|
||||
'pt-BR': 'pt_BR',
|
||||
}
|
||||
|
||||
DEFAULT_LOCALE_CODE = settings.LANGUAGE_CODE
|
||||
DEFAULT_LOCALE = mappings.get(DEFAULT_LOCALE_CODE)
|
||||
|
||||
|
||||
# This filter turns Wagtail language codes into OpenGraph locale strings
|
||||
@register.filter
|
||||
|
@ -43,3 +45,27 @@ def get_local_language_names():
|
|||
for lang in settings.LANGUAGES:
|
||||
languages.append([lang[0], get_language_info(lang[0])['name_local']])
|
||||
return sorted(languages, key=lambda x: locale.strxfrm(unicodedata.normalize('NFD', x[1])).casefold())
|
||||
|
||||
|
||||
# Get the url for a page, but with the locale code removed.
|
||||
@register.simple_tag()
|
||||
def get_unlocalized_url(page, locale):
|
||||
return page.get_url().replace(f'/{locale}/', '/', 1)
|
||||
|
||||
|
||||
# Force-relocalize a URL
|
||||
@register.simple_tag()
|
||||
def relocalized_url(url, locale_code):
|
||||
if locale_code == DEFAULT_LOCALE_CODE:
|
||||
return url
|
||||
return url.replace(f'/{DEFAULT_LOCALE_CODE}/', f'/{locale_code}/')
|
||||
|
||||
|
||||
# Overcome a limitation of the routablepageurl tag
|
||||
@register.simple_tag(takes_context=True)
|
||||
def localizedroutablepageurl(context, page, url_name, locale_code, *args, **kwargs):
|
||||
url = relocalized_url(
|
||||
routablepageurl(context, page, url_name, *args, **kwargs),
|
||||
locale_code,
|
||||
)
|
||||
return url
|
||||
|
|
|
@ -47,7 +47,6 @@ class BuyersGuideViewTest(TestCase):
|
|||
buyersguide = BuyersGuidePage()
|
||||
buyersguide.title = 'Privacy not included'
|
||||
buyersguide.slug = 'privacynotincluded'
|
||||
buyersguide.slug_en = 'privacynotincluded'
|
||||
homepage.add_child(instance=buyersguide)
|
||||
buyersguide.save_revision().publish()
|
||||
|
||||
|
@ -147,7 +146,6 @@ class BuyersGuideTestMixin(WagtailPageTests):
|
|||
buyersguide = BuyersGuidePage()
|
||||
buyersguide.title = 'Privacy not included'
|
||||
buyersguide.slug = 'privacynotincluded'
|
||||
buyersguide.slug_en = 'privacynotincluded'
|
||||
homepage.add_child(instance=buyersguide)
|
||||
buyersguide.save_revision().publish()
|
||||
self.homepage = Homepage.objects.first()
|
||||
|
@ -163,9 +161,7 @@ class BuyersGuideTestMixin(WagtailPageTests):
|
|||
)
|
||||
product_page = ProductPage(
|
||||
slug='product-page',
|
||||
slug_en='product-page',
|
||||
title='Product Page',
|
||||
title_en='Product Page',
|
||||
live=True,
|
||||
image=wagtail_image
|
||||
)
|
||||
|
@ -243,7 +239,7 @@ class TestBuyersGuidePage(BuyersGuideTestMixin):
|
|||
self.assertEqual(response.redirect_chain[0][0], product.url)
|
||||
|
||||
def test_sitemap_entries(self):
|
||||
response = self.client.get('/sitemap.xml')
|
||||
response = self.client.get('/en/sitemap.xml')
|
||||
context = response.context
|
||||
|
||||
self.assertEqual(context.template_name, 'sitemap.xml')
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
# TODO: REmove this and other translation.py files.
|
||||
# They aren't needed but keep coming back when we merge master into our localization branch
|
||||
from .models import (
|
||||
ModularPage,
|
||||
MiniSiteNameSpace,
|
||||
|
|
|
@ -7,11 +7,19 @@ from django.core.cache import cache
|
|||
from django.urls import reverse
|
||||
|
||||
from wagtail.admin.menu import MenuItem
|
||||
import wagtail.admin.rich_text.editors.draftail.features as draftail_features
|
||||
from wagtail.admin.rich_text.editors.draftail import features as draftail_features
|
||||
from wagtail.admin.rich_text.converters.html_to_contentstate import InlineStyleElementHandler
|
||||
from wagtail.core import hooks
|
||||
from wagtail.core.utils import find_available_slug
|
||||
from networkapi.wagtailpages.pagemodels.products import BuyersGuidePage, ProductPage
|
||||
|
||||
# The real code runs "instance.sync_trees()" here, but we want this to do nothing instead,
|
||||
# so that locale creation creates the locale entry but does not try to sync 1300+ pages as
|
||||
# part of the same web request.
|
||||
from django.db.models.signals import post_save
|
||||
from wagtail_localize.models import LocaleSynchronization, sync_trees_on_locale_sync_save
|
||||
post_save.disconnect(sync_trees_on_locale_sync_save, sender=LocaleSynchronization)
|
||||
|
||||
|
||||
# Extended rich text features for our site
|
||||
@hooks.register('register_rich_text_features')
|
||||
|
@ -104,6 +112,27 @@ def manage_pni_cache(request, page):
|
|||
cache.clear()
|
||||
|
||||
|
||||
@hooks.register('after_publish_page')
|
||||
def sync_localized_slugs(request, page):
|
||||
for translation in page.get_translations():
|
||||
translation.slug = find_available_slug(
|
||||
translation.get_parent(),
|
||||
page.slug,
|
||||
ignore_page_id=translation.id
|
||||
)
|
||||
|
||||
if translation.alias_of_id is not None:
|
||||
# This is still an alias rather than a published
|
||||
# localized page, so we can only save it as we
|
||||
# would any plain Django model:
|
||||
translation.save()
|
||||
|
||||
else:
|
||||
# If it's a real page, it needs to go through
|
||||
# the revision/publication process.
|
||||
translation.save_revision().publish()
|
||||
|
||||
|
||||
@hooks.register('after_delete_page')
|
||||
@hooks.register('after_publish_page')
|
||||
@hooks.register('after_unpublish_page')
|
||||
|
|
|
@ -421,7 +421,6 @@
|
|||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@fullhuman/postcss-purgecss/-/postcss-purgecss-4.0.3.tgz",
|
||||
"integrity": "sha512-/EnQ9UDWGGqHkn1UKAwSgh+gJHPKmD+Z+5dQ4gWT4qq2NUyez3zqAfZNwFH3eSgmgO+wjTXfhlLchx2M9/K+7Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"purgecss": "^4.0.3"
|
||||
}
|
||||
|
@ -618,8 +617,7 @@
|
|||
"acorn": {
|
||||
"version": "7.4.1",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A=="
|
||||
},
|
||||
"acorn-jsx": {
|
||||
"version": "5.3.1",
|
||||
|
@ -631,7 +629,6 @@
|
|||
"version": "1.8.2",
|
||||
"resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz",
|
||||
"integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn": "^7.0.0",
|
||||
"acorn-walk": "^7.0.0",
|
||||
|
@ -641,8 +638,7 @@
|
|||
"acorn-walk": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz",
|
||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA=="
|
||||
},
|
||||
"ajv": {
|
||||
"version": "6.12.6",
|
||||
|
@ -716,8 +712,7 @@
|
|||
"arg": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.0.tgz",
|
||||
"integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-4P8Zm2H+BRS+c/xX1LrHw0qKpEhdlZjLCgWy+d78T9vqa2Z2SiD2wMrYuWIAFy5IZUD7nnNXroRttz+0RzlrzQ=="
|
||||
},
|
||||
"argparse": {
|
||||
"version": "1.0.10",
|
||||
|
@ -1295,8 +1290,7 @@
|
|||
"bytes": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.0.tgz",
|
||||
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg=="
|
||||
},
|
||||
"cacheable-request": {
|
||||
"version": "2.1.4",
|
||||
|
@ -1366,8 +1360,7 @@
|
|||
"camelcase-css": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA=="
|
||||
},
|
||||
"camelcase-keys": {
|
||||
"version": "2.1.0",
|
||||
|
@ -1845,8 +1838,7 @@
|
|||
"css-unit-converter": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/css-unit-converter/-/css-unit-converter-1.1.2.tgz",
|
||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-IiJwMC8rdZE0+xiEZHeru6YoONC4rfPMqGm2W85jMIbkFvv5nFTwJVFHam2eFrN6txmoUYFAFXiv8ICVeTO0MA=="
|
||||
},
|
||||
"css-what": {
|
||||
"version": "4.0.0",
|
||||
|
@ -2210,8 +2202,7 @@
|
|||
"defined": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz",
|
||||
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=",
|
||||
"dev": true
|
||||
"integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM="
|
||||
},
|
||||
"dependency-graph": {
|
||||
"version": "0.9.0",
|
||||
|
@ -2222,7 +2213,6 @@
|
|||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz",
|
||||
"integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"acorn-node": "^1.6.1",
|
||||
"defined": "^1.0.0",
|
||||
|
@ -2232,8 +2222,7 @@
|
|||
"didyoumean": {
|
||||
"version": "1.2.2",
|
||||
"resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.2.tgz",
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gxtyfqMg7GKyhQmb056K7M3xszy/myH8w+B4RT+QXBQsvAOdc3XymqDDPHx1BgPgsdAA5SIifona89YtRATDzw=="
|
||||
},
|
||||
"dir-glob": {
|
||||
"version": "3.0.1",
|
||||
|
@ -2253,8 +2242,7 @@
|
|||
"dlv": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/dlv/-/dlv-1.1.3.tgz",
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-+HlytyjlPKnIG8XuRG8WvmBP8xs8P71y+SKKS6ZXWoEgLuePxtDoUEiH7WkdePWrQ5JBpE6aoVqfZfJUQkjXwA=="
|
||||
},
|
||||
"doctrine": {
|
||||
"version": "3.0.0",
|
||||
|
@ -3422,8 +3410,7 @@
|
|||
"html-tags": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/html-tags/-/html-tags-3.1.0.tgz",
|
||||
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-1qYz89hW3lFDEazhjW0yVAV87lw8lVkrJocr72XmBkMKsoSVJCQx3W8BXsC7hO2qAt8BoVjYjtAcZ9perqGnNg=="
|
||||
},
|
||||
"htmlparser2": {
|
||||
"version": "3.10.1",
|
||||
|
@ -3994,8 +3981,7 @@
|
|||
"lilconfig": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz",
|
||||
"integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg=="
|
||||
},
|
||||
"lines-and-columns": {
|
||||
"version": "1.1.6",
|
||||
|
@ -4036,8 +4022,7 @@
|
|||
"lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"lodash.debounce": {
|
||||
"version": "4.0.8",
|
||||
|
@ -4084,14 +4069,12 @@
|
|||
"lodash.toarray": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/lodash.toarray/-/lodash.toarray-4.4.0.tgz",
|
||||
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE=",
|
||||
"dev": true
|
||||
"integrity": "sha1-JMS/zWsvuji/0FlNsRedjptlZWE="
|
||||
},
|
||||
"lodash.topath": {
|
||||
"version": "4.5.2",
|
||||
"resolved": "https://registry.npmjs.org/lodash.topath/-/lodash.topath-4.5.2.tgz",
|
||||
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak=",
|
||||
"dev": true
|
||||
"integrity": "sha1-NhY1Hzu6YZlKCTGYlmC9AyVP0Ak="
|
||||
},
|
||||
"lodash.uniq": {
|
||||
"version": "4.5.0",
|
||||
|
@ -4381,8 +4364,7 @@
|
|||
"modern-normalize": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/modern-normalize/-/modern-normalize-1.1.0.tgz",
|
||||
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-2lMlY1Yc1+CUy0gw4H95uNN7vjbpoED7NNRSBHE25nWfLBdmMzFCsPshlzbxHz+gYMcBEUN8V4pU16prcdPSgA=="
|
||||
},
|
||||
"moment": {
|
||||
"version": "2.29.1",
|
||||
|
@ -4415,7 +4397,6 @@
|
|||
"version": "1.10.0",
|
||||
"resolved": "https://registry.npmjs.org/node-emoji/-/node-emoji-1.10.0.tgz",
|
||||
"integrity": "sha512-Yt3384If5H6BYGVHiHwTL+99OzJKHhgp82S8/dktEK73T26BazdgZ4JZh92xSVtGNJvz9UbXdNAc5hcrXV42vw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"lodash.toarray": "^4.4.0"
|
||||
}
|
||||
|
@ -4608,8 +4589,7 @@
|
|||
"object-hash": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-2.2.0.tgz",
|
||||
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gScRMn0bS5fH+IuwyIFgnh9zBdo4DV+6GhygmWM9HyNJSgS0hScp1f5vjtm7oIIOiT9trXrShAkLFSc2IqKNgw=="
|
||||
},
|
||||
"object-inspect": {
|
||||
"version": "1.7.0",
|
||||
|
@ -5569,7 +5549,6 @@
|
|||
"version": "14.0.2",
|
||||
"resolved": "https://registry.npmjs.org/postcss-import/-/postcss-import-14.0.2.tgz",
|
||||
"integrity": "sha512-BJ2pVK4KhUyMcqjuKs9RijV5tatNzNa73e/32aBVE/ejYPe37iH+6vAu9WvqUkB5OAYgLHzbSvzHnorybJCm9g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss-value-parser": "^4.0.0",
|
||||
"read-cache": "^1.0.0",
|
||||
|
@ -5580,7 +5559,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-3.0.3.tgz",
|
||||
"integrity": "sha512-gWnoWQXKFw65Hk/mi2+WTQTHdPD5UJdDXZmX073EY/B3BWnYjO4F4t0VneTCnCGQ5E5GsCdMkzPaTXwl3r5dJw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"camelcase-css": "^2.0.1",
|
||||
"postcss": "^8.1.6"
|
||||
|
@ -5944,7 +5922,6 @@
|
|||
"version": "5.0.5",
|
||||
"resolved": "https://registry.npmjs.org/postcss-nested/-/postcss-nested-5.0.5.tgz",
|
||||
"integrity": "sha512-GSRXYz5bccobpTzLQZXOnSOfKl6TwVr5CyAQJUPub4nuRJSOECK5AqurxVgmtxP48p0Kc/ndY/YyS1yqldX0Ew==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"postcss-selector-parser": "^6.0.4"
|
||||
},
|
||||
|
@ -5953,7 +5930,6 @@
|
|||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
|
||||
"integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
|
@ -6810,7 +6786,6 @@
|
|||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/purgecss/-/purgecss-4.0.3.tgz",
|
||||
"integrity": "sha512-PYOIn5ibRIP34PBU9zohUcCI09c7drPJJtTDAc0Q6QlRz2/CHQ8ywGLdE7ZhxU2VTqB7p5wkvj5Qcm05Rz3Jmw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"commander": "^6.0.0",
|
||||
"glob": "^7.0.0",
|
||||
|
@ -6821,8 +6796,7 @@
|
|||
"commander": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz",
|
||||
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -6969,7 +6943,6 @@
|
|||
"version": "3.6.0",
|
||||
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
|
||||
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"picomatch": "^2.2.1"
|
||||
}
|
||||
|
@ -6996,7 +6969,6 @@
|
|||
"version": "2.1.8",
|
||||
"resolved": "https://registry.npmjs.org/reduce-css-calc/-/reduce-css-calc-2.1.8.tgz",
|
||||
"integrity": "sha512-8liAVezDmUcH+tdzoEGrhfbGcP7nOV4NkGE3a74+qqvE7nt9i4sKLGBuZNOnpI4WiGksiNPklZxva80061QiPg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"css-unit-converter": "^1.1.1",
|
||||
"postcss-value-parser": "^3.3.0"
|
||||
|
@ -7005,8 +6977,7 @@
|
|||
"postcss-value-parser": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz",
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -7139,7 +7110,6 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz",
|
||||
"integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"glob": "^7.1.3"
|
||||
}
|
||||
|
@ -8519,7 +8489,6 @@
|
|||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-2.2.4.tgz",
|
||||
"integrity": "sha512-OdBCPgazNNsknSP+JfrPzkay9aqKjhKtFhbhgxHgvEFdHy/GuRPo2SCJ4w1SFTN8H6FPI4m6qD/Jj20NWY1GkA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@fullhuman/postcss-purgecss": "^4.0.3",
|
||||
"arg": "^5.0.0",
|
||||
|
@ -8558,7 +8527,6 @@
|
|||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
|
@ -8567,7 +8535,6 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz",
|
||||
"integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"normalize-path": "^3.0.0",
|
||||
"picomatch": "^2.0.4"
|
||||
|
@ -8577,7 +8544,6 @@
|
|||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
|
@ -8587,7 +8553,6 @@
|
|||
"version": "3.5.2",
|
||||
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz",
|
||||
"integrity": "sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"anymatch": "~3.1.2",
|
||||
"braces": "~3.0.2",
|
||||
|
@ -8603,7 +8568,6 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
|
@ -8614,7 +8578,6 @@
|
|||
"version": "3.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color/-/color-3.1.3.tgz",
|
||||
"integrity": "sha512-xgXAcTHa2HeFCGLE9Xs/R82hujGtu9Jd9x4NW3T34+OMs7VoPsjwzRczKHvTAHeJwWFwX5j15+MgAppE8ztObQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-convert": "^1.9.1",
|
||||
"color-string": "^1.5.4"
|
||||
|
@ -8624,7 +8587,6 @@
|
|||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
|
@ -8632,8 +8594,7 @@
|
|||
"color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=",
|
||||
"dev": true
|
||||
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8641,7 +8602,6 @@
|
|||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
|
@ -8649,14 +8609,12 @@
|
|||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA=="
|
||||
},
|
||||
"color-string": {
|
||||
"version": "1.5.5",
|
||||
"resolved": "https://registry.npmjs.org/color-string/-/color-string-1.5.5.tgz",
|
||||
"integrity": "sha512-jgIoum0OfQfq9Whcfc2z/VhCNcmQjWbey6qBX0vqt7YICflUmBCh9E9CiQD5GSJ+Uehixm3NUwHVhqUAWRivZg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"color-name": "^1.0.0",
|
||||
"simple-swizzle": "^0.2.2"
|
||||
|
@ -8666,7 +8624,6 @@
|
|||
"version": "7.0.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz",
|
||||
"integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/parse-json": "^4.0.0",
|
||||
"import-fresh": "^3.2.1",
|
||||
|
@ -8679,7 +8636,6 @@
|
|||
"version": "3.2.7",
|
||||
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz",
|
||||
"integrity": "sha512-rYGMRwip6lUMvYD3BTScMwT1HtAs2d71SMv66Vrxs0IekGZEjhM0pcMfjQPnknBt2zeCwQMEupiN02ZP4DiT1Q==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@nodelib/fs.stat": "^2.0.2",
|
||||
"@nodelib/fs.walk": "^1.2.3",
|
||||
|
@ -8692,7 +8648,6 @@
|
|||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
|
||||
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
|
@ -8703,7 +8658,6 @@
|
|||
"version": "10.0.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.0.tgz",
|
||||
"integrity": "sha512-C5owb14u9eJwizKGdchcDUQeFtlSHHthBk8pbX9Vc1PFZrLombudjDnNns88aYslCyF6IY5SUw3Roz6xShcEIQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"graceful-fs": "^4.2.0",
|
||||
"jsonfile": "^6.0.1",
|
||||
|
@ -8714,7 +8668,6 @@
|
|||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.0.tgz",
|
||||
"integrity": "sha512-Hdd4287VEJcZXUwv1l8a+vXC1GjOQqXe+VS30w/ypihpcnu9M1n3xeYeJu5CBpeEQj2nAab2xxz28GuA3vp4Ww==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-glob": "^4.0.1"
|
||||
}
|
||||
|
@ -8722,14 +8675,12 @@
|
|||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ=="
|
||||
},
|
||||
"import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
"integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"parent-module": "^1.0.0",
|
||||
"resolve-from": "^4.0.0"
|
||||
|
@ -8739,7 +8690,6 @@
|
|||
"version": "2.4.0",
|
||||
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.4.0.tgz",
|
||||
"integrity": "sha512-6A2fkfq1rfeQZjxrZJGerpLCTHRNEBiSgnu0+obeJpEPZRUooHgsizvzv0ZjJwOz3iWIHdJtVWJ/tmPr3D21/A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has": "^1.0.3"
|
||||
}
|
||||
|
@ -8748,7 +8698,6 @@
|
|||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz",
|
||||
"integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"braces": "^3.0.1",
|
||||
"picomatch": "^2.2.3"
|
||||
|
@ -8757,8 +8706,7 @@
|
|||
"picomatch": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz",
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8766,7 +8714,6 @@
|
|||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
"integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.0.0",
|
||||
"error-ex": "^1.3.1",
|
||||
|
@ -8777,14 +8724,12 @@
|
|||
"path-type": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz",
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==",
|
||||
"dev": true
|
||||
"integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw=="
|
||||
},
|
||||
"postcss-load-config": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/postcss-load-config/-/postcss-load-config-3.1.0.tgz",
|
||||
"integrity": "sha512-ipM8Ds01ZUophjDTQYSVP70slFSYg3T0/zyfII5vzhN6V57YSxMgG5syXuwi5VtS8wSf3iL30v0uBdoIVx4Q0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"import-cwd": "^3.0.0",
|
||||
"lilconfig": "^2.0.3",
|
||||
|
@ -8794,8 +8739,7 @@
|
|||
"yaml": {
|
||||
"version": "1.10.2",
|
||||
"resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz",
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8803,7 +8747,6 @@
|
|||
"version": "6.0.6",
|
||||
"resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz",
|
||||
"integrity": "sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"cssesc": "^3.0.0",
|
||||
"util-deprecate": "^1.0.2"
|
||||
|
@ -8812,14 +8755,12 @@
|
|||
"quick-lru": {
|
||||
"version": "5.1.1",
|
||||
"resolved": "https://registry.npmjs.org/quick-lru/-/quick-lru-5.1.1.tgz",
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-WuyALRjWPDGtt/wzJiadO5AXY+8hZ80hVpe6MyivgraREW751X3SbhRvG3eLKOYN+8VEvqLcf3wdnt44Z4S4SA=="
|
||||
},
|
||||
"resolve": {
|
||||
"version": "1.20.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.20.0.tgz",
|
||||
"integrity": "sha512-wENBPt4ySzg4ybFQW2TT1zMQucPK95HSh/nq2CFTZVOGut2+pQvSsgtda4d26YrYcr067wjbmzOG8byDPBX63A==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"is-core-module": "^2.2.0",
|
||||
"path-parse": "^1.0.6"
|
||||
|
@ -8828,14 +8769,12 @@
|
|||
"resolve-from": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz",
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==",
|
||||
"dev": true
|
||||
"integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g=="
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
|
@ -8843,8 +8782,7 @@
|
|||
"universalify": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz",
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ=="
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -8913,7 +8851,6 @@
|
|||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz",
|
||||
"integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"rimraf": "^3.0.0"
|
||||
}
|
||||
|
@ -9123,8 +9060,7 @@
|
|||
"util-deprecate": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=",
|
||||
"dev": true
|
||||
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||
},
|
||||
"util.promisify": {
|
||||
"version": "1.0.1",
|
||||
|
@ -9313,8 +9249,7 @@
|
|||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ=="
|
||||
},
|
||||
"y18n": {
|
||||
"version": "4.0.3",
|
||||
|
|
|
@ -117,4 +117,4 @@
|
|||
"svgo": "^2.2.2",
|
||||
"wait-on": "^5.2.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,8 +9,7 @@ python ./manage.py migrate --no-input
|
|||
python ./manage.py block_inventory
|
||||
|
||||
# Wagtail translations
|
||||
python ./manage.py sync_page_translation_fields
|
||||
python ./manage.py update_translation_fields
|
||||
# TODO: May need to add in auto syncing using wagtail-localize in the future.
|
||||
|
||||
# Clear cache for BuyersGuide
|
||||
python ./manage.py clear_cache
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
basket-client
|
||||
beautifulsoup4
|
||||
boto3
|
||||
Django==3.0.14
|
||||
Django==3.1.11
|
||||
dj-database-url
|
||||
djangorestframework
|
||||
django-admin-sortable==2.2.3
|
||||
|
@ -20,15 +20,16 @@ python-slugify
|
|||
requests
|
||||
social-auth-app-django
|
||||
wagtail-airtable
|
||||
wagtail==2.12.5
|
||||
wagtail==2.13.1
|
||||
wagtail-factories
|
||||
wagtail-localize==1.0rc3
|
||||
wagtail-localize-git==0.9.3
|
||||
wagtail-inventory==1.3
|
||||
wagtailmedia
|
||||
wagtail-metadata
|
||||
whitenoise
|
||||
wagtail-modeltranslation==0.10.17
|
||||
psycopg2-binary
|
||||
cloudinary
|
||||
sentry-sdk
|
||||
wagtail-footnotes
|
||||
git+https://github.com/MozillaFoundation/wagtail-footnotes.git@localized-footnotes
|
||||
scout-apm
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче