From e4023daa805f7147b1d7d0011b2c9688d4873f93 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Wed, 16 Aug 2017 17:53:51 -0400 Subject: [PATCH 01/11] update - redirecting to download page if on mobile and mimetype is pdf --- .../templates/archive/download_to_view_pdf.html | 7 +++++++ .../perma/templates/archive/single-link.html | 2 ++ perma_web/perma/utils.py | 15 +++++++++++++++ perma_web/perma/views/common.py | 12 +++++++++--- 4 files changed, 33 insertions(+), 3 deletions(-) create mode 100644 perma_web/perma/templates/archive/download_to_view_pdf.html diff --git a/perma_web/perma/templates/archive/download_to_view_pdf.html b/perma_web/perma/templates/archive/download_to_view_pdf.html new file mode 100644 index 000000000..aeadf60e3 --- /dev/null +++ b/perma_web/perma/templates/archive/download_to_view_pdf.html @@ -0,0 +1,7 @@ +{% with request.META.HTTP_REFERER as referer %} + <div class="record-message"> + <p class="record-message-primary">Perma.cc can't display this file type but you can view or download the archived file by clicking below.</p> + <p class="record-message-secondary">File type {{mime_type}}</p> + <a class="btn btn-large btn-info" target="_blank" href="{{capture.url}}">View/Download File</a> + <div> +{% endwith %} \ No newline at end of file diff --git a/perma_web/perma/templates/archive/single-link.html b/perma_web/perma/templates/archive/single-link.html index 269f71384..b0eef9df7 100755 --- a/perma_web/perma/templates/archive/single-link.html +++ b/perma_web/perma/templates/archive/single-link.html @@ -245,6 +245,8 @@ {% if link.user_deleted %} {% include "archive/deleted.html" %} + {% elif download_pdf_view %} + {% include "archive/download_to_view_pdf.html" %} {% elif can_view %} {% include "archive/iframe.html" %} {% elif link.is_private %} diff --git a/perma_web/perma/utils.py b/perma_web/perma/utils.py index 8fa5399c3..76701ae23 100644 --- a/perma_web/perma/utils.py +++ b/perma_web/perma/utils.py @@ -9,6 +9,7 @@ from netaddr import IPAddress, IPNetwork from functools import wraps import requests +from ua_parser import user_agent_parser from django.core.paginator import Paginator from django.db.models import Q @@ -252,3 +253,17 @@ def get_lat_long(address): warn("Error connecting to geocoding API: %s" % r.status_code) +def parse_user_agent(user_agent_str): + return user_agent_parser.ParseUserAgent(user_agent_str) + + +### pdf handling on mobile apple ### + +def redirect_to_download(capture_mime_type, user_agent_str): + # redirecting to a page with a download button (and not attempting to display) + # if mobile apple device, and the request is a pdf + parsed_agent = parse_user_agent(user_agent_str) + + if "Mobile" in parsed_agent["family"] and "pdf" in capture_mime_type: + return True + return False diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index b3ba38277..0705e2045 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -6,7 +6,6 @@ from ratelimit.decorators import ratelimit from datetime import timedelta from wsgiref.handlers import format_date_time -from ua_parser import user_agent_parser from urllib import urlencode from django.contrib.auth.views import redirect_to_login @@ -24,7 +23,7 @@ from ..models import Link, Registrar, Organization, LinkUser from ..forms import ContactForm -from ..utils import if_anonymous, ratelimit_ip_key +from ..utils import if_anonymous, ratelimit_ip_key, redirect_to_download, parse_user_agent from ..email import send_admin_email, send_user_email_copy_admins from warcio.warcwriter import BufferWARCWriter @@ -109,6 +108,7 @@ def single_linky(request, guid): """ Given a Perma ID, serve it up. """ + raw_user_agent = request.META.get('HTTP_USER_AGENT', '') # Create a canonical version of guid (non-alphanumerics removed, hyphens every 4 characters, uppercase), # and forward to that if it's different from current guid. @@ -195,7 +195,7 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): # safari=1 in the query string indicates that the redirect has already happened. # See http://labs.fundbox.com/third-party-cookies-with-ie-at-2am/ if link.is_private and not request.GET.get('safari'): - user_agent = user_agent_parser.ParseUserAgent(request.META.get('HTTP_USER_AGENT', '')) + user_agent = parse_user_agent(raw_user_agent) if user_agent.get('family') == 'Safari': return redirect_to_login(request.build_absolute_uri(), "//%s%s" % (settings.WARC_HOST, reverse('user_management_set_safari_cookie'))) @@ -210,6 +210,10 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): if (not capture or capture.status != 'success') and link.screenshot_capture and link.screenshot_capture.status == 'success': return HttpResponseRedirect(reverse('single_linky', args=[guid])+"?type=image") + # Special handling for mobile pdf viewing because it can be buggy + # Redirecting to a download page if on mobile + download_pdf_view = redirect_to_download(capture.mime_type(), raw_user_agent) + # If this record was just created by the current user, show them a new record message new_record = request.user.is_authenticated() and link.created_by_id == request.user.id and not link.user_deleted \ and link.creation_timestamp > timezone.now() - timedelta(seconds=300) @@ -224,6 +228,8 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): context = { 'link': link, + 'download_pdf_view': download_pdf_view, + 'mime_type': capture.mime_type(), 'can_view': request.user.can_view(link), 'can_edit': request.user.can_edit(link), 'can_delete': request.user.can_delete(link), From da58b5e1b27bbbbecc54bacc116bb3486fc940a1 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Wed, 16 Aug 2017 17:54:21 -0400 Subject: [PATCH 02/11] clean up - spaces --- perma_web/perma/views/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index 0705e2045..d919bfbd0 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -245,9 +245,9 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): response = render(request, 'archive/single-link.html', context) date_header = format_date_time(mktime(link.creation_timestamp.timetuple())) - link_memento = protocol + settings.HOST + '/' + link.guid + link_memento = protocol + settings.HOST + '/' + link.guid link_timegate = protocol + settings.WARC_HOST + settings.TIMEGATE_WARC_ROUTE + '/' + link.safe_url - link_timemap = protocol + settings.WARC_HOST + settings.WARC_ROUTE + '/timemap/*/' + link.safe_url + link_timemap = protocol + settings.WARC_HOST + settings.WARC_ROUTE + '/timemap/*/' + link.safe_url response['Memento-Datetime'] = date_header link_memento_headers = '<{0}>; rel="original"; datetime="{1}",<{2}>; rel="memento"; datetime="{1}",<{3}>; rel="timegate",<{4}>; rel="timemap"; type="application/link-format"' From d7093af92da20bdd9ee74c93d87146eeb7fb7f69 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Wed, 16 Aug 2017 17:54:35 -0400 Subject: [PATCH 03/11] fix - broken url in comment --- perma_web/fabfile/dev.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perma_web/fabfile/dev.py b/perma_web/fabfile/dev.py index 873bfff73..0ad1dd9f3 100644 --- a/perma_web/fabfile/dev.py +++ b/perma_web/fabfile/dev.py @@ -105,7 +105,7 @@ def sauce_tunnel(): Set up Sauce tunnel before running functional tests targeted at localhost. """ if subprocess.call(['which','sc']) == 1: # error return code -- program not found - sys.exit("Please check that the `sc` program is installed and in your path. To install: https://docs.saucelabs.com/reference/sauce-connect/") + sys.exit("Please check that the `sc` program is installed and in your path. To install: https://wiki.saucelabs.com/display/DOCS/Sauce+Connect+Proxy") local("sc -u %s -k %s" % (settings.SAUCE_USERNAME, settings.SAUCE_ACCESS_KEY)) From 00083c8628599aae75b74999fbf9a5f130bc30d0 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:12:35 -0400 Subject: [PATCH 04/11] rename --- perma_web/perma/templates/archive/single-link.html | 3 ++- perma_web/perma/views/common.py | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/perma_web/perma/templates/archive/single-link.html b/perma_web/perma/templates/archive/single-link.html index b0eef9df7..ee0a0fc63 100755 --- a/perma_web/perma/templates/archive/single-link.html +++ b/perma_web/perma/templates/archive/single-link.html @@ -239,13 +239,14 @@ {% endif %} </header> + {% endblock %} {% block mainContent %} {% if link.user_deleted %} {% include "archive/deleted.html" %} - {% elif download_pdf_view %} + {% elif redirect_to_download_view %} {% include "archive/download_to_view_pdf.html" %} {% elif can_view %} {% include "archive/iframe.html" %} diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index d919bfbd0..acc2a05d5 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -212,7 +212,7 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): # Special handling for mobile pdf viewing because it can be buggy # Redirecting to a download page if on mobile - download_pdf_view = redirect_to_download(capture.mime_type(), raw_user_agent) + redirect_to_download_view = redirect_to_download(capture.mime_type(), raw_user_agent) # If this record was just created by the current user, show them a new record message new_record = request.user.is_authenticated() and link.created_by_id == request.user.id and not link.user_deleted \ @@ -228,7 +228,7 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): context = { 'link': link, - 'download_pdf_view': download_pdf_view, + 'redirect_to_download_view': redirect_to_download_view, 'mime_type': capture.mime_type(), 'can_view': request.user.can_view(link), 'can_edit': request.user.can_edit(link), From 085f13fc42e7475663680b77476602411806097c Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:12:57 -0400 Subject: [PATCH 05/11] reword --- perma_web/perma/templates/archive/download_to_view_pdf.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perma_web/perma/templates/archive/download_to_view_pdf.html b/perma_web/perma/templates/archive/download_to_view_pdf.html index aeadf60e3..5e4fbcb3f 100644 --- a/perma_web/perma/templates/archive/download_to_view_pdf.html +++ b/perma_web/perma/templates/archive/download_to_view_pdf.html @@ -1,6 +1,6 @@ {% with request.META.HTTP_REFERER as referer %} <div class="record-message"> - <p class="record-message-primary">Perma.cc can't display this file type but you can view or download the archived file by clicking below.</p> + <p class="record-message-primary">Perma.cc can't display this file type on mobile but you can view or download the archived file by clicking below.</p> <p class="record-message-secondary">File type {{mime_type}}</p> <a class="btn btn-large btn-info" target="_blank" href="{{capture.url}}">View/Download File</a> <div> From 57ac19b347646b1aea9b325a72c9cb635a99d7e5 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:13:21 -0400 Subject: [PATCH 06/11] add - test, testing message appearance on pdf + mobile --- .../templates/archive/download_to_view_pdf.html | 2 +- perma_web/perma/tests/test_views_common.py | 13 ++++++++++++- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/perma_web/perma/templates/archive/download_to_view_pdf.html b/perma_web/perma/templates/archive/download_to_view_pdf.html index 5e4fbcb3f..f56811008 100644 --- a/perma_web/perma/templates/archive/download_to_view_pdf.html +++ b/perma_web/perma/templates/archive/download_to_view_pdf.html @@ -1,6 +1,6 @@ {% with request.META.HTTP_REFERER as referer %} <div class="record-message"> - <p class="record-message-primary">Perma.cc can't display this file type on mobile but you can view or download the archived file by clicking below.</p> + <p class="record-message-primary">Perma.cc can't display this file type on mobile, but you can view or download the archived file by clicking below.</p> <p class="record-message-secondary">File type {{mime_type}}</p> <a class="btn btn-large btn-info" target="_blank" href="{{capture.url}}">View/Download File</a> <div> diff --git a/perma_web/perma/tests/test_views_common.py b/perma_web/perma/tests/test_views_common.py index 1ea1f66ea..3f1b14a16 100644 --- a/perma_web/perma/tests/test_views_common.py +++ b/perma_web/perma/tests/test_views_common.py @@ -1,7 +1,7 @@ from django.conf import settings from django.core import mail from django.core.urlresolvers import reverse -from django.test import override_settings +from django.test import override_settings, Client from perma.urls import urlpatterns from perma.models import Registrar @@ -54,6 +54,17 @@ def test_dark_archive(self): response = self.get('single_linky', reverse_kwargs={'kwargs': {'guid': 'ABCD-0001'}}) self.assertIn("This record is private.", response.content) + def test_redirect_to_download(self): + # Give user option to download to view pdf if on mobile + client = Client(HTTP_USER_AGENT='Mozilla/5.0 (iPhone; CPU iPhone OS 6_1_4 like Mac OS X) AppleWebKit/536.26 (KHTML, like Gecko) Version/6.0 Mobile/10B350 Safari/8536.25') + response = client.get(reverse('single_linky', kwargs={'guid': '7CF8-SS4G'})) + self.assertIn("Perma.cc can\'t display this file type on mobile", response.content) + + # If not on mobile, display link as normal + client = Client(HTTP_USER_AGENT='Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_6) AppleWebKit/601.7.7 (KHTML, like Gecko) Version/9.1.2 Safari/601.7.7') + response = client.get(reverse('single_linky', kwargs={'guid': '7CF8-SS4G'})) + self.assertNotIn("Perma.cc can\'t display this file type on mobile", response.content) + def test_deleted(self): response = self.get('single_linky', reverse_kwargs={'kwargs': {'guid': 'ABCD-0003'}}) self.assertIn("This record has been deleted.", response.content) From dd52dbd5f384a53353438826f24bbedf8017fd9d Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:19:36 -0400 Subject: [PATCH 07/11] fix - blue button --- perma_web/perma/templates/archive/download_to_view_pdf.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/perma_web/perma/templates/archive/download_to_view_pdf.html b/perma_web/perma/templates/archive/download_to_view_pdf.html index f56811008..bd3c2064b 100644 --- a/perma_web/perma/templates/archive/download_to_view_pdf.html +++ b/perma_web/perma/templates/archive/download_to_view_pdf.html @@ -2,6 +2,6 @@ <div class="record-message"> <p class="record-message-primary">Perma.cc can't display this file type on mobile, but you can view or download the archived file by clicking below.</p> <p class="record-message-secondary">File type {{mime_type}}</p> - <a class="btn btn-large btn-info" target="_blank" href="{{capture.url}}">View/Download File</a> + <a class="btn btn-primary" target="_blank" href="{{capture.url}}">View/Download File</a> <div> {% endwith %} \ No newline at end of file From 55ec3fd7da936cbff4d41af6d8cb8e64180efbf2 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:28:02 -0400 Subject: [PATCH 08/11] fix - if capture is deleted, then mime type does not exist. Catch error --- perma_web/perma/views/common.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index acc2a05d5..0ba91940a 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -212,7 +212,13 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): # Special handling for mobile pdf viewing because it can be buggy # Redirecting to a download page if on mobile - redirect_to_download_view = redirect_to_download(capture.mime_type(), raw_user_agent) + try: + capture_mime_type = capture.mime_type() + redirect_to_download_view = redirect_to_download(capture.mime_type(), raw_user_agent) + except AttributeError: + # if capture is deleted, we will catch it here + capture_mime_type = None + redirect_to_download_view = False # If this record was just created by the current user, show them a new record message new_record = request.user.is_authenticated() and link.created_by_id == request.user.id and not link.user_deleted \ @@ -229,7 +235,7 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): context = { 'link': link, 'redirect_to_download_view': redirect_to_download_view, - 'mime_type': capture.mime_type(), + 'mime_type': capture_mime_type, 'can_view': request.user.can_view(link), 'can_edit': request.user.can_edit(link), 'can_delete': request.user.can_delete(link), From 7dd89df9d07f9a805f82081b10d4d4586873fe61 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Thu, 17 Aug 2017 17:53:02 -0400 Subject: [PATCH 09/11] refactor - minor fixes in phrasing and boolean returns --- perma_web/perma/utils.py | 6 ++---- perma_web/perma/views/common.py | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/perma_web/perma/utils.py b/perma_web/perma/utils.py index 76701ae23..3b4c1f7ab 100644 --- a/perma_web/perma/utils.py +++ b/perma_web/perma/utils.py @@ -257,13 +257,11 @@ def parse_user_agent(user_agent_str): return user_agent_parser.ParseUserAgent(user_agent_str) -### pdf handling on mobile apple ### +### pdf handling on mobile ### def redirect_to_download(capture_mime_type, user_agent_str): # redirecting to a page with a download button (and not attempting to display) # if mobile apple device, and the request is a pdf parsed_agent = parse_user_agent(user_agent_str) - if "Mobile" in parsed_agent["family"] and "pdf" in capture_mime_type: - return True - return False + return "Mobile" in parsed_agent["family"] and "pdf" in capture_mime_type diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index 0ba91940a..adbff60f1 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -214,7 +214,7 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): # Redirecting to a download page if on mobile try: capture_mime_type = capture.mime_type() - redirect_to_download_view = redirect_to_download(capture.mime_type(), raw_user_agent) + redirect_to_download_view = redirect_to_download(capture_mime_type, raw_user_agent) except AttributeError: # if capture is deleted, we will catch it here capture_mime_type = None From a4221faafc7e273fec4ed9fb9377e00223a89612 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Sun, 20 Aug 2017 14:14:42 -0400 Subject: [PATCH 10/11] fix - nested redirect to download view, so that we don't expose private links --- perma_web/perma/templates/archive/single-link.html | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/perma_web/perma/templates/archive/single-link.html b/perma_web/perma/templates/archive/single-link.html index ee0a0fc63..77965dcfb 100755 --- a/perma_web/perma/templates/archive/single-link.html +++ b/perma_web/perma/templates/archive/single-link.html @@ -246,10 +246,12 @@ {% if link.user_deleted %} {% include "archive/deleted.html" %} - {% elif redirect_to_download_view %} - {% include "archive/download_to_view_pdf.html" %} {% elif can_view %} - {% include "archive/iframe.html" %} + {% if redirect_to_download_view %} + {% include "archive/download_to_view_pdf.html" %} + {% else %} + {% include "archive/iframe.html" %} + {% endif %} {% elif link.is_private %} {% include "archive/dark-archive.html" %} {% endif %} From b7fa0a6a4b395bbfdcb8e68d531e5c3418c02134 Mon Sep 17 00:00:00 2001 From: anastasia <anastasia.aizman@gmail.com> Date: Sun, 20 Aug 2017 14:15:21 -0400 Subject: [PATCH 11/11] refactor - minor fixes --- .../templates/archive/download_to_view_pdf.html | 12 +++++------- perma_web/perma/views/common.py | 10 +++++----- 2 files changed, 10 insertions(+), 12 deletions(-) diff --git a/perma_web/perma/templates/archive/download_to_view_pdf.html b/perma_web/perma/templates/archive/download_to_view_pdf.html index bd3c2064b..63f31ce82 100644 --- a/perma_web/perma/templates/archive/download_to_view_pdf.html +++ b/perma_web/perma/templates/archive/download_to_view_pdf.html @@ -1,7 +1,5 @@ -{% with request.META.HTTP_REFERER as referer %} - <div class="record-message"> - <p class="record-message-primary">Perma.cc can't display this file type on mobile, but you can view or download the archived file by clicking below.</p> - <p class="record-message-secondary">File type {{mime_type}}</p> - <a class="btn btn-primary" target="_blank" href="{{capture.url}}">View/Download File</a> - <div> -{% endwith %} \ No newline at end of file +<div class="record-message"> + <p class="record-message-primary">Perma.cc can't display this file type on mobile, but you can view or download the archived file by clicking below.</p> + <p class="record-message-secondary">File type {{mime_type}}</p> + <a class="btn btn-primary" target="_blank" href="{{capture.url}}">View/Download File</a> +<div> \ No newline at end of file diff --git a/perma_web/perma/views/common.py b/perma_web/perma/views/common.py index adbff60f1..2a3103b72 100755 --- a/perma_web/perma/views/common.py +++ b/perma_web/perma/views/common.py @@ -210,15 +210,15 @@ def make_warcinfo(filename, guid, coll_title, coll_desc, rec_title, pages): if (not capture or capture.status != 'success') and link.screenshot_capture and link.screenshot_capture.status == 'success': return HttpResponseRedirect(reverse('single_linky', args=[guid])+"?type=image") - # Special handling for mobile pdf viewing because it can be buggy - # Redirecting to a download page if on mobile try: capture_mime_type = capture.mime_type() - redirect_to_download_view = redirect_to_download(capture_mime_type, raw_user_agent) except AttributeError: - # if capture is deleted, we will catch it here + # If capture is deleted, then mime type does not exist. Catch error. capture_mime_type = None - redirect_to_download_view = False + + # Special handling for mobile pdf viewing because it can be buggy + # Redirecting to a download page if on mobile + redirect_to_download_view = redirect_to_download(capture_mime_type, raw_user_agent) # If this record was just created by the current user, show them a new record message new_record = request.user.is_authenticated() and link.created_by_id == request.user.id and not link.user_deleted \