aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--rss_generator.py47
-rw-r--r--server.py21
-rw-r--r--siteconfig.py38
-rw-r--r--view_functions.py23
4 files changed, 78 insertions, 51 deletions
diff --git a/rss_generator.py b/rss_generator.py
index 4397a45..f248003 100644
--- a/rss_generator.py
+++ b/rss_generator.py
@@ -1,12 +1,24 @@
import os
from time import strftime, strptime, ctime
from siteconfig import siteconfig
+from view_functions import is_hidden_path
class RSS_Item:
+ """
+ RSS_Item - a (very) basic implementation of an object in an RSS
+ feed using only essential parameters as specified in:
+ https://www.rssboard.org/rss-specification#hrelementsOfLtitemgt
+
+ Item data is generated from a given file path
+ """
PARAGRAPHS = siteconfig.rss_channel_config['DESCRIPTION_LENGTH']
class NotAFile(Exception):
+ """
+ Throws an exception if an RSS_Item is made out of a
+ directory or invalid file
+ """
def __init__(self, path: str):
self.path = path
self.message = f"{path} not a file"
@@ -18,6 +30,7 @@ class RSS_Item:
self.FULL_PATH = path
self.TITLE = path.rsplit('.', 1)[0].split('/')[-1]
+ self.FILE_TYPE = path.rsplit('.', 1)[1]
self.DESCRIPTION = self.parse_file()
self.LAST_UPDATE = self.file_last_modified()
self.URI = self.get_uri()
@@ -35,7 +48,8 @@ class RSS_Item:
"""
parse_file - reads the file at FULL_PATH and saves the content
from when the first <p> tag is hit up to and including the
- closing </p> tag. Expects an HTML style file
+ closing </p> tag. Other files are interpreted as text files
+ and, just reads the first 3 paragraphs (two new lines in a row)
"""
with open(self.FULL_PATH) as f:
in_body = False
@@ -45,13 +59,19 @@ class RSS_Item:
if paragraphs >= self.PARAGRAPHS:
break
line = line.strip()
- if line.startswith("<p>"):
- in_body = True
- if in_body:
+ if self.FILE_TYPE in ['html', 'html!']:
+ if line.startswith("<p>"):
+ in_body = True
+ if in_body:
+ description += line
+ if line.endswith("</p>"):
+ in_body = False
+ paragraphs += 1
+ else:
description += line
- if line.endswith("</p>"):
- in_body = False
- paragraphs += 1
+ # remember, we stripped the line
+ if line == '':
+ paragraphs += 1
return ''.join(description)
@@ -59,16 +79,25 @@ class RSS_Item:
return ctime(os.stat(self.FULL_PATH).st_ctime)
def get_uri(self):
+ # return everything after "./templates/"
return '/'.join(self.FULL_PATH.split('/')[2:])
def get_rss_channel():
+ """
+ get_rss_channel - list all files from the BASE_DIR, and if allowed,
+ add them as RSS_Items to populate feed.xml. Called by feed.xml view
+ """
items = []
+ extensions = siteconfig.rss_channel_config['RSS_FILE_EXT']
for root, dirs, files in os.walk(siteconfig.BASE_DIR):
for f in files:
+ # remember, path will be like "./templates/site/..."
path = os.path.join(root, f)
if (
- path.endswith(".html") or f.endswith(".html!")
- ) and path not in siteconfig.RSS_OMIT:
+ path.split(".")[-1] in extensions
+ and path not in siteconfig.RSS_OMIT
+ and not is_hidden_path(path.split('.', 1)[1])
+ ):
items.append(RSS_Item(path))
return items
diff --git a/server.py b/server.py
index 14c4182..ab66ccc 100644
--- a/server.py
+++ b/server.py
@@ -1,7 +1,6 @@
"""
server.py - sets up and runs the flask server
"""
-import os
from flask import Flask
from siteconfig import siteconfig
from flask_compress import Compress
@@ -20,23 +19,8 @@ def setup():
setup - sets up the app according to the settings specified (or not
specified) in `siteconfig`
"""
- if siteconfig.SECRET_KEY:
- app.config['SECRET_KEY'] = siteconfig.SECRET_KEY
- else:
- SECRET_KEY = os.urandom(32)
- app.config['SECRET_KEY'] = SECRET_KEY
-
- if siteconfig.MAIN_SITE_DIRS:
- app.config.update({'MAIN_SITE_DIRS': siteconfig.MAIN_SITE_DIRS})
- else:
- s = "./templates/site/"
- top_dirs = [
- 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['SECRET_KEY'] = siteconfig.SECRET_KEY
+ app.config.update({'MAIN_SITE_DIRS': siteconfig.MAIN_SITE_DIRS})
app.config.update({'DOMAIN': siteconfig.DOMAIN})
app.config.update({'HOME_TITLE': siteconfig.HOME_TITLE})
app.config.update(
@@ -45,6 +29,7 @@ def setup():
app.config.update({'RSS_CHANNEL': get_rss_channel()})
app.config.update({'TEMPLATES_AUTO_RELOAD': True})
+
# Setup needs to come first to be compatible with wsgi
setup()
compress.init_app(app)
diff --git a/siteconfig.py b/siteconfig.py
index 4c60674..8917a20 100644
--- a/siteconfig.py
+++ b/siteconfig.py
@@ -1,28 +1,24 @@
"""
siteconfig.py - user editable configuration file
"""
+import os
class siteconfig:
- # REQUIRED SETTINGS#
-
- DOMAIN = "example.net" # Your site here!
- HOME_TITLE = "WELCOME"
- 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"
+ # BACKGROUND SETTINGS #
+ # These don't need to be changed
# This setting is required, don't change it unless you're running
# things in different directories
BASE_DIR = "./templates/site/"
+
# Add your desired mimetypes to the csv file
MIMETYPES = {}
with open('mimetypes.csv') as f:
for line in f.readlines():
ext, mime = line.strip().split(',')
MIMETYPES.update({ext: mime})
+
# This reads your omit file.
# Entries should be the full path from the site directory.
# For example "dontread.txt" in this project is entered as
@@ -32,16 +28,34 @@ class siteconfig:
for line in f.readlines():
RSS_OMIT.append(BASE_DIR + line.strip())
+ DEFAULT_SITE_DIRS = []
+ for x in os.listdir(BASE_DIR):
+ if os.path.isdir(BASE_DIR + x) and not x.startswith("."):
+ DEFAULT_SITE_DIRS.append(x)
+
+ # REQUIRED SETTINGS #
+
+ DOMAIN = "example.net" # Your site here!
+ HOME_TITLE = "WELCOME"
+ 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"
+
# OPTIONAL SETTINGS #
# Be default, ALL directories in the site toolbar are contained in
# ./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"]
+
+ MAIN_SITE_DIRS = sorted(
+ DEFAULT_SITE_DIRS
+ ) # ["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.
+ SECRET_KEY = os.urandom(32) # replace with random number.
# Options for Flask Compress
# see here https://pypi.org/project/Flask-Compress/
@@ -90,4 +104,6 @@ class siteconfig:
'WEBMASTER': "webmaster@example.net",
# Max amount of paragraphs to print in each description
'DESCRIPTION_LENGTH': 3,
+ # File extensions to include in RSS updates
+ 'RSS_FILE_EXT': ["txt", "html", "html!"],
}
diff --git a/view_functions.py b/view_functions.py
index 64dcfe0..f86952d 100644
--- a/view_functions.py
+++ b/view_functions.py
@@ -4,7 +4,6 @@ about files and paths.
"""
import os
from siteconfig import siteconfig
-from server import app
def default_context():
@@ -14,8 +13,8 @@ def default_context():
make up the navbar
"""
return {
- 'domain': app.config['DOMAIN'],
- 'navbar': sorted(app.config['MAIN_SITE_DIRS']),
+ 'domain': siteconfig.DOMAIN,
+ 'navbar': siteconfig.MAIN_SITE_DIRS,
}
@@ -49,14 +48,10 @@ def index_dir(path):
links = f.readlines()
elif obj == siteconfig.DESC_FILE:
description = True
- elif obj.startswith('.'):
- continue
- else:
+ elif not obj.startswith('.'):
files.append(obj)
elif os.path.isdir(path + '/' + obj):
- if obj.startswith('.'):
- continue
- else:
+ if not obj.startswith('.'):
dirs.append(obj)
return sorted(dirs), sorted(files), sorted(links), description
@@ -64,8 +59,10 @@ def index_dir(path):
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
+ Tests if the URI path requested by the user, has any hidden paths
+ which should not be rendered
"""
- return path.split('/')[-1].startswith('.')
+ for d in path.split('/'):
+ if d.startswith('.'):
+ return True
+ return False