From 297f4744318b486bb6380338072fadd87906b77f Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Fri, 23 Feb 2024 15:34:58 +0000 Subject: [PATCH 1/2] fix(dev): force xlsx download for edge; - Force xlsx downloads for MS Edge. --- ckanext/recombinant/views.py | 34 +++++++++++++++++++++++++++++++--- 1 file changed, 31 insertions(+), 3 deletions(-) diff --git a/ckanext/recombinant/views.py b/ckanext/recombinant/views.py index 3ac8e54..5a3f04a 100644 --- a/ckanext/recombinant/views.py +++ b/ckanext/recombinant/views.py @@ -242,9 +242,22 @@ def template(dataset_type, lang, owner_org): blob = StringIO() book.save(blob) response = Response(blob.getvalue()) - response.headers['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + # (canada fork only): modify response headers for Microsoft Edge + content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + disposition_type = 'inline' + user_agent_legacy = request.get('headers', {}).get('User-Agent') + user_agent = request.get('headers', {}).get('Sec-CH-UA', user_agent_legacy) + if user_agent and ( + "Microsoft Edge" in user_agent or + "Edg/" in user_agent or + "EdgA/" in user_agent + ): + content_type = 'application/octet-stream' + disposition_type = 'attachment' + response.headers['Content-Type'] = content_type response.headers['Content-Disposition'] = ( - 'inline; filename="{0}_{1}_{2}.xlsx"'.format( + '{}; filename="{0}_{1}_{2}.xlsx"'.format( + disposition_type, dataset['owner_org'], lang, dataset['dataset_type'])) @@ -262,7 +275,22 @@ def data_dictionary(dataset_type): blob = StringIO() book.save(blob) response = Response(blob.getvalue()) - response.headers['Content-Type'] = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + # (canada fork only): modify response headers for Microsoft Edge + content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + disposition_type = 'inline' + user_agent_legacy = request.get('headers', {}).get('User-Agent') + user_agent = request.get('headers', {}).get('Sec-CH-UA', user_agent_legacy) + if user_agent and ( + "Microsoft Edge" in user_agent or + "Edg/" in user_agent or + "EdgA/" in user_agent + ): + content_type = 'application/octet-stream' + disposition_type = 'attachment' + response.headers['Content-Type'] = content_type + response.headers['Content-Disposition'] = '{}; filename="{}.xlxs"'.format( + disposition_type, + dataset_type) return response From 29f7ef940a6e471587497bbf6d4b9b30ded941ab Mon Sep 17 00:00:00 2001 From: Jesse Vickery Date: Fri, 23 Feb 2024 16:09:59 +0000 Subject: [PATCH 2/2] fix(dev): request obj, reusable method; - Use obj not dict request syntax. - Reusable method for xlsx header values. --- ckanext/recombinant/views.py | 53 ++++++++++++++++++------------------ 1 file changed, 27 insertions(+), 26 deletions(-) diff --git a/ckanext/recombinant/views.py b/ckanext/recombinant/views.py index 5a3f04a..2ed9470 100644 --- a/ckanext/recombinant/views.py +++ b/ckanext/recombinant/views.py @@ -186,6 +186,29 @@ def record_fail(err): ) +def _xlsx_response_headers(): + """ + Returns tuple of content type and disposition type. + + If the request is from MS Edge user agent, we force the XLSX + download to prevent Edge from cowboying into Office Apps Online + """ + content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' + disposition_type = 'inline' + user_agent_legacy = getattr(request, 'headers', {}).get('User-Agent') + user_agent = getattr(request, 'headers', {}).get('Sec-CH-UA', user_agent_legacy) + if user_agent and ( + "Microsoft Edge" in user_agent or + "Edg/" in user_agent or + "EdgA/" in user_agent + ): + # force the XLSX file to be downloaded in MS Edge, + # and not open in Office Apps Online. + content_type = 'application/octet-stream' + disposition_type = 'attachment' + return content_type, disposition_type + + @recombinant.route('/recombinant-template/__.xlsx', methods=['GET', 'POST']) def template(dataset_type, lang, owner_org): @@ -242,21 +265,10 @@ def template(dataset_type, lang, owner_org): blob = StringIO() book.save(blob) response = Response(blob.getvalue()) - # (canada fork only): modify response headers for Microsoft Edge - content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - disposition_type = 'inline' - user_agent_legacy = request.get('headers', {}).get('User-Agent') - user_agent = request.get('headers', {}).get('Sec-CH-UA', user_agent_legacy) - if user_agent and ( - "Microsoft Edge" in user_agent or - "Edg/" in user_agent or - "EdgA/" in user_agent - ): - content_type = 'application/octet-stream' - disposition_type = 'attachment' + content_type, disposition_type = _xlsx_response_headers() response.headers['Content-Type'] = content_type response.headers['Content-Disposition'] = ( - '{}; filename="{0}_{1}_{2}.xlsx"'.format( + '{}; filename="{}_{}_{}.xlsx"'.format( disposition_type, dataset['owner_org'], lang, @@ -275,20 +287,9 @@ def data_dictionary(dataset_type): blob = StringIO() book.save(blob) response = Response(blob.getvalue()) - # (canada fork only): modify response headers for Microsoft Edge - content_type = 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' - disposition_type = 'inline' - user_agent_legacy = request.get('headers', {}).get('User-Agent') - user_agent = request.get('headers', {}).get('Sec-CH-UA', user_agent_legacy) - if user_agent and ( - "Microsoft Edge" in user_agent or - "Edg/" in user_agent or - "EdgA/" in user_agent - ): - content_type = 'application/octet-stream' - disposition_type = 'attachment' + content_type, disposition_type = _xlsx_response_headers() response.headers['Content-Type'] = content_type - response.headers['Content-Disposition'] = '{}; filename="{}.xlxs"'.format( + response.headers['Content-Disposition'] = '{}; filename="{}.xlsx"'.format( disposition_type, dataset_type) return response