aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormjfernez <mjfernez@gmail.com>2021-06-15 23:28:40 -0400
committermjfernez <mjfernez@gmail.com>2021-06-16 00:12:00 -0400
commit945594509e6a19ab0229e9949691e2f7652ea500 (patch)
tree6604218008b8de51fa70d998cadc960ef627efe2
parent3ba991bedda7ac3d2e090bfa9bd9d254ee285ae6 (diff)
downloadezcms-945594509e6a19ab0229e9949691e2f7652ea500.tar.gz
Changed / to /site, added views.py, README amended
Previously this program served files in the 'templates/site' dir on '/', but this caused problems when accessing raw files using '/raw/' which is useful for embedding or quickly downloading content. It's also an inconvenience to the user, since they have to add a word rather than double-clicking an replacing it. The main server file and the base and index templates have been changed to reflect this. The codebase has been reorganized to separate views from the main flask app. Blueprints were avoided since only one blueprint would be needed so thus unnecessary. README and docstrings were also expanded for clarity and edited for errors. Some comments
-rw-r--r--README16
-rw-r--r--server.py184
-rw-r--r--templates/base.html4
-rw-r--r--templates/site/tutorials/py-style.html0
-rw-r--r--views.py180
5 files changed, 204 insertions, 180 deletions
diff --git a/README b/README
index ddc1932..a0a84f2 100644
--- a/README
+++ b/README
@@ -24,11 +24,11 @@ elsewhere.
Why not just use a database or the million other CMS software packages out
there? Zero reason not to! I just wanted to see what it would look like to
build something from the ground up WITHOUT having to copy HTML over and over
-again. Databases are great, but so are filesystems, and I see no reason to
+again. Databases are great, but so are file systems, and I see no reason to
overcomplicate when making a simple home page. This software is primarily
geared towards bloggers or people who want a home page like it's 1999, but
Flask has great documentation so I think you'll find it a pleasure to build on
-top of.
+top of if you want to get creative.
### Why not just neocities?
@@ -58,8 +58,10 @@ $ python server.py
```
Your server will (by default) be hosted on http://127.0.0.1:5000
-and have the `templates/site/` directory mounted. You should see `home.html`
-render.
+and have the `templates/site/` directory delivered to your users when they
+access http://127.0.0.1:5000/site/
+
+You should see `home.html` render on the root directory.
## Adding Pages
@@ -70,7 +72,7 @@ particular is special since it contains the top-level folders which will be
used to navigate your site, but any folders beneath will be automatically
indexed.
-As an excercise, add a file to the `templates/site/thoughts/rants` folder
+As an exercise, add a file to the `templates/site/thoughts/rants` folder
called `myrant.html` and put the following content:
`<p>I don't like spam!</p>`
@@ -185,7 +187,7 @@ replace the HTML with your own license (or none), by editing
`templates/site/license.html`
-### Other tips
+### Other Tips
There are a few special directories linked that are needed to
customize your site. First the `static` directory, which holds your static
@@ -204,6 +206,8 @@ documented. A quickstart looks like this:
```bash
$ sudo pip install uwsgi
+$ sudo mkdir /var/path/to/your-flask/
+$ sudo chown www-data -R /var/path/to/your-flask
$ uwsgi -s /var/path/to/your-flask.sock --manage-script-name --mount /=server:app --virtualenv ./env
```
diff --git a/server.py b/server.py
index e2e93f0..e77485c 100644
--- a/server.py
+++ b/server.py
@@ -1,183 +1,15 @@
import os
from flask import Flask
-from flask import request, send_from_directory, abort
-from flask import render_template, render_template_string
from siteconfig import siteconfig
app = Flask(__name__)
-# bit of a hack.
-# Brackets don't play nicely with Jinja so instead of using .format,
-# we just replace the special charcater $
-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.
-
- 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
- """
- dirs = []
- files = []
- links = []
- description = ""
- 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:
- with open(path + '/' + obj) as f:
- description = f.read()
- 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, diretories won't actually be "hidden" but
- they are still not indexed by this program
- """
- return path.split('/')[-1].startswith('.')
-
-
-@app.route("/")
-def home():
- """
- home - renders the template `home.html` as the main index file
-
- If you'd like to customize your home page, that is the file you want to
- edit, though you can optionally change the title here if you wish
- """
- context = default_context()
- context.update(
- {
- 'title': app.config['HOME_TITLE'],
- 'parent_dir': '/'
- }
- )
- return render_template("site/home.html", **context)
-
-
-# from: https://pythonise.com/series/learning-flask/sending-files-with-flask
-@app.route("/<path:path>")
-def render_file(path):
- """
- render_file - renders an HTML document for the given `path`.
-
- If `path` is an HTML file it is rendered within the base template,
- otherwise, the raw file is returned. If `path` points to a directory, this
- function instead creates an index for the directory containing it's files,
- links, and other info.
- """
- if is_hidden_path(path):
- abort(404)
- abs_path = "./templates/site/" + path
- context = default_context()
- context.update(
- {
- 'title': path.split('.')[0].upper(),
- 'parent_dir': '/' + '/'.join(path.split('/')[:-1])
- }
- )
- if os.path.isfile(abs_path):
- if abs_path.endswith('.html'):
- with open(abs_path, 'rb') as f:
- content = f.read().decode("UTF-8")
- return render_template_string(CONTENT_BLOCK.replace('$', content), **context)
- elif abs_path.endswith('.html!'):
- return render_template("site/" + path, **context)
- else:
- # not an html file, so don't render it
- return send_from_directory('templates/site/', path,
- mimetype=siteconfig.MIMETYPES.get(
- f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE
- )
- )
- elif os.path.isdir(abs_path):
- dirs, files, links, description = index_dir(abs_path)
- context.update(
- {
- 'cur_dir': path.split('/')[-1] + '/',
- 'dirs': dirs,
- 'files': files,
- 'links': links,
- 'description': description
- }
- )
- return render_template("index.html", **context)
- else:
- context.update({'errors': "404 File not found"})
- return render_template("base.html", **context)
-
-
-@app.route("/raw/<path:path>")
-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
- """
- return send_from_directory('template/site/', path,
- mimetype=siteconfig.MIMETYPES.get(
- f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE
- )
- )
-
-
-@app.route("/static/<path:path>")
-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
- """
- return send_from_directory('static/', path,
- mimetype=siteconfig.MIMETYPES.get(
- f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE
- )
- )
-
+from views import *
def setup():
"""
setup - sets up the app according to the settings specified (or not
- speified) in `siteconfig`
+ specified) in `siteconfig`
"""
if siteconfig.SECRET_KEY:
app.config['SECRET_KEY'] = siteconfig.SECRET_KEY
@@ -188,12 +20,20 @@ def setup():
if siteconfig.MAIN_SITE_DIRS:
app.config.update({'MAIN_SITE_DIRS': siteconfig.MAIN_SITE_DIRS})
else:
- app.config.update({'MAIN_SITE_DIRS': index_dir('./templates/site')[0]})
+ s = './templates/site/'
+ top_dirs = [
+ x for x in os.listdir(s) if os.path.isdir(s + x)
+ ]
+ app.config.update(
+ {
+ 'MAIN_SITE_DIRS': sorted(top_dirs)
+ }
+ )
app.config.update({'DOMAIN': siteconfig.DOMAIN})
app.config.update({'HOME_TITLE': siteconfig.HOME_TITLE})
-# Need to come first to be compatible with wsgi
+# Setup needs to come first to be compatible with wsgi
setup()
if __name__ == '__main__':
app.run()
diff --git a/templates/base.html b/templates/base.html
index 5c4e189..6476091 100644
--- a/templates/base.html
+++ b/templates/base.html
@@ -13,7 +13,7 @@
<div class="navbar">
<b>|</b> <!-- This makes the bar symmetrical -->
{% for dir in navbar %}
- <b> <a href="/{{ dir }}">{{ dir }}/</a> |</b>
+ <b> <a href="/site/{{ dir }}">{{ dir }}/</a> |</b>
{% endfor %}
</div>
<h2>{{ title }}</h2>
@@ -21,7 +21,7 @@
{% block content %}
{% endblock %}
<h3>{{ errors }}</h3>
- {% if parent_dir != '/' %}
+ {% if parent_dir != '/site/' %}
<h3><a href="{{ parent_dir }}">Go up to parent folder ({{ parent_dir }})</a></h3>
{% endif %}
</div>
diff --git a/templates/site/tutorials/py-style.html b/templates/site/tutorials/py-style.html
deleted file mode 100644
index e69de29..0000000
--- a/templates/site/tutorials/py-style.html
+++ /dev/null
diff --git a/views.py b/views.py
new file mode 100644
index 0000000..c4e3fe2
--- /dev/null
+++ b/views.py
@@ -0,0 +1,180 @@
+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
+
+# 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 free text. Both are displayed on the index.html
+ for the given `path`
+ """
+ dirs = []
+ files = []
+ links = []
+ description = ""
+ 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:
+ with open(path + '/' + obj) as f:
+ description = f.read()
+ 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('.')
+
+
+@app.route("/")
+@app.route("/site")
+def home():
+ """
+ home - renders the template `home.html` as the main index file
+
+ If you'd like to customize your home page, that is the file you want to
+ 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/'
+ }
+ )
+ return render_template("site/home.html", **context)
+
+
+# from: https://pythonise.com/series/learning-flask/sending-files-with-flask
+@app.route("/site/<path:path>")
+def render_file(path):
+ """
+ render_file - renders an HTML document for the given `path`.
+
+ If `path` is an HTML file it is rendered within the base template,
+ otherwise, the raw file is returned. If `path` points to a directory, this
+ function instead creates an index for the directory containing it's files,
+ links, and other info.
+ """
+ if is_hidden_path(path):
+ abort(404)
+ abs_path = "./templates/site/" + path
+ context = default_context()
+ context.update(
+ {
+ 'title': path.split('.')[0].upper(),
+ 'parent_dir': '/site/' + '/'.join(path.split('/')[:-1])
+ }
+ )
+ if os.path.isfile(abs_path):
+ if abs_path.endswith('.html'):
+ with open(abs_path, 'rb') as f:
+ content = f.read().decode("UTF-8")
+ return render_template_string(CONTENT_BLOCK.replace('$', content), **context)
+ elif abs_path.endswith('.html!'):
+ return render_template("site/" + path, **context)
+ else:
+ # not an html file, so don't render it
+ return send_from_directory(
+ 'templates/site/',
+ path,
+ mimetype=siteconfig.MIMETYPES.get(
+ f".{ path.split('.')[-1] }",
+ siteconfig.DEFAULT_MIMETYPE
+ )
+ )
+ elif os.path.isdir(abs_path):
+ dirs, files, links, description = index_dir(abs_path)
+ context.update(
+ {
+ 'cur_dir': path.split('/')[-1] + '/',
+ 'dirs': dirs,
+ 'files': files,
+ 'links': links,
+ 'description': description
+ }
+ )
+ return render_template("index.html", **context)
+ else:
+ context.update({'errors': "404 File not found"})
+ return render_template("base.html", **context)
+
+
+@app.route("/raw/<path:path>")
+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.
+ """
+ return send_from_directory('templates/site/', path,
+ mimetype=siteconfig.MIMETYPES.get(
+ f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE
+ )
+ )
+
+
+@app.route("/static/<path:path>")
+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
+ """
+ return send_from_directory('static/', path,
+ mimetype=siteconfig.MIMETYPES.get(
+ f".{ path.split('.')[-1] }", siteconfig.DEFAULT_MIMETYPE
+ )
+ )