From 0f7495bf2b675fdabb881b66be06e55da8df9bc9 Mon Sep 17 00:00:00 2001 From: "Brian S. Stephan" Date: Fri, 19 Jun 2020 19:58:12 -0500 Subject: [PATCH] add the ability to redirect a file-looking request to a dir if the client has requested /foo, and foo is actually a directory, this redirects the client to /foo/ --- incorporealcms/pages.py | 21 ++++++++++++++++++++- tests/functional_tests.py | 17 +++++++++++++++++ tests/test_pages.py | 26 +++++++++++++++++++++++++- 3 files changed, 62 insertions(+), 2 deletions(-) diff --git a/incorporealcms/pages.py b/incorporealcms/pages.py index a78e42b..761d5c2 100644 --- a/incorporealcms/pages.py +++ b/incorporealcms/pages.py @@ -6,7 +6,7 @@ import os import markdown from flask import Blueprint, Markup, abort from flask import current_app as app -from flask import render_template +from flask import redirect, render_template from tzlocal import get_localzone logger = logging.getLogger(__name__) @@ -19,6 +19,9 @@ md = markdown.Markdown(extensions=['meta', 'tables']) @bp.route('/') def display_page(path): """Get the file contents of the requested path and render the file.""" + if is_file_path_actually_dir_path(path): + return redirect(f'{path}/', code=301) + resolved_path = resolve_page_file(path) logger.debug("received request for path '%s', resolved to '%s'", path, resolved_path) try: @@ -52,6 +55,22 @@ def resolve_page_file(path): return path +def is_file_path_actually_dir_path(path): + """Check if requested path which looks like a file is actually a directory. + + If, for example, /foo used to be a file (foo.md) which later became a directory, + foo/, this returns True. Useful for when I make my structure more complicated + than it originally was, or if users are just weird. + """ + if not path.endswith('/'): + logger.debug("requested path '%s' looks like a file", path) + if os.path.isdir(f'{app.instance_path}/pages/{path}'): + logger.debug("...and it's actually a dir") + return True + + return False + + def generate_parent_navs(path): """Create a series of paths/links to navigate up from the given path.""" # derive additional path/location stuff based on path diff --git a/tests/functional_tests.py b/tests/functional_tests.py index 46a1c1d..b8a26d0 100644 --- a/tests/functional_tests.py +++ b/tests/functional_tests.py @@ -35,3 +35,20 @@ def test_page_has_modified_timestamp(client): response = client.get('/') assert response.status_code == 200 assert re.search(r'Last modified: ....-..-.. ..:..:.. ...', response.data.decode()) is not None + + +def test_that_page_request_redirects_to_directory(client): + """Test that a request to /foo reirects to /foo/, if foo is a directory. + + This might be useful in cases where a formerly page-only page has been + converted to a directory with subpages. + """ + response = client.get('/subdir') + assert response.status_code == 301 + + +def test_that_dir_request_does_not_redirect(client): + """Test that a request to /foo/ serves the index page, if foo is a directory.""" + response = client.get('/subdir/') + assert response.status_code == 200 + assert b'another page' in response.data diff --git a/tests/test_pages.py b/tests/test_pages.py index 319eaaf..7f59491 100644 --- a/tests/test_pages.py +++ b/tests/test_pages.py @@ -1,5 +1,5 @@ """Unit test helper methods.""" -from incorporealcms.pages import generate_parent_navs, resolve_page_file +from incorporealcms.pages import generate_parent_navs, is_file_path_actually_dir_path, resolve_page_file def test_resolve_page_file_dir_to_index(): @@ -50,3 +50,27 @@ def test_generate_page_navs_subdir_with_title_parsing_real_page(app): ('SUB!', '/subdir-with-title/'), ('/subdir-with-title/page', '/subdir-with-title/page') ] + + +def test_is_file_path_actually_dir_path_valid_file_is_yes(app): + """Test that a file request for what's actually a directory is detected as such.""" + with app.app_context(): + assert is_file_path_actually_dir_path('/subdir') + + +def test_is_file_path_actually_dir_path_valid_dir_is_no(app): + """Test that a directory request is still a directory request.""" + with app.app_context(): + assert not is_file_path_actually_dir_path('/subdir/') + + +def test_is_file_path_actually_dir_path_nonsense_file_is_no(app): + """Test that requests to nonsense file-looking paths aren't treated as dirs.""" + with app.app_context(): + assert not is_file_path_actually_dir_path('/antphnathpnthapnthsnthax') + + +def test_is_file_path_actually_dir_path_nonsense_dir_is_no(app): + """Test that a directory request is a directory request even if the dir doesn't exist.""" + with app.app_context(): + assert not is_file_path_actually_dir_path('/antphnathpnthapnthsnthax/')