From 0eb027879a9ed607d44ecf9d4ce52703ccd9a41d Mon Sep 17 00:00:00 2001 From: Robert Sparks Date: Tue, 20 Jul 2021 19:58:31 +0000 Subject: [PATCH] Render markdown on the document main page for document materials. Fixes #2927. Commit ready for merge. - Legacy-Id: 19243 --- ietf/doc/tests.py | 67 ++++++++++++++++++++++- ietf/doc/views_doc.py | 5 +- ietf/templates/doc/document_material.html | 12 +++- 3 files changed, 80 insertions(+), 4 deletions(-) diff --git a/ietf/doc/tests.py b/ietf/doc/tests.py index e8fa33891..3a2ed8445 100644 --- a/ietf/doc/tests.py +++ b/ietf/doc/tests.py @@ -33,14 +33,15 @@ from ietf.doc.models import ( Document, DocAlias, DocRelationshipName, RelatedDo from ietf.doc.factories import ( DocumentFactory, DocEventFactory, CharterFactory, ConflictReviewFactory, WgDraftFactory, IndividualDraftFactory, WgRfcFactory, IndividualRfcFactory, StateDocEventFactory, BallotPositionDocEventFactory, - BallotDocEventFactory, DocumentAuthorFactory ) + BallotDocEventFactory, DocumentAuthorFactory, NewRevisionDocEventFactory) from ietf.doc.fields import SearchableDocumentsField from ietf.doc.utils import create_ballot_if_not_open, uppercase_std_abbreviated_name from ietf.group.models import Group from ietf.group.factories import GroupFactory, RoleFactory from ietf.ipr.factories import HolderIprDisclosureFactory from ietf.meeting.models import Meeting, Session, SessionPresentation, SchedulingEvent -from ietf.meeting.factories import MeetingFactory, SessionFactory +from ietf.meeting.factories import MeetingFactory, SessionFactory, SessionPresentationFactory + from ietf.name.models import SessionStatusName, BallotPositionName from ietf.person.models import Person from ietf.person.factories import PersonFactory, EmailFactory @@ -2297,3 +2298,65 @@ class FieldTests(TestCase): dict(id=doc.pk, text=escape(uppercase_std_abbreviated_name(doc.name))), decoded[str(doc.pk)], ) + +class MaterialsTests(TestCase): + + def setUp(self): + self.id_dir = self.tempdir('id') + self.saved_agenda_path = settings.AGENDA_PATH + settings.AGENDA_PATH = self.id_dir + + meeting_number='111' + meeting_dir = os.path.join(f'{settings.AGENDA_PATH}',f'{meeting_number}') + os.mkdir(meeting_dir) + agenda_dir = os.path.join(meeting_dir,'agenda') + os.mkdir(agenda_dir) + + group_acronym='bogons' + + # This is too much work - the factory should + # * build the DocumentHistory correctly + # * maybe do something by default with uploaded_filename + # and there should be a more usable unit to save bits to disk (handle_file_upload isn't quite right) that tests can leverage + try: + uploaded_filename_00 = f'agenda-{meeting_number}-{group_acronym}-00.txt' + uploaded_filename_01 = f'agenda-{meeting_number}-{group_acronym}-01.md' + f = io.open(os.path.join(agenda_dir, uploaded_filename_00), 'w') + f.write('This is some unremarkable text') + f.close() + f = io.open(os.path.join(agenda_dir, uploaded_filename_01), 'w') + f.write('This links to [an unusual place](https://unusual.example).') + f.close() + + self.doc = DocumentFactory(type_id='agenda',rev='00',group__acronym=group_acronym, newrevisiondocevent=None, name=f'agenda-{meeting_number}-{group_acronym}', uploaded_filename=uploaded_filename_00) + e = NewRevisionDocEventFactory(doc=self.doc,rev='00') + self.doc.save_with_history([e]) + self.doc.rev = '01' + self.doc.uploaded_filename = uploaded_filename_01 + e = NewRevisionDocEventFactory(doc=self.doc, rev='01') + self.doc.save_with_history([e]) + + # This is necessary for the view to be able to find the document + # which hints that the view has an issue : if a materials document is taken out of all SessionPresentations, it is no longer accessable by this view + SessionPresentationFactory(session__meeting__number=meeting_number, session__group=self.doc.group, document=self.doc) + + except: + shutil.rmtree(self.id_dir) + raise + + def tearDown(self): + settings.AGENDA_PATH = self.saved_agenda_path + shutil.rmtree(self.id_dir) + + def test_markdown_and_text(self): + url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=self.doc.name,rev='00')) + r = self.client.get(url) + self.assertEqual(r.status_code,200) + q = PyQuery(r.content) + self.assertTrue(q('#materials-content > pre')) + + url = urlreverse("ietf.doc.views_doc.document_main", kwargs=dict(name=self.doc.name,rev='01')) + r = self.client.get(url) + self.assertEqual(r.status_code,200) + q = PyQuery(r.content) + self.assertEqual(q('#materials-content .panel-body a').attr['href'],'https://unusual.example') diff --git a/ietf/doc/views_doc.py b/ietf/doc/views_doc.py index e95077564..2ea987acc 100644 --- a/ietf/doc/views_doc.py +++ b/ietf/doc/views_doc.py @@ -624,6 +624,7 @@ def document_main(request, name, rev=None): pathname = os.path.join(doc.get_file_path(), basename) content = None + content_is_html = False other_types = [] globs = glob.glob(pathname + ".*") url = doc.get_href() @@ -637,7 +638,8 @@ def document_main(request, name, rev=None): content = doc.text_or_error() t = "plain text" elif extension == ".md": - content = doc.text_or_error() + content = markdown.markdown(doc.text_or_error(), extensions=['extra']) + content_is_html = True t = "markdown" other_types.append((t, url)) @@ -645,6 +647,7 @@ def document_main(request, name, rev=None): dict(doc=doc, top=top, content=content, + content_is_html=content_is_html, revisions=revisions, latest_rev=latest_rev, snapshot=snapshot, diff --git a/ietf/templates/doc/document_material.html b/ietf/templates/doc/document_material.html index 1e5679e82..83443879f 100644 --- a/ietf/templates/doc/document_material.html +++ b/ietf/templates/doc/document_material.html @@ -123,8 +123,17 @@

{% if doc.meeting_related %}Meeting{% endif %} {{ doc.type.name }}
{{ doc.name }}

+
{% if doc.rev and content != None %} -
{{ content|sanitize|maybewordwrap|safe }}
+ {% if content_is_html %} +
+
+ {{ content|sanitize|safe }} +
+
+ {% else %} +
{{ content|sanitize|maybewordwrap|safe }}
+ {% endif %} {% else %}

Not available as plain text.

@@ -132,4 +141,5 @@

Download as {{ other_types.0.0.upper }}

{% endif %} {% endif %} +
{% endblock %}