diff --git a/.editorconfig b/.editorconfig
index 95dc121e163..11e80fa699a 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -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
\ No newline at end of file
diff --git a/.gitignore b/.gitignore
index 3687fc93dd2..d302f3208c9 100644
--- a/.gitignore
+++ b/.gitignore
@@ -14,6 +14,8 @@
*.#*
.*.swp
.DS_store
+datatracker.sublime-project
+datatracker.sublime-workspace
# Simulated Subversion default ignores end here
/.coverage
/.factoryboy_random_state
diff --git a/dev/tests/Dockerfile b/dev/tests/Dockerfile
index 8c938b89101..212481c44ff 100644
--- a/dev/tests/Dockerfile
+++ b/dev/tests/Dockerfile
@@ -24,7 +24,6 @@ RUN apt-get install -qy \
build-essential \
curl \
docker-ce-cli \
- default-jdk \
enscript \
gawk \
gcc \
@@ -46,7 +45,6 @@ RUN apt-get install -qy \
libxtst6 \
libmagic-dev \
libmariadb-dev \
- libtidy-dev \
locales \
mariadb-client \
netcat \
@@ -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
diff --git a/docker/app.Dockerfile b/docker/app.Dockerfile
index f153928a539..4c78753411f 100644
--- a/docker/app.Dockerfile
+++ b/docker/app.Dockerfile
@@ -31,7 +31,6 @@ RUN apt-get install -qy \
bash \
build-essential \
curl \
- default-jdk \
docker-ce-cli \
enscript \
fish \
@@ -56,7 +55,6 @@ RUN apt-get install -qy \
libmagic-dev \
libmariadb-dev \
libmemcached-tools \
- libtidy-dev \
locales \
mariadb-client \
memcached \
@@ -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
diff --git a/ietf/dbtemplate/templates/dbtemplate/template_show.html b/ietf/dbtemplate/templates/dbtemplate/template_show.html
index 177b50affba..60e3bb9c7cd 100644
--- a/ietf/dbtemplate/templates/dbtemplate/template_show.html
+++ b/ietf/dbtemplate/templates/dbtemplate/template_show.html
@@ -33,8 +33,8 @@
-
{{ template.content }}
+
-{% endblock %}
\ No newline at end of file
+{% endblock %}
diff --git a/ietf/doc/templatetags/ballot_icon.py b/ietf/doc/templatetags/ballot_icon.py
index 587a2553093..52b7635e9d7 100644
--- a/ietf/doc/templatetags/ballot_icon.py
+++ b/ietf/doc/templatetags/ballot_icon.py
@@ -109,14 +109,15 @@ def sort_key(t):
else:
typename = "IESG"
- res = ['
')
+ res.append('>')
res.append("")
@@ -137,7 +138,7 @@ def sort_key(t):
res.append(' | ')
i = i + 1
- res.append("
")
+ res.append("
")
res.append('
' % ballot.pk)
return mark_safe("".join(res))
diff --git a/ietf/doc/templatetags/ietf_filters.py b/ietf/doc/templatetags/ietf_filters.py
index 21cd383cbc5..65e7d426438 100644
--- a/ietf/doc/templatetags/ietf_filters.py
+++ b/ietf/doc/templatetags/ietf_filters.py
@@ -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('
%s
%s
' % (snippet, full))
+ return mark_safe('
%s
%s
' % (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('
Edit' % (urlreverse(url_name, args=args, kwargs=kwargs)))
+ return mark_safe('
Edit' % (urlreverse(url_name, args=args, kwargs=kwargs)))
@register.filter
def textify(text):
diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py
index 56bc8a2c899..9fdc3f6b267 100644
--- a/ietf/doc/tests.py
+++ b/ietf/doc/tests.py
@@ -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')
diff --git a/ietf/doc/tests_ballot.py b/ietf/doc/tests_ballot.py
index 3d15a307a64..317e4e3a1d0 100644
--- a/ietf/doc/tests_ballot.py
+++ b/ietf/doc/tests_ballot.py
@@ -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)
- #
is followed by a panel with the message of interest, so use next()
+ #
is followed by a panel with the message of interest, so use next()
self.assertEqual(
len(heading.next().find(
f'*[title="{expected}"]'
@@ -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')
\ No newline at end of file
diff --git a/ietf/doc/tests_draft.py b/ietf/doc/tests_draft.py
index 9a4e69383eb..be29535d87c 100644
--- a/ietf/doc/tests_draft.py
+++ b/ietf/doc/tests_draft.py
@@ -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
@@ -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")
@@ -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))
diff --git a/ietf/doc/tests_review.py b/ietf/doc/tests_review.py
index 44287a6ef44..7e902514d57 100644
--- a/ietf/doc/tests_review.py
+++ b/ietf/doc/tests_review.py
@@ -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):
@@ -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)
diff --git a/ietf/doc/views_ballot.py b/ietf/doc/views_ballot.py
index 6841e07f5b8..828302e816d 100644
--- a/ietf/doc/views_ballot.py
+++ b/ietf/doc/views_ballot.py
@@ -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")
@@ -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 = ""
diff --git a/ietf/doc/views_charter.py b/ietf/doc/views_charter.py
index 29cfa7f8e2d..c2b88ac4730 100644
--- a/ietf/doc/views_charter.py
+++ b/ietf/doc/views_charter.py
@@ -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']):
@@ -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'])
diff --git a/ietf/doc/views_status_change.py b/ietf/doc/views_status_change.py
index 2484d864508..e7679f66bfd 100644
--- a/ietf/doc/views_status_change.py
+++ b/ietf/doc/views_status_change.py
@@ -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)))
return render(request, 'doc/status_change/last_call.html',
dict(doc=status_change,
diff --git a/ietf/group/tests_info.py b/ietf/group/tests_info.py
index 988956ca3ce..0cb9cfc62ad 100644
--- a/ietf/group/tests_info.py
+++ b/ietf/group/tests_info.py
@@ -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()
diff --git a/ietf/ietfauth/views.py b/ietf/ietfauth/views.py
index 6a087145b8c..892e3c64679 100644
--- a/ietf/ietfauth/views.py
+++ b/ietf/ietfauth/views.py
@@ -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
account profile and review your
+ to your
account profile 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
@@ -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'})
\ No newline at end of file
+ return render(request, 'form.html', {'form':form, 'title':"Disable a personal API key", 'description':'', 'button':'Disable key'})
diff --git a/ietf/liaisons/tests.py b/ietf/liaisons/tests.py
index 7f98b8d7505..4e4eaa136c3 100644
--- a/ietf/liaisons/tests.py
+++ b/ietf/liaisons/tests.py
@@ -317,7 +317,7 @@ 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")
@@ -325,13 +325,13 @@ 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]')), 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)
@@ -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")
@@ -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)
diff --git a/ietf/liaisons/widgets.py b/ietf/liaisons/widgets.py
index 1630f9574ee..d6e2fe936bb 100644
--- a/ietf/liaisons/widgets.py
+++ b/ietf/liaisons/widgets.py
@@ -18,21 +18,21 @@ def __init__(self, *args, **kwargs):
super(ButtonWidget, self).__init__(*args, **kwargs)
def render(self, name, value, **kwargs):
- html = '
%s' % conditional_escape(self.show_on)
- html += '
%s' % conditional_escape(self.label)
+ html = '
%s' % conditional_escape(self.show_on)
+ html += '
%s' % conditional_escape(self.label)
if self.require:
for i in self.require:
- html += '
%s' % conditional_escape(i)
+ html += '
%s' % conditional_escape(i)
required_str = 'Please fill in %s to attach a new file' % conditional_escape(self.required_label)
- html += '
%s' % conditional_escape(required_str)
- html += '
' % conditional_escape(self.label)
+ html += '
%s' % conditional_escape(required_str)
+ html += '
' % conditional_escape(self.label)
return mark_safe(html)
class ShowAttachmentsWidget(Widget):
def render(self, name, value, **kwargs):
html = '
' % name
- html += '
No files attached'
+ html += '
No files attached'
html += '
'
if value and isinstance(value, QuerySet):
for attachment in value:
diff --git a/ietf/meeting/views.py b/ietf/meeting/views.py
index 12b84dfaa67..408b6a29c82 100644
--- a/ietf/meeting/views.py
+++ b/ietf/meeting/views.py
@@ -3001,7 +3001,7 @@ def ajax_get_utc(request):
utc_day_offset = (naive_utc_dt.date() - dt.date()).days
html = "
{utc} UTC".format(utc=utc)
if utc_day_offset != 0:
- html = html + "
{0:+d} Day".format(utc_day_offset)
+ html = html + '
{0:+d} Day'.format(utc_day_offset)
context_data = {'timezone': timezone,
'time': time,
'utc': utc,
diff --git a/ietf/secr/sreq/forms.py b/ietf/secr/sreq/forms.py
index dab5225e2c8..ecad4ce7e54 100644
--- a/ietf/secr/sreq/forms.py
+++ b/ietf/secr/sreq/forms.py
@@ -117,7 +117,7 @@ def __init__(self, group, meeting, data=None, *args, **kwargs):
self._add_widget_class(constraint_field.widget, 'wg_constraint')
selector_field = forms.ChoiceField(choices=group_acronym_choices, required=False)
- selector_field.widget.attrs['data-slug'] = constraintname.slug # used by onChange handler
+ selector_field.widget.attrs['data-slug'] = constraintname.slug # used by onchange handler
self._add_widget_class(selector_field.widget, 'wg_constraint_selector')
cfield_id = 'constraint_{}'.format(constraintname.slug)
@@ -150,7 +150,7 @@ def __init__(self, group, meeting, data=None, *args, **kwargs):
field_id)
)
- self.fields['joint_with_groups_selector'].widget.attrs['onChange'] = "document.form_post.joint_with_groups.value=document.form_post.joint_with_groups.value + ' ' + this.options[this.selectedIndex].value; return 1;"
+ self.fields['joint_with_groups_selector'].widget.attrs['onchange'] = "document.form_post.joint_with_groups.value=document.form_post.joint_with_groups.value + ' ' + this.options[this.selectedIndex].value; return 1;"
self.fields["resources"].choices = [(x.pk,x.desc) for x in ResourceAssociation.objects.filter(name__used=True).order_by('name__order') ]
if self.hidden:
diff --git a/ietf/secr/templates/announcement/confirm.html b/ietf/secr/templates/announcement/confirm.html
index 8682ebb8147..7ad745a09e6 100644
--- a/ietf/secr/templates/announcement/confirm.html
+++ b/ietf/secr/templates/announcement/confirm.html
@@ -33,7 +33,7 @@
Confirm Announcement
diff --git a/ietf/secr/templates/announcement/main.html b/ietf/secr/templates/announcement/main.html
index 7ff77aa247b..c88b4a2406c 100644
--- a/ietf/secr/templates/announcement/main.html
+++ b/ietf/secr/templates/announcement/main.html
@@ -13,18 +13,20 @@
Announcement