diff options
-rw-r--r-- | requirements.txt | 1 | ||||
-rw-r--r-- | server.py | 21 | ||||
-rw-r--r-- | siteconfig.py | 32 | ||||
-rw-r--r-- | view_functions.py | 71 | ||||
-rw-r--r-- | views.py | 94 |
5 files changed, 134 insertions, 85 deletions
diff --git a/requirements.txt b/requirements.txt index 63d0835..b3c4209 100644 --- a/requirements.txt +++ b/requirements.txt @@ -7,3 +7,4 @@ pip==20.3.4 setuptools==44.1.1 Werkzeug==2.0.1 Flask-Compress==1.10.1 +Flask-Caching==1.10.1 @@ -1,10 +1,20 @@ +""" +server.py - sets up and runs the flask server +""" import os from flask import Flask from siteconfig import siteconfig from flask_compress import Compress +from flask_caching import Cache app = Flask(__name__) compress = Compress() +cache = Cache( + config={ + 'CACHE_TYPE': siteconfig.CACHE_TYPE, + 'CACHE_DEFAULT_TIMEOUT': siteconfig.CACHE_DEFAULT_TIMEOUT, + } +) from views import * @@ -25,17 +35,22 @@ def setup(): else: s = "./templates/site/" top_dirs = [ - x for x in os.listdir(s) \ - if os.path.isdir(s + x) and not x.startswith(".") + x + for x in os.listdir(s) + if os.path.isdir(s + x) and not x.startswith(".") ] app.config.update({'MAIN_SITE_DIRS': sorted(top_dirs)}) app.config.update({'DOMAIN': siteconfig.DOMAIN}) app.config.update({'HOME_TITLE': siteconfig.HOME_TITLE}) - app.config.update({'COMPRESS_MIMETYPES': siteconfig.COMPRESS_MIMETYPES}) + app.config.update( + {'COMPRESS_MIMETYPES': siteconfig.COMPRESS_MIMETYPES} + ) + # Setup needs to come first to be compatible with wsgi setup() if __name__ == "__main__": compress.init_app(app) + cache.init_app(app) app.run() diff --git a/siteconfig.py b/siteconfig.py index fa73b46..4e0ef90 100644 --- a/siteconfig.py +++ b/siteconfig.py @@ -1,15 +1,20 @@ +""" +siteconfig.py - user editable configuration file +""" + + class siteconfig: # REQUIRED SETTINGS# - DOMAIN = "example.net" # Your site here! - HOME_TITLE = "WELCOME" # Goes right under - # your site - LINKS_FILE = ".links" # ".lnx" if you like - DESC_FILE = ".description" # ".desc" - DEFAULT_MIMETYPE = "application/octet-stream" + DOMAIN = "example.net" # Your site here! + HOME_TITLE = "WELCOME" # Goes right under + # your site + LINKS_FILE = ".links" # ".lnx" if you like + DESC_FILE = ".description" # ".desc" + DEFAULT_MIMETYPE = "application/octet-stream" # ^This usually prompts a browser to download a file if the mime # type is unknown. A good alternative might be "text/plain" - + # Add your desired mimetypes to the csv file MIMETYPES = {} with open('mimetypes.csv') as f: @@ -23,9 +28,18 @@ class siteconfig: # ./templates/site/. You can change this to only specific directories, but # these still have to be in ./templates/site MAIN_SITE_DIRS = None # ["dir1", "dir2", "dir3"] + # Set a custom secret key. If not set, it will be generated # Most of the time, you don't need to set this! - SECRET_KEY = None # Something random. - # Special option for Flask Compress + SECRET_KEY = None # Something random. + + # Option for Flask Compress # see here https://pypi.org/project/Flask-Compress/ COMPRESS_MIMETYPES = list(MIMETYPES.values()) + + # Option for Flask Caching + # https://flask-caching.readthedocs.io/en/latest/#configuring-flask-caching + CACHE_TYPE = "SimpleCache" + + # Time in seconds that your files stay cached for + CACHE_DEFAULT_TIMEOUT = 300 diff --git a/view_functions.py b/view_functions.py new file mode 100644 index 0000000..64dcfe0 --- /dev/null +++ b/view_functions.py @@ -0,0 +1,71 @@ +""" +view_functions.py - defines functions called by views to display the correct data +about files and paths. +""" +import os +from siteconfig import siteconfig +from server import app + + +def default_context(): + """ + default_context - returns the minimum info needed to render a template--the + domain name (for the home directory), and the top site directories which + make up the navbar + """ + return { + 'domain': app.config['DOMAIN'], + 'navbar': sorted(app.config['MAIN_SITE_DIRS']), + } + + +def index_dir(path): + """ + index_dir - Given a directory at `path`, list it's contents, + and sort each item as a file or a directory or a special file. + + return - a tuple with the values: + > a list of directories in `path`, + > a list of files in `path`, + > (if present), a list of external links to add to the index.html of the + directory + > (if present), a short description (string) of what the directory contains + + Lists are sorted alphabetically. + + *Special files include '.links' and '.description' the format of these + files is unquoted CSV and text/html. Both are displayed on the index.html + for the given `path` + """ + dirs = [] + files = [] + links = [] + description = False + contents = os.listdir(path) + for obj in contents: + if os.path.isfile(path + '/' + obj): + if obj == siteconfig.LINKS_FILE: + with open(path + '/' + obj) as f: + links = f.readlines() + elif obj == siteconfig.DESC_FILE: + description = True + elif obj.startswith('.'): + continue + else: + files.append(obj) + elif os.path.isdir(path + '/' + obj): + if obj.startswith('.'): + continue + else: + dirs.append(obj) + + return sorted(dirs), sorted(files), sorted(links), description + + +def is_hidden_path(path): + """ + Tests if last object specified in `path` is hidden. + Inspired by Unix. On Windows, directories won't actually be "hidden" but + they are still not indexed by this program + """ + return path.split('/')[-1].startswith('.') @@ -1,81 +1,25 @@ +""" +views.py - defines the logic that generates views that a user sees when +browsing to certain pages +""" import os from flask import request, send_from_directory, abort from flask import render_template, render_template_string from siteconfig import siteconfig -from server import app +from server import app, cache +from view_functions import default_context, index_dir, is_hidden_path # bit of a hack. # Brackets don't play nicely with Jinja so instead of using .format, # we just replace the special character $ -CONTENT_BLOCK = "{% extends 'base.html' %}{% block content %}${% endblock %}" - - -def default_context(): - """ - default_context - returns the minimum info needed to render a template--the - domain name (for the home directory), and the top site directories which - make up the navbar - """ - return { - 'domain': app.config['DOMAIN'], - 'navbar': sorted(app.config['MAIN_SITE_DIRS']), - } - - -def index_dir(path): - """ - index_dir - Given a directory at `path`, list it's contents, - and sort each item as a file or a directory or a special file. - - return - a tuple with the values: - > a list of directories in `path`, - > a list of files in `path`, - > (if present), a list of external links to add to the index.html of the - directory - > (if present), a short description (string) of what the directory contains - - Lists are sorted alphabetically. - - *Special files include '.links' and '.description' the format of these - files is unquoted CSV and text/html. Both are displayed on the index.html - for the given `path` - """ - dirs = [] - files = [] - links = [] - description = False - contents = os.listdir(path) - for obj in contents: - if os.path.isfile(path + '/' + obj): - if obj == siteconfig.LINKS_FILE: - with open(path + '/' + obj) as f: - links = f.readlines() - elif obj == siteconfig.DESC_FILE: - description = True - elif obj.startswith('.'): - continue - else: - files.append(obj) - elif os.path.isdir(path + '/' + obj): - if obj.startswith('.'): - continue - else: - dirs.append(obj) - - return sorted(dirs), sorted(files), sorted(links), description - - -def is_hidden_path(path): - """ - Tests if last object specified in `path` is hidden. - Inspired by Unix. On Windows, directories won't actually be "hidden" but - they are still not indexed by this program - """ - return path.split('/')[-1].startswith('.') +CONTENT_BLOCK = ( + "{% extends 'base.html' %}{% block content %}${% endblock %}" +) @app.route("/") @app.route("/site") +@cache.cached() def home(): """ home - renders the template `home.html` as the main index file @@ -84,12 +28,15 @@ def home(): edit, though you can optionally change the title here if you wish """ context = default_context() - context.update({'title': app.config['HOME_TITLE'], 'parent_dir': '/site/'}) + context.update( + {'title': app.config['HOME_TITLE'], 'parent_dir': '/site/'} + ) return render_template("site/home.html", **context) # from: https://pythonise.com/series/learning-flask/sending-files-with-flask @app.route("/site/<path:path>") +@cache.cached() def render_file(path): """ render_file - renders an HTML document for the given `path`. @@ -124,7 +71,8 @@ def render_file(path): 'templates/site/', path, mimetype=siteconfig.MIMETYPES.get( - f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE + f".{ path.split('.')[-1] }", + siteconfig.DEFAULT_MIMETYPE, ), ) elif os.path.isdir(abs_path): @@ -146,11 +94,11 @@ def render_file(path): @app.route("/raw/<path:path>") +@cache.cached() def send_file_from_site(path): """ - send_file - instead of rendering a file within a template as with - `render_file`, send the raw file to the user, when site is replace with - path. + send_file_from_site - instead of rendering a file within a template + as with `render_file`, send the raw file to the user """ return send_from_directory( 'templates/site/', @@ -162,10 +110,10 @@ def send_file_from_site(path): @app.route("/static/<path:path>") +@cache.cached() def send_file_from_static(path): """ - send_file - instead of rendering a file within a template as with - `render_file`, send the raw file to the user + send_file_from_static - send files from the static directory """ return send_from_directory( 'static/', |