Enhance ValidatingEmbedBlock with strict host validation and update ArticlePage fields in migration
This commit is contained in:
parent
ee6eb0db17
commit
7c9fe7f6f9
@ -2,6 +2,8 @@ from django.core.exceptions import ValidationError
|
||||
from wagtail.embeds.blocks import EmbedBlock
|
||||
from wagtail.embeds import embeds as wagtail_embeds
|
||||
from wagtail import blocks
|
||||
from urllib.parse import urlparse
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
class ValidatingEmbedBlock(EmbedBlock):
|
||||
@ -13,13 +15,32 @@ class ValidatingEmbedBlock(EmbedBlock):
|
||||
def clean(self, value):
|
||||
value = super().clean(value)
|
||||
if value:
|
||||
try:
|
||||
# Attempt to resolve and cache embed; will raise on failure
|
||||
wagtail_embeds.get_embed(value)
|
||||
except Exception:
|
||||
raise ValidationError(
|
||||
"嵌入連結無法驗證,請確認為公開且可嵌入的 URL。"
|
||||
)
|
||||
# Inherit base validation (already run via super().clean), and add
|
||||
# optional network validation for selected providers.
|
||||
url_str = value if isinstance(value, str) else getattr(value, "url", None)
|
||||
if not url_str:
|
||||
return value
|
||||
host = (urlparse(url_str).hostname or "").lower()
|
||||
|
||||
strict_hosts = getattr(
|
||||
settings,
|
||||
"EMBED_STRICT_HOSTS",
|
||||
("instagram.com", "facebook.com"),
|
||||
)
|
||||
validate_all = getattr(settings, "EMBED_STRICT_VALIDATE_ALL", False)
|
||||
|
||||
def _matches(h: str) -> bool:
|
||||
return host == h or host.endswith("." + h)
|
||||
|
||||
must_validate = bool(validate_all or any(_matches(h) for h in strict_hosts))
|
||||
if must_validate:
|
||||
try:
|
||||
# Attempt to resolve and cache embed; will raise on failure
|
||||
wagtail_embeds.get_embed(url_str)
|
||||
except Exception:
|
||||
raise ValidationError(
|
||||
"嵌入連結無法驗證(需公開且有權杖)。請確認 URL 與設定。"
|
||||
)
|
||||
return value
|
||||
|
||||
|
||||
|
||||
@ -0,0 +1,36 @@
|
||||
# Generated by Django 5.2.7 on 2025-10-29 09:33
|
||||
|
||||
import django.db.models.deletion
|
||||
import wagtail.fields
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('home', '0007_articlepage_banner_image_alter_articlepage_body'),
|
||||
('wagtailimages', '0027_image_description'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='articlepage',
|
||||
name='banner_image',
|
||||
field=models.ForeignKey(blank=True, help_text='文章內文橫幅圖片', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlepage',
|
||||
name='body',
|
||||
field=wagtail.fields.StreamField([('heading', 0), ('paragraph', 1), ('image', 2), ('embed', 3), ('hr', 4), ('html', 5)], block_lookup={0: ('home.blocks.H2HeadingBlock', (), {'form_classname': 'full title'}), 1: ('wagtail.blocks.RichTextBlock', (), {'features': ['bold', 'italic', 'link']}), 2: ('wagtail.images.blocks.ImageChooserBlock', (), {}), 3: ('home.blocks.ValidatingEmbedBlock', (), {}), 4: ('home.blocks.HorizontalRuleBlock', (), {}), 5: ('wagtail.blocks.RawHTMLBlock', (), {'help_text': '僅限信任來源的 blockquote/iframe 原始碼'})}),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlepage',
|
||||
name='cover_image',
|
||||
field=models.ForeignKey(blank=True, help_text='列表封面圖', null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='+', to='wagtailimages.image'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='articlepage',
|
||||
name='recommended',
|
||||
field=models.BooleanField(default=False, help_text='在推薦區塊顯示'),
|
||||
),
|
||||
]
|
||||
Loading…
x
Reference in New Issue
Block a user