Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: prefer PDF in (+refactor) materials_document view #8136

Merged
merged 7 commits into from
Nov 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 55 additions & 2 deletions ietf/meeting/tests_views.py
Original file line number Diff line number Diff line change
Expand Up @@ -125,8 +125,12 @@ def tearDown(self):
settings.MEETINGHOST_LOGO_PATH = self.saved_meetinghost_logo_path
super().tearDown()

def write_materials_file(self, meeting, doc, content, charset="utf-8"):
path = os.path.join(self.materials_dir, "%s/%s/%s" % (meeting.number, doc.type_id, doc.uploaded_filename))
def write_materials_file(self, meeting, doc, content, charset="utf-8", with_ext=None):
if with_ext is None:
filename = doc.uploaded_filename
else:
filename = Path(doc.uploaded_filename).with_suffix(with_ext)
path = os.path.join(self.materials_dir, "%s/%s/%s" % (meeting.number, doc.type_id, filename))

dirname = os.path.dirname(path)
if not os.path.exists(dirname):
Expand Down Expand Up @@ -753,7 +757,56 @@ def test_materials_has_edit_links(self):
)
self.assertEqual(len(q(f'a[href^="{edit_url}#session"]')), 1, f'Link to session_details page for {acro}')

def test_materials_document_extension_choice(self):
def _url(**kwargs):
return urlreverse("ietf.meeting.views.materials_document", kwargs=kwargs)

presentation = SessionPresentationFactory(
document__rev="00",
document__name="slides-whatever",
document__uploaded_filename="slides-whatever-00.txt",
document__type_id="slides",
document__states=(("reuse_policy", "single"),)
)
session = presentation.session
meeting = session.meeting
# This is not a realistic set of files to exist, but is useful for testing. Normally,
# we'd have _either_ txt, pdf, or pptx + pdf.
self.write_materials_file(meeting, presentation.document, "Hi I'm a txt", with_ext=".txt")
self.write_materials_file(meeting, presentation.document, "Hi I'm a pptx", with_ext=".pptx")

# with no rev, prefers the uploaded_filename
r = self.client.get(_url(document="slides-whatever", num=meeting.number)) # no rev
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content.decode(), "Hi I'm a txt")

# with a rev, prefers pptx because it comes first alphabetically
r = self.client.get(_url(document="slides-whatever-00", num=meeting.number))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content.decode(), "Hi I'm a pptx")

# now create a pdf
self.write_materials_file(meeting, presentation.document, "Hi I'm a pdf", with_ext=".pdf")

# with no rev, still prefers uploaded_filename
r = self.client.get(_url(document="slides-whatever", num=meeting.number)) # no rev
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content.decode(), "Hi I'm a txt")

# pdf should be preferred with a rev
r = self.client.get(_url(document="slides-whatever-00", num=meeting.number))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content.decode(), "Hi I'm a pdf")

# and explicit extensions should, of course, be respected
for ext in ["pdf", "pptx", "txt"]:
r = self.client.get(_url(document="slides-whatever-00", num=meeting.number, ext=f".{ext}"))
self.assertEqual(r.status_code, 200)
self.assertEqual(r.content.decode(), f"Hi I'm a {ext}")

# and 404 should come up if the ext is not found
r = self.client.get(_url(document="slides-whatever-00", num=meeting.number, ext=".docx"))
self.assertEqual(r.status_code, 404)

def test_materials_editable_groups(self):
meeting = make_meeting_test_data()
Expand Down
2 changes: 1 addition & 1 deletion ietf/meeting/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ def get_redirect_url(self, *args, **kwargs):
url(r'^week-view(?:.html)?/?$', AgendaRedirectView.as_view(pattern_name='agenda', permanent=True)),
url(r'^materials(?:.html)?/?$', views.materials),
url(r'^request_minutes/?$', views.request_minutes),
url(r'^materials/%(document)s((?P<ext>\.[a-z0-9]+)|/)?$' % settings.URL_REGEXPS, views.materials_document),
url(r'^materials/%(document)s(?P<ext>\.[a-z0-9]+)?/?$' % settings.URL_REGEXPS, views.materials_document),
url(r'^session/?$', views.materials_editable_groups),
url(r'^proceedings(?:.html)?/?$', views.proceedings),
url(r'^proceedings(?:.html)?/finalize/?$', views.finalize_proceedings),
Expand Down
54 changes: 32 additions & 22 deletions ietf/meeting/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@

import csv
import datetime
import glob
import io
import itertools
import json
Expand All @@ -20,6 +19,7 @@
from collections import OrderedDict, Counter, deque, defaultdict, namedtuple
from functools import partialmethod
import jsonschema
from pathlib import Path
from urllib.parse import parse_qs, unquote, urlencode, urlsplit, urlunsplit
from tempfile import mkstemp
from wsgiref.handlers import format_date_time
Expand Down Expand Up @@ -250,40 +250,49 @@ def _get_materials_doc(meeting, name):

@cache_page(1 * 60)
def materials_document(request, document, num=None, ext=None):
meeting=get_meeting(num,type_in=['ietf','interim'])
"""Materials document view

:param request: Django request
:param document: Name of document without an extension
:param num: meeting number
:param ext: extension including preceding '.'
"""
meeting = get_meeting(num, type_in=["ietf", "interim"])
num = meeting.number
try:
doc, rev = _get_materials_doc(meeting=meeting, name=document)
except Document.DoesNotExist:
raise Http404("No such document for meeting %s" % num)

if not rev:
filename = doc.get_file_name()
filename = Path(doc.get_file_name())
else:
filename = os.path.join(doc.get_file_path(), document)
filename = Path(doc.get_file_path()) / document
if ext:
if not filename.endswith(ext):
name, _ = os.path.splitext(filename)
filename = name + ext
else:
filenames = glob.glob(filename+'.*')
if filenames:
filename = filenames[0]
_, basename = os.path.split(filename)
if not os.path.exists(filename):
raise Http404("File not found: %s" % filename)
filename = filename.with_suffix(ext)
elif filename.suffix == "":
# If we don't already have an extension, try to add one
ext_choices = {
# Construct a map from suffix to full filename
fn.suffix: fn
for fn in sorted(filename.parent.glob(filename.stem + ".*"))
}
if len(ext_choices) > 0:
if ".pdf" in ext_choices:
filename = ext_choices[".pdf"]
else:
filename = list(ext_choices.values())[0]
if not filename.exists():
raise Http404(f"File not found: {filename}")

old_proceedings_format = meeting.number.isdigit() and int(meeting.number) <= 96
if settings.MEETING_MATERIALS_SERVE_LOCALLY or old_proceedings_format:
with io.open(filename, 'rb') as file:
bytes = file.read()

bytes = filename.read_bytes()
mtype, chset = get_mime_type(bytes)
content_type = "%s; charset=%s" % (mtype, chset)

file_ext = os.path.splitext(filename)
if len(file_ext) == 2 and file_ext[1] == '.md' and mtype == 'text/plain':
sorted_accept = sort_accept_tuple(request.META.get('HTTP_ACCEPT'))
if filename.suffix == ".md" and mtype == "text/plain":
sorted_accept = sort_accept_tuple(request.META.get("HTTP_ACCEPT"))
for atype in sorted_accept:
if atype[0] == "text/markdown":
content_type = content_type.replace("plain", "markdown", 1)
Expand All @@ -293,7 +302,7 @@ def materials_document(request, document, num=None, ext=None):
"minimal.html",
{
"content": markdown.markdown(bytes.decode(encoding=chset)),
"title": basename,
"title": filename.name,
},
)
content_type = content_type.replace("plain", "html", 1)
Expand All @@ -302,11 +311,12 @@ def materials_document(request, document, num=None, ext=None):
break

response = HttpResponse(bytes, content_type=content_type)
response['Content-Disposition'] = 'inline; filename="%s"' % basename
response["Content-Disposition"] = f'inline; filename="{filename.name}"'
return response
else:
return HttpResponseRedirect(redirect_to=doc.get_href(meeting=meeting))


@login_required
def materials_editable_groups(request, num=None):
meeting = get_meeting(num)
Expand Down
Loading