Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
8198106
Add html-validate and bump some deps.
larseggert Mar 28, 2022
905ae1f
Remove tidy, vnu and related scaffolding.
larseggert Mar 28, 2022
25d5166
test: basic proof of concept for hooking templates for validation
rjsparks Mar 25, 2022
5dfca20
Run html-validate
larseggert Mar 29, 2022
9bab826
Bunch of HTML fixes
larseggert Mar 29, 2022
ba7fd48
More fixes
larseggert Mar 29, 2022
51a9eab
Ignore SublimeText project files
larseggert Mar 29, 2022
ec2a74c
Bump deps
larseggert Mar 29, 2022
4abf451
More HTML fixes
larseggert Mar 31, 2022
ccd8eeb
More HTML fixes
larseggert Mar 31, 2022
36d118c
Add config option, and disable HTML validation by default
larseggert Mar 31, 2022
ba1acbb
Batch HTML validations together, to amortize overheads
larseggert Apr 1, 2022
c977600
Make sure to validate all variants of a rendered template.
larseggert Apr 1, 2022
923cc8b
Bump deps
larseggert Apr 1, 2022
ca7f0be
Make tmp path more readable
larseggert Apr 4, 2022
e0f75a1
More HTML fixes
larseggert Apr 4, 2022
5fe5158
More HTML fixes
larseggert Apr 4, 2022
12dd882
More HTML fixes
larseggert Apr 5, 2022
fb1e644
More HTML fixes
larseggert Apr 5, 2022
b64c741
More HTML fixes
larseggert Apr 5, 2022
1b7222e
Run by default
larseggert Apr 5, 2022
7b50d6f
Fix .editorconfig to not trim final newlines.
larseggert Apr 6, 2022
a3afeea
Fix csrf_token outside form. Fix scope for colspans.
larseggert Apr 6, 2022
a5ee6b5
Address review comments by @jennifer-richards.
larseggert Apr 6, 2022
fb449b0
Fix quotes
larseggert Apr 7, 2022
ee3e87f
Re-enable mypy test and suppress attribute error on "import Template"
larseggert Apr 7, 2022
8188fae
Merge branch 'feat/bs5' into validate-html
jennifer-richards Apr 7, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
31 changes: 5 additions & 26 deletions .editorconfig
Original file line number Diff line number Diff line change
Expand Up @@ -4,59 +4,38 @@

root = true

# Settings for IETF datatracker
# Global settings for IETF datatracker
# ---------------------------------------------------------
# PEP8 Style

[*]
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
# to avoid tripping Henrik's commit hook:
trim_trailing_whitespace = false
insert_final_newline = false
trim_trailing_whitespace = true
insert_final_newline = true

# Specializations below *add to* the above defaults

# Settings for .github folder
# ---------------------------------------------------------
# GitHub Markdown Style

[.github/**]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = false
insert_final_newline = true

# Settings for client-side JS / Vue files
# ---------------------------------------------------------
# StandardJS Style

[client/**]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

[package.json]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true

# Settings for cypress tests
# ---------------------------------------------------------
# StandardJS Style

[cypress/**]
indent_style = space
indent_size = 2
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@
*.#*
.*.swp
.DS_store
datatracker.sublime-project
datatracker.sublime-workspace
# Simulated Subversion default ignores end here
/.coverage
/.factoryboy_random_state
Expand Down
5 changes: 0 additions & 5 deletions dev/tests/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ RUN apt-get install -qy \
build-essential \
curl \
docker-ce-cli \
default-jdk \
enscript \
gawk \
gcc \
Expand All @@ -46,7 +45,6 @@ RUN apt-get install -qy \
libxtst6 \
libmagic-dev \
libmariadb-dev \
libtidy-dev \
locales \
mariadb-client \
netcat \
Expand Down Expand Up @@ -109,9 +107,6 @@ RUN pip3 --disable-pip-version-check --no-cache-dir install -r /tmp/pip-tmp/requ
# Turn off rsyslog kernel logging (doesn't work in Docker)
RUN sed -i '/imklog/s/^/#/' /etc/rsyslog.conf

# Install the Nu Html Checker (v.Nu)
ADD https://github.com/validator/validator/releases/download/latest/vnu.jar /

# Fetch wait-for utility
ADD https://raw.githubusercontent.com/eficode/wait-for/v2.1.3/wait-for /usr/local/bin/
RUN chmod +rx /usr/local/bin/wait-for
Expand Down
5 changes: 0 additions & 5 deletions docker/app.Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ RUN apt-get install -qy \
bash \
build-essential \
curl \
default-jdk \
docker-ce-cli \
enscript \
fish \
Expand All @@ -56,7 +55,6 @@ RUN apt-get install -qy \
libmagic-dev \
libmariadb-dev \
libmemcached-tools \
libtidy-dev \
locales \
mariadb-client \
memcached \
Expand Down Expand Up @@ -125,9 +123,6 @@ RUN sed -i '/imklog/s/^/#/' /etc/rsyslog.conf
# Colorize the bash shell
RUN sed -i 's/#force_color_prompt=/force_color_prompt=/' /root/.bashrc

# Install the Nu Html Checker (v.Nu)
ADD https://github.com/validator/validator/releases/download/latest/vnu.jar /

ADD https://raw.githubusercontent.com/eficode/wait-for/v2.1.3/wait-for /usr/local/bin/
RUN chmod +rx /usr/local/bin/wait-for

Expand Down
6 changes: 3 additions & 3 deletions ietf/dbtemplate/templates/dbtemplate/template_show.html
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,8 @@ <h2>Meta information</h2>

<h2>Template content</h2>

<div class = "card">
<p class='pasted'>{{ template.content }}</p>
<div class="card">
<p class="pasted">{{ template.content }}</p>
</div>

{% endblock %}
{% endblock %}
7 changes: 4 additions & 3 deletions ietf/doc/templatetags/ballot_icon.py
Original file line number Diff line number Diff line change
Expand Up @@ -109,14 +109,15 @@ def sort_key(t):
else:
typename = "IESG"

res = ['<a %s href="%s" data-bs-toggle="modal" data-bs-target="#modal-%d" title="%s positions (click to show more)" class="ballot-icon"><table' % (
res = ['<a %s href="%s" data-bs-toggle="modal" data-bs-target="#modal-%d" aria-label="%s positions" title="%s positions (click to show more)" class="ballot-icon"><table' % (
right_click_string,
urlreverse("ietf.doc.views_doc.ballot_popup", kwargs=dict(name=doc.name, ballot_id=ballot.pk)),
ballot.pk,
typename,
typename,)]
if my_blocking:
res.append(' class="is-blocking" ')
res.append('>')
res.append('><tbody>')

res.append("<tr>")

Expand All @@ -137,7 +138,7 @@ def sort_key(t):
res.append('<td class="position-empty"></td>')
i = i + 1

res.append("</tr></table></a>")
res.append("</tr></tbody></table></a>")
res.append('<div id="modal-%d" class="modal fade" tabindex="-1" role="dialog" aria-hidden="true"><div class="modal-dialog modal-dialog-scrollable modal-xl"><div class="modal-content"></div></div></div>' % ballot.pk)

return mark_safe("".join(res))
Expand Down
4 changes: 2 additions & 2 deletions ietf/doc/templatetags/ietf_filters.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,13 +413,13 @@ def format_snippet(text, trunc_words=25):
full = keep_spacing(collapsebr(linebreaksbr(mark_safe(sanitize_fragment(text)))))
snippet = truncatewords_html(full, trunc_words)
if snippet != full:
return mark_safe('<div class="snippet">%s<button class="btn btn-sm btn-primary show-all"><i class="bi bi-caret-down"></i></button></div><div class="visually-hidden full">%s</div>' % (snippet, full))
return mark_safe('<div class="snippet">%s<button type="button" aria-label="Expand" class="btn btn-sm btn-primary show-all"><i class="bi bi-caret-down"></i></button></div><div class="visually-hidden full">%s</div>' % (snippet, full))
return mark_safe(full)

@register.simple_tag
def doc_edit_button(url_name, *args, **kwargs):
"""Given URL name/args/kwargs, looks up the URL just like "url" tag and returns a properly formatted button for the document material tables."""
return mark_safe('<a class="btn btn-primary btn-sm" role="button" href="%s">Edit</a>' % (urlreverse(url_name, args=args, kwargs=kwargs)))
return mark_safe('<a class="btn btn-primary btn-sm" type="button" href="%s">Edit</a>' % (urlreverse(url_name, args=args, kwargs=kwargs)))

@register.filter
def textify(text):
Expand Down
2 changes: 1 addition & 1 deletion ietf/doc/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -1595,7 +1595,7 @@ def test_document_ballot_popup_unique_anchors_per_doc(self):
href = q(f'div.balloter-name a[href$="{author_slug}"]').attr('href')
ids = [
target.attr('id')
for target in q(f'h5[id$="{author_slug}"]').items()
for target in q(f'p.h5[id$="{author_slug}"]').items()
]
self.assertEqual(len(ids), 1, 'Should be exactly one link for the balloter')
self.assertEqual(href, f'#{ids[0]}', 'Anchor href should match ID')
Expand Down
6 changes: 3 additions & 3 deletions ietf/doc/tests_ballot.py
Original file line number Diff line number Diff line change
Expand Up @@ -1196,9 +1196,9 @@ def test_ballotpositiondocevent_any_email_sent(self):
)

def _assertBallotMessage(self, q, balloter, expected):
heading = q(f'h5[id$="_{slugify(balloter.plain_name())}"]')
heading = q(f'p.h5[id$="_{slugify(balloter.plain_name())}"]')
self.assertEqual(len(heading), 1)
# <h5/> is followed by a panel with the message of interest, so use next()
# <p.h5/> is followed by a panel with the message of interest, so use next()
self.assertEqual(
len(heading.next().find(
f'*[title="{expected}"]'
Expand Down Expand Up @@ -1379,4 +1379,4 @@ def test_document_ballot_content_without_send_email_values(self):
q = PyQuery(content)
self._assertBallotMessage(q, balloters[0], 'No email send requests for this discuss')
self._assertBallotMessage(q, balloters[1], 'No ballot position send log available')
self._assertBallotMessage(q, old_balloter, 'No ballot position send log available')
self._assertBallotMessage(q, old_balloter, 'No ballot position send log available')
6 changes: 3 additions & 3 deletions ietf/doc/tests_draft.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ def test_change_state(self):
self.assertEqual(len(q('form select[name=state]')), 1)

if next_states:
self.assertEqual(len(q('[type=submit][value="%s"]' % next_states[0].name)), 1)
self.assertEqual(len(q('[type=submit]:contains("%s")' % next_states[0].name)), 1)


# faulty post
Expand Down Expand Up @@ -148,7 +148,7 @@ def test_change_state(self):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('form [type=submit][value="%s"]' % first_state.name)), 1)
self.assertEqual(len(q('form [type=submit]:contains("%s")' % first_state.name)), 1)

def test_pull_from_rfc_queue(self):
ad = Person.objects.get(user__username="ad")
Expand Down Expand Up @@ -1383,7 +1383,7 @@ def verify_can_see(username):
r = self.client.get(url)
self.assertEqual(r.status_code,200)
q = PyQuery(r.content)
self.assertEqual(len(q('form input[name="confirm"]')),1)
self.assertEqual(len(q('form button[name="confirm"]')),1)

url = urlreverse('ietf.doc.views_draft.to_iesg', kwargs=dict(name=self.docname))

Expand Down
3 changes: 2 additions & 1 deletion ietf/doc/tests_review.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
from ietf.utils.test_utils import login_testing_unauthorized, reload_db_objects
from ietf.utils.test_utils import TestCase
from ietf.utils.text import strip_prefix, xslugify
from django.utils.html import escape

class ReviewTests(TestCase):
def setUp(self):
Expand Down Expand Up @@ -175,7 +176,7 @@ def test_review_request(self):
self.assertContains(r, review_req.team.name)
try:
# FIXME-LARS
self.assertContains(r, author.name)
self.assertContains(r, escape(author.name))
except:
print(r.content)
self.assertContains(r, author.name)
Expand Down
4 changes: 2 additions & 2 deletions ietf/doc/views_ballot.py
Original file line number Diff line number Diff line change
Expand Up @@ -574,7 +574,7 @@ def lastcalltext(request, name):
e.save()

# make sure form has the updated text
form = LastCallTextForm(initial=dict(last_call_text=e.text))
form = LastCallTextForm(initial=dict(last_call_text=escape(e.text)))


s = doc.get_state("draft-iesg")
Expand Down Expand Up @@ -813,7 +813,7 @@ def ballot_approvaltext(request, name):
e.save()

# make sure form has the updated text
form = ApprovalTextForm(initial=dict(approval_text=e.text))
form = ApprovalTextForm(initial=dict(approval_text=escape(e.text)))

can_announce = doc.get_state("draft-iesg").order > 19
need_intended_status = ""
Expand Down
6 changes: 3 additions & 3 deletions ietf/doc/views_charter.py
Original file line number Diff line number Diff line change
Expand Up @@ -556,8 +556,8 @@ def review_announcement_text(request, name):
(existing, existing_new_work) = default_review_text(group, charter, by)
existing.save()
existing_new_work.save()
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=existing.text,
new_work_text=existing_new_work.text))
form = ReviewAnnouncementTextForm(initial=dict(announcement_text=escape(existing.text),
new_work_text=escape(existing_new_work.text)))

if any(x in request.POST for x in ['send_annc_only','send_nw_only','send_both']) and form.is_valid():
if any(x in request.POST for x in ['send_annc_only','send_both']):
Expand Down Expand Up @@ -613,7 +613,7 @@ def action_announcement_text(request, name):
if "regenerate_text" in request.POST:
e = default_action_text(group, charter, by)
e.save()
form = ActionAnnouncementTextForm(initial=dict(announcement_text=e.text))
form = ActionAnnouncementTextForm(initial=dict(announcement_text=escape(e.text)))

if "send_text" in request.POST and form.is_valid():
parsed_msg = send_mail_preformatted(request, form.cleaned_data['announcement_text'])
Expand Down
2 changes: 1 addition & 1 deletion ietf/doc/views_status_change.py
Original file line number Diff line number Diff line change
Expand Up @@ -716,7 +716,7 @@ def last_call(request, name):

if "regenerate_last_call_text" in request.POST:
e = generate_last_call_text(request,status_change)
form = LastCallTextForm(initial=dict(last_call_text=e.text))
form = LastCallTextForm(initial=dict(last_call_text=escape(e.text)))
Comment thread
rjsparks marked this conversation as resolved.

return render(request, 'doc/status_change/last_call.html',
dict(doc=status_change,
Expand Down
2 changes: 1 addition & 1 deletion ietf/group/tests_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -1527,7 +1527,7 @@ def test_can_switch_date_types_for_initial_charter(self):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(q('#switch-date-use-form button').attr('style'), 'display:none;')
self.assertTrue(q('#switch-date-use-form button').hasClass('d-none'))

ms.group.charter.rev='00-00'
ms.group.charter.save()
Expand Down
8 changes: 4 additions & 4 deletions ietf/ietfauth/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -744,17 +744,17 @@ def login(request, extra_context=None):
logout(request)
response = render(request, 'registration/missing_person.html')
if require_consent:
messages.warning(request, mark_safe("""
messages.warning(request, mark_safe('''

You have personal information associated with your account which is not
derived from draft submissions or other ietf work, namely: %s. Please go
to your <a href='/accounts/profile'>account profile</a> and review your
to your <a href="/accounts/profile">account profile</a> and review your
personal information, then scoll to the bottom and check the 'confirm'
checkbox and submit the form, in order to to indicate that that the
provided personal information may be used and displayed within the IETF
datatracker.

""" % ', '.join(require_consent)))
''' % ', '.join(require_consent)))
return response

@login_required
Expand Down Expand Up @@ -816,4 +816,4 @@ def clean_key(self):
messages.error(request, "Key validation failed; key not disabled")
else:
form = KeyDeleteForm(request.GET)
return render(request, 'form.html', {'form':form, 'title':"Disable a personal API key", 'description':'', 'button':'Disable key'})
return render(request, 'form.html', {'form':form, 'title':"Disable a personal API key", 'description':'', 'button':'Disable key'})
10 changes: 5 additions & 5 deletions ietf/liaisons/tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -317,21 +317,21 @@ def test_taken_care_of(self):
r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('form input[name=do_action_taken]')), 0)
self.assertEqual(len(q('form button[name=do_action_taken]')), 0)

# log in and get
self.client.login(username="secretary", password="secretary+password")

r = self.client.get(url)
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('form input[name=do_action_taken]')), 1)
self.assertEqual(len(q('form button[name=do_action_taken]')), 1)

# mark action taken
r = self.client.post(url, dict(do_action_taken="1"))
self.assertEqual(r.status_code, 200)
q = PyQuery(r.content)
self.assertEqual(len(q('form input[name=do_action_taken]')), 0)
self.assertEqual(len(q('form button[name=do_action_taken]')), 0)
liaison = LiaisonStatement.objects.get(id=liaison.id)
self.assertTrue(liaison.action_taken)

Expand All @@ -357,7 +357,7 @@ def test_approval_process(self):
self.assertEqual(r.status_code, 200)
self.assertContains(r, liaison.title)
q = PyQuery(r.content)
self.assertEqual(len(q('form input[name=approved]')), 0)
self.assertEqual(len(q('form button[name=approved]')), 0)

# check the detail page / authorized
self.client.login(username="ulm-liaiman", password="ulm-liaiman+password")
Expand All @@ -368,7 +368,7 @@ def test_approval_process(self):
from ietf.liaisons.utils import can_edit_liaison
user = User.objects.get(username='ulm-liaiman')
self.assertTrue(can_edit_liaison(user, liaison))
self.assertEqual(len(q('form input[name=approved]')), 1)
self.assertEqual(len(q('form button[name=approved]')), 1)

# approve
mailbox_before = len(outbox)
Expand Down
Loading