--- /dev/null
+#! .venv/bin/python3
+
+from flask import Flask, Response, request
+import markdown
+from os import listdir
+from markdown.extensions.toc import TocExtension
+
+app = Flask(__name__)
+md = markdown.Markdown(extensions = ['meta', 'tables', 'footnotes', TocExtension(title = "Table of contents")])
+
+class Page():
+ def __init__(
+ self,
+ title: str = "Unamed page",
+ abstract: str = "...",
+ keywords: list = ["Undefined"],
+ date: str = "n.d.",
+ content: str = ""
+ ):
+
+ self.title = title
+ self.abstract = abstract
+ self.keywords = keywords
+ self.date = date
+ self.content = content
+
+ def from_metadata(self, metadata):
+ if "title" in metadata: self.title = metadata["title"]
+ if "abstract" in metadata: self.abstract = metadata["abstract"]
+ if "keywords" in metadata: self.keywords = [x.strip().title() for x in metadata["keywords"].split(",")]
+ if "date" in metadata: self.date = metadata["date"]
+
+ def make(self):
+ format_keywords = " - ".join([f"<a href='/categories?name={key.lower()}'>{key}</a>" for key in self.keywords])
+
+ page = f"""
+<!DOCTYPE html>
+<html>
+ <head>
+ <title>{self.title}</title>
+ <link rel="stylesheet" href="style.css">
+ <script src="script.js"></script>
+ </head>
+ <body>
+ <h1 class='mainTitle'>{self.title}</h1>
+ <h2>{self.date}</h2>
+ <p>Abstract: <em>{self.abstract}</em></p>
+ <p>Keywords: <em>{format_keywords}</em></p>
+ <hr>
+ <div>
+ {self.content}
+ </div>
+ <p>
+ © William Greenwood 2024
+ </p>
+ </body>
+</html>
+ """
+
+ return Response(page, mimetype="text/html")
+
+@app.route("/")
+def homepage():
+ return "Hello, World!"
+
+@app.route("/<string:title>.<string:extension>")
+def get_static(title, extension):
+ title = title.replace("/", "")
+
+ match extension:
+ case "css": path, mime = "/", "text/css"
+ case "js": path, mime = "/", "text/javascript"
+ case "png": path, mime = "/media/", "image/png"
+ case _: path = mime = ""
+
+ try:
+ with open(f"{path}/{title}.{extension}", "r") as f:
+ return Response(f.read, minetype=mime)
+
+ except FileNotFoundError:
+ return ""
+
+@app.route("/categories")
+def get_categories():
+ name = request.args.get('name')
+ index = {}
+
+ for file_name in listdir("./pages"):
+ keywords = ["Undefined"]
+ title = "Untitled post"
+ abstract = "..."
+ with open(f"./pages/{file_name}", "r") as f:
+ while keywords == ["Undefined"]:
+ line = f.readline().split(":")
+ if len(line) == 2:
+ key, value = line
+ match key:
+ case "title":
+ title = value.strip().title()
+ case "abstract":
+ abstract = value.strip()
+ case "categories":
+ keywords = [x.strip() for x in value.split(",")]
+ else:
+ break
+
+ entry = {"title": title, "abstract": abstract, "path": f"/{file_name[:-3]}"}
+ for key in keywords:
+ if key in index:
+ index[key] += [entry]
+ elif key == name or name is None:
+ index.update({key: [entry]})
+
+ content = ""
+ for c in index:
+ content += f"<h1>{c}</h1><ul>"
+
+ for post in index[c]:
+ content += f"<li><a href='{post['path']}'>{post['title']} - <em>{abstract}</em></a></li>"
+
+ content += "</ul>"
+
+ page = Page(
+ title = "Keywords",
+ keywords = [c.title() for c in index],
+ content = content
+ )
+ return page.make()
+
+@app.route("/<string:title>")
+def generate_page(title):
+ title = title.replace("/", "")
+ try:
+ with open(f"pages/{title}.md", "r") as f:
+ html = md.convert(f.read())
+ metadata = {k: v[0] for k, v in md.Meta.items()}
+ md.reset()
+
+ page = Page(content = html)
+ page.from_metadata(metadata)
+ return page.make()
+
+ except FileNotFoundError:
+ page = Page(title = "404", abstract = "Page not found!")
+ return page.make()
+
+if __name__ == "__main__":
+ app.run(host='127.0.0.1', port=5000)