Skip to content

Commit

Permalink
images: add validator which enforces alt texts on img tags
Browse files Browse the repository at this point in the history
  • Loading branch information
goapunk committed Jan 29, 2024
1 parent aa44c6c commit d52847e
Show file tree
Hide file tree
Showing 5 changed files with 95 additions and 0 deletions.
20 changes: 20 additions & 0 deletions adhocracy4/images/validators.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import math

import magic
from bs4 import BeautifulSoup
from django.core.exceptions import ValidationError
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _

image_max_mb = 5
Expand Down Expand Up @@ -74,3 +76,21 @@ def validate_image(
if errors:
raise ValidationError(errors)
return image


@deconstructible
class ImageAltTextValidator:
"""Validate that if the input contains html img tags that all have the alt
attribute set, otherwise raise ValidationError.
"""

message = _("Please add an alternative text for all images.")

def __call__(self, value):
soup = BeautifulSoup(value, "html.parser")
images = soup("img", alt=False)
if len(images) > 0:
raise ValidationError(self.message)

def __eq__(self, other):
return isinstance(other, self.__class__)
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Generated by Django 4.2 on 2024-01-29 13:29

import adhocracy4.images.validators
from django.db import migrations
import django_ckeditor_5.fields


class Migration(migrations.Migration):
dependencies = [
("a4projects", "0046_alter_project_information_alter_project_result"),
]

operations = [
migrations.AlterField(
model_name="project",
name="information",
field=django_ckeditor_5.fields.CKEditor5Field(
blank=True,
validators=[adhocracy4.images.validators.ImageAltTextValidator()],
verbose_name="Description of your project",
),
),
migrations.AlterField(
model_name="project",
name="result",
field=django_ckeditor_5.fields.CKEditor5Field(
blank=True,
validators=[adhocracy4.images.validators.ImageAltTextValidator()],
verbose_name="Results of your project",
),
),
]
3 changes: 3 additions & 0 deletions adhocracy4/projects/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
from adhocracy4 import transforms as html_transforms
from adhocracy4.administrative_districts.models import AdministrativeDistrict
from adhocracy4.images import fields
from adhocracy4.images.validators import ImageAltTextValidator
from adhocracy4.maps.fields import PointField
from adhocracy4.models import base

Expand Down Expand Up @@ -218,11 +219,13 @@ class Project(
blank=True,
config_name="collapsible-image-editor",
verbose_name=_("Description of your project"),
validators=[ImageAltTextValidator()],
)
result = CKEditor5Field(
blank=True,
config_name="collapsible-image-editor",
verbose_name=_("Results of your project"),
validators=[ImageAltTextValidator()],
)
access = EnumField(
Access, default=Access.PUBLIC, verbose_name=_("Access to the project")
Expand Down
2 changes: 2 additions & 0 deletions changelog/7274.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
- custom migration for iframes to make them work with ckeditor5 (WARNING:
backing up your database before running is recommended).
- added dependency beautifulsoup4
- added an ImageAltTextValidator to enforce alt text on img tags. The validator
is used for project information and result.

### Changed

Expand Down
38 changes: 38 additions & 0 deletions tests/dashboard/test_form_components.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
from adhocracy4.dashboard.components.forms import ProjectDashboardForm
from adhocracy4.dashboard.components.forms import ProjectFormComponent
from adhocracy4.dashboard.forms import ProjectBasicForm
from adhocracy4.dashboard.forms import ProjectInformationForm
from adhocracy4.dashboard.forms import ProjectResultForm
from adhocracy4.images.validators import ImageAltTextValidator
from adhocracy4.modules import models as module_models
from adhocracy4.phases import models as phase_models
from adhocracy4.projects import models as project_models
Expand Down Expand Up @@ -270,3 +273,38 @@ class Component(ModuleFormSetComponent):
phase.start_date = now()
phase.save()
assert component.get_progress(module) == (1, 2)


@pytest.mark.django_db
@pytest.mark.parametrize(
"form_class, field_name",
[(ProjectInformationForm, "information"), (ProjectResultForm, "result")],
)
def test_project_form_image_missing_alt_text(form_class, field_name, project_factory):
project = project_factory(is_draft=False)
form = form_class(
instance=project,
data={
field_name: "my project description <img></img>",
},
)
assert field_name in form.errors
assert form.errors[field_name].data[0].messages[0] == ImageAltTextValidator.message
assert not form.is_valid()


@pytest.mark.django_db
@pytest.mark.parametrize(
"form_class, field_name",
[(ProjectInformationForm, "information"), (ProjectResultForm, "result")],
)
def test_project_form_image_has_alt_text(form_class, field_name, project_factory):
project = project_factory(is_draft=False)
form = form_class(
instance=project,
data={
field_name: "my project description <img alt='descriptive picture'></img>",
},
)
assert field_name not in form.errors
assert form.is_valid()

0 comments on commit d52847e

Please sign in to comment.