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/', | 
