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 0000000000000000000000000000000000000000..61111bc8de627b35858aa7f6c1c471b58b743c16 --- /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 d88c3974fb4c7076653be5d2730664b4e2c89c01..b962a913fbf51f10259a6aa032502ef780296fa9 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 7739ad567eeb997bc0d2f47a17cb8c096dc4a833..2df9744d72b5f00450000d94ad6b667ab160bb97 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 7587a59be5f656968864af8ae07c08bed3fa7560..e3983636e69ea95805f741f86b10f9d92efaeb62 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 a46b68a397e3a2e4150481ec9a32bf87762bd211..66005518179e606ccf97fe01b33b7c75cf88235e 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 6ff5548e4a6c0d969df3c1ee4824860d08968c08..c265b2d873acad97ffaa4fc87676352828724f80 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():