From a8aa2c8457dc6b33a1ebd2173f9da2fb053f0d3f Mon Sep 17 00:00:00 2001 From: Dan Granville <dan@blipcreative.com> Date: Fri, 11 Aug 2023 14:23:05 +0100 Subject: [PATCH] txt-preview: improvements (#180) * enable horizontal scrolling * add option to truncate .txt file preview after PREVIEWER_TXT_MAX_BYTES * avoid possible invalid encoding errors Co-authored-by: Guillaume Viger <fenekku@fenekku.com> --- .../scss/invenio_previewer/txt.scss | 4 ++++ invenio_previewer/config.py | 3 +++ invenio_previewer/extensions/txt.py | 8 +++++--- .../semantic-ui/invenio_previewer/txt.html | 11 +++++------ invenio_previewer/webpack.py | 1 + tests/test_macros.py | 18 ++++++++++++++++++ 6 files changed, 36 insertions(+), 9 deletions(-) create mode 100644 invenio_previewer/assets/semantic-ui/scss/invenio_previewer/txt.scss diff --git a/invenio_previewer/assets/semantic-ui/scss/invenio_previewer/txt.scss b/invenio_previewer/assets/semantic-ui/scss/invenio_previewer/txt.scss new file mode 100644 index 0000000..61111bc --- /dev/null +++ b/invenio_previewer/assets/semantic-ui/scss/invenio_previewer/txt.scss @@ -0,0 +1,4 @@ +#text-previewer { + padding: 0.5em; +} + diff --git a/invenio_previewer/config.py b/invenio_previewer/config.py index d88c397..b962a91 100644 --- a/invenio_previewer/config.py +++ b/invenio_previewer/config.py @@ -26,6 +26,9 @@ PREVIEWER_MAX_FILE_SIZE_BYTES = 1 * 1024 * 1024 PREVIEWER_MAX_IMAGE_SIZE_BYTES = 0.5 * 1024 * 1024 """Maximum file size in bytes for image files.""" +PREVIEWER_TXT_MAX_BYTES = 1 * 1024 * 1024 +"""Maximum number of .txt file bytes to preview before truncated.""" + PREVIEWER_ZIP_MAX_FILES = 1000 """Max number of files showed in the ZIP previewer.""" diff --git a/invenio_previewer/extensions/txt.py b/invenio_previewer/extensions/txt.py index 7739ad5..2df9744 100644 --- a/invenio_previewer/extensions/txt.py +++ b/invenio_previewer/extensions/txt.py @@ -8,19 +8,20 @@ """Text rendering.""" -from flask import render_template +from flask import current_app, render_template from ..proxies import current_previewer from ..utils import detect_encoding previewable_extensions = ["txt"] +max_bytes = current_app.config.get('PREVIEWER_TXT_MAX_BYTES', -1) def render(file): """Render HTML from txt file content.""" with file.open() as fp: encoding = detect_encoding(fp, default="utf-8") - return fp.read().decode(encoding) + return fp.read(max_bytes).decode(encoding, errors="ignore") def can_preview(file): @@ -37,5 +38,6 @@ def preview(file): file=file, content=render(file), js_bundles=current_previewer.js_bundles, - css_bundles=current_previewer.css_bundles, + css_bundles=['txt_css.css'], + truncated=max_bytes < file.size, ) diff --git a/invenio_previewer/templates/semantic-ui/invenio_previewer/txt.html b/invenio_previewer/templates/semantic-ui/invenio_previewer/txt.html index 7587a59..e398363 100644 --- a/invenio_previewer/templates/semantic-ui/invenio_previewer/txt.html +++ b/invenio_previewer/templates/semantic-ui/invenio_previewer/txt.html @@ -10,11 +10,10 @@ {%- extends config.PREVIEWER_ABSTRACT_TEMPLATE %} {% block panel %} -<div class="ui container"> - <div class="ui grid column"> - <div class="column"> - <pre>{{ content }}</pre> - </div> - </div> +<div id="text-previewer"> + <pre>{{ content }}</pre> + {% if truncated %} + <hr /><div class="banner">{{ _('Preview of large file truncated') }}</div> + {% endif %} </div> {% endblock %} diff --git a/invenio_previewer/webpack.py b/invenio_previewer/webpack.py index a46b68a..6600551 100644 --- a/invenio_previewer/webpack.py +++ b/invenio_previewer/webpack.py @@ -75,6 +75,7 @@ previewer = WebpackThemeBundle( 'bottom_css': './scss/invenio_previewer/bottom.scss', 'simple_image_css': './scss/invenio_previewer/simple_image.scss', + 'txt_css': './scss/invenio_previewer/txt.scss', }, dependencies={ 'd3': '^3.5.17', diff --git a/tests/test_macros.py b/tests/test_macros.py index 6ff5548..c265b2d 100644 --- a/tests/test_macros.py +++ b/tests/test_macros.py @@ -232,6 +232,24 @@ def test_simple_image_extension(app, webassets, record): assert 'class="previewer-simple-image"' in res.get_data(as_text=True) +def test_txt_extension(app, webassets, record): + """Text .txt file viewer.""" + create_file(record, 'test1.txt', BytesIO(b'test content foobar')) + + with app.test_client() as client: + res = client.get(preview_url(record['control_number'], 'test1.txt')) + assert "<pre>test content foobar</pre>" in res.get_data(as_text=True) + + max_file_size = app.config.get( + 'PREVIEWER_TXT_MAX_BYTES', 1 * 1024 * 1024) + too_large_string = '1' * (max_file_size + 1) + create_file(record, 'test2.txt', BytesIO(b(too_large_string))) + + with app.test_client() as client: + res = client.get(preview_url(record['control_number'], 'test1.txt')) + assert "file truncated" in res.get_data(as_text=True) + + def test_view_macro_file_list(app): """Test file list macro.""" with app.test_request_context(): -- GitLab