fix: Improve validation for form that accepts pasted email feedback (#5761)

* test: Test paste-email-feedback-form with missing headers and/or body

* fix: Don't crash if paste-email-feedback-form doesn't contain a Subject line

* test: Test that paste-email-feedback-form requires headers

* fix: If email headers are missing, prompt the user to try again

* chore: retrigger PR checks
This commit is contained in:
Paul Selkirk 2023-06-08 14:56:24 -04:00 committed by GitHub
parent cc35a2d678
commit 2ca4f7beaf
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 54 additions and 4 deletions

View file

@ -99,6 +99,7 @@ class NomcomViewsTest(TestCase):
self.private_nominate_newperson_url = reverse('ietf.nomcom.views.private_nominate_newperson', kwargs={'year': self.year})
self.add_questionnaire_url = reverse('ietf.nomcom.views.private_questionnaire', kwargs={'year': self.year})
self.private_feedback_url = reverse('ietf.nomcom.views.private_feedback', kwargs={'year': self.year})
self.private_feedback_email_url = reverse('ietf.nomcom.views.private_feedback_email', kwargs={'year': self.year})
self.positions_url = reverse('ietf.nomcom.views.list_positions', kwargs={'year': self.year})
self.edit_position_url = reverse('ietf.nomcom.views.edit_position', kwargs={'year': self.year})
@ -1012,6 +1013,43 @@ class NomcomViewsTest(TestCase):
nominee_position.save()
def test_private_feedback_email(self):
self.access_chair_url(self.private_feedback_email_url)
feedback_url = self.private_feedback_email_url
response = self.client.get(feedback_url)
self.assertEqual(response.status_code, 200)
nomcom = get_nomcom_by_year(self.year)
if not nomcom.public_key:
self.assertNotContains(response, "paste-email-feedback-form")
# save the cert file in tmp
with io.open(self.cert_file.name, 'r') as fd:
nomcom.public_key.save('cert', File(fd))
response = self.client.get(feedback_url)
self.assertEqual(response.status_code, 200)
self.assertContains(response, "paste-email-feedback-form")
headers = \
"From: Zaphod Beeblebrox <president@galaxy>\n" \
"Subject: Ford Prefect\n\n"
body = \
"Hey, you sass that hoopy Ford Prefect?\n" \
"There's a frood who really knows where his towel is.\n"
test_data = {'email_text': body}
response = self.client.post(feedback_url, test_data)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'Missing email headers')
test_data = {'email_text': headers + body}
response = self.client.post(feedback_url, test_data)
self.assertEqual(response.status_code, 200)
self.assertContains(response, 'The feedback email has been registered.')
class NomineePositionStateSaveTest(TestCase):
"""Tests for the NomineePosition save override method"""

View file

@ -12,6 +12,7 @@ import tempfile
from collections import defaultdict
from email import message_from_string, message_from_bytes
from email.errors import HeaderParseError
from email.header import decode_header
from email.iterators import typed_subpart_iterator
from email.utils import parseaddr
@ -442,7 +443,11 @@ def make_nomineeposition_for_newperson(nomcom, candidate_name, candidate_email,
def getheader(header_text, default="utf-8"):
"""Decode the specified header"""
try:
tuples = decode_header(header_text)
except TypeError:
return ""
header_sections = [ text.decode(charset or default) if isinstance(text, bytes) else text for text, charset in tuples]
return "".join(header_sections)
@ -491,6 +496,9 @@ def parse_email(text):
body = get_body(msg)
subject = getheader(msg['Subject'])
__, addr = parseaddr(msg['From'])
if not addr:
raise HeaderParseError
return addr.lower(), subject, body

View file

@ -20,6 +20,7 @@ from django.template.loader import render_to_string
from django.urls import reverse
from django.utils.encoding import force_bytes, force_str
from email.errors import HeaderParseError
from ietf.dbtemplate.models import DBTemplate
from ietf.dbtemplate.views import group_template_edit, group_template_show
@ -652,9 +653,12 @@ def private_feedback_email(request, year):
form = FeedbackEmailForm(data=request.POST,
nomcom=nomcom)
if form.is_valid():
try:
form.save()
form = FeedbackEmailForm(nomcom=nomcom)
messages.success(request, 'The feedback email has been registered.')
except HeaderParseError:
messages.error(request, 'Missing email headers')
return render(request, template,
{'form': form,