From a5c94f728a577b8f330527e908bc300554b6528c Mon Sep 17 00:00:00 2001 From: Dendy Faist Date: Sat, 24 Feb 2024 06:46:16 +0100 Subject: [PATCH] Initial commit --- .gitignore | 22 ++++++++ app.py | 4 ++ debug.sh | 3 + src/__init__.py | 128 ++++++++++++++++++++++++++++++++++++++++++ src/config.py | 8 +++ static/style/main.css | 100 +++++++++++++++++++++++++++++++++ templates/base.html | 25 +++++++++ templates/error.html | 9 +++ templates/main.html | 68 ++++++++++++++++++++++ 9 files changed, 367 insertions(+) create mode 100644 .gitignore create mode 100755 app.py create mode 100755 debug.sh create mode 100644 src/__init__.py create mode 100644 src/config.py create mode 100644 static/style/main.css create mode 100644 templates/base.html create mode 100644 templates/error.html create mode 100644 templates/main.html diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..36a0601 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +.DS_Store +.idea +*.log +tmp/ +.bak* +.cache/ + +# --- Python --- +__pycache__/ +venv/ +# -------------- + +# --- JavaScript --- +node_modules +bun.lockb +# ------------------ + +# --- Local env --- +data/ +config.toml +# ----------------- + diff --git a/app.py b/app.py new file mode 100755 index 0000000..d7bc2c4 --- /dev/null +++ b/app.py @@ -0,0 +1,4 @@ +from src import app + +if __name__ == "__main__": + app.run() diff --git a/debug.sh b/debug.sh new file mode 100755 index 0000000..e0dc617 --- /dev/null +++ b/debug.sh @@ -0,0 +1,3 @@ +#!/bin/sh + +venv/bin/python -m flask run --debug -h 192.168.5.3 diff --git a/src/__init__.py b/src/__init__.py new file mode 100644 index 0000000..6784035 --- /dev/null +++ b/src/__init__.py @@ -0,0 +1,128 @@ +#!/usr/bin/env python3 + +import traceback +import os + +from flask import Flask, render_template, request +from pygments import formatters, highlight, lexers +import markdown + +from src import ( + # tango_controller, + utils, + config, +) + +app = Flask( + __name__, + template_folder="../templates", + static_folder="../static", +) +# app.register_blueprint(tango_controller.bp) + +# Edit +# Create file + + +def get_tree() -> dict: + data_path = config.get('data_path') + ret = {} + + for root, _, files in os.walk(data_path): + current = ret + + relpath = os.path.relpath(root, data_path) + breadcrumbs = relpath.split(os.path.sep) + if breadcrumbs == ['.']: + breadcrumbs = [] + + # Move the current to that folder and create + # the intermediate steps if they don't exist + for folder in breadcrumbs: + if folder not in current or current[folder] is None: + current[folder] = {} + + current = current[folder] + + print(breadcrumbs) + for file in files: + filename, _ = os.path.splitext(file) + current[filename] = None + + return ret + + +@app.route('/', defaults={'path': ''}) +@app.route('/', methods=['POST', 'GET']) +def index(path): + internal_path = os.path.join(config.get('data_path'), path + '.md') + path = '/' + path + + # Checks ################################################### + + if '..' in path: + return 'Path cannot contain double dots, i.e. "..".' + + # If the user sent input, save it ########################## + + if path == '/': + return ( + render_template( + "main.html", + path=path, + item_list=get_tree(), + markdown=markdown.markdown, + content='Welcome', + edit=False, + ), + 200, + ) + + raw_markdown = request.form.get('text', None) + if raw_markdown is not None: + with open(internal_path, 'w') as file: + file.write(str(raw_markdown)) + + # Get the document contents ################################ + + is_edit = 'edit' in request.args and path != '/' + + if os.path.exists(internal_path): + with open(internal_path) as file: + raw_markdown = file.read() + elif is_edit: + raw_markdown = f'# {path}\n\nChangeme' + else: + return ( + render_template( + "error.html", + code=404, + msg=f'The path "{path}" does not exist.', + ), + 404, + ) + + # Actual serving ########################################### + + return ( + render_template( + "main.html", + path=path, + item_list=get_tree(), + markdown=markdown.markdown, + content=raw_markdown, + edit=is_edit, + ), + 200, + ) + + +@ app.errorhandler(Exception) +def internal_error(e): + tb_text = "".join(traceback.format_exc()) + + lexer = lexers.get_lexer_by_name("pytb", stripall=True) + formatter = formatters.get_formatter_by_name("terminal") + tb_colored = highlight(tb_text, lexer, formatter) + print(tb_colored) + return utils.ERR_500 diff --git a/src/config.py b/src/config.py new file mode 100644 index 0000000..8d4b981 --- /dev/null +++ b/src/config.py @@ -0,0 +1,8 @@ +import tomllib + +with open("config.toml", "rb") as f: + config = tomllib.load(f) + + +def get(q: str): + return config.get(q, None) diff --git a/static/style/main.css b/static/style/main.css new file mode 100644 index 0000000..2980c1d --- /dev/null +++ b/static/style/main.css @@ -0,0 +1,100 @@ +html { + min-height: 100%; +} + +body { + padding: 20px; + background-color: #191919; + color: white; + font-family: monospace; + margin-bottom: 100px; +} + +h1, h2, h3, h4, h5, h6 { + color: orange; +} + +a { + text-decoration: none; + color: orange; +} + a:hover { + color: #191919; + background-color: orange; + } + +input { + border: 1px solid black; + background-color: white; +} + +footer { + background-color: black; + position: fixed; + left: 0; + bottom: 0; + width: calc(100vw - 20px); + padding: 10px; + text-align: center; + overflow: hidden; +} + +ul { + padding-left: 20px; + padding-bottom: 0px; + list-style-type: none; +} + +main { + display: flex; + gap: 20px; + min-height: 80vh; +} + +nav { + padding-right: 10px; + display: flex; + flex-direction: column; + border-right: 1px solid orange; + width: 200px; +} + +article { + flex-grow: 1; +} + +pre { + background-color: #000; + color: #DDD; + padding: 10px; + padding-left: 20px; +} + + +.editor-toolbar { + border-top: 0px solid #444; + border-left: 0px solid #444; + border-right: 0px solid #444; + border-radius: 0px; +} +.EasyMDEContainer .CodeMirror { + border: 1px solid #444; +} + +.editor-toolbar .fa { + color: white; +} + +.editor-toolbar button.active, +.editor-toolbar button:hover { + background-color: black; +} + +.CodeMirror { + color: white; + background-color: black; +} + +.CodeMirror-cursor { + border-left: 2px solid gray; +} diff --git a/templates/base.html b/templates/base.html new file mode 100644 index 0000000..57addf8 --- /dev/null +++ b/templates/base.html @@ -0,0 +1,25 @@ + + + + + + + + + {% block title %}{% endblock %} - {{ config.get("name") }} + + + + + {# #} + + + + + + {% block body %}{% endblock %} + + diff --git a/templates/error.html b/templates/error.html new file mode 100644 index 0000000..f9dad71 --- /dev/null +++ b/templates/error.html @@ -0,0 +1,9 @@ +{% extends 'base.html' %} + +{% block title %}Error {{ code }}{% endblock %} + +{% block body %} +

Error {{ code }}

+

{{ msg }}

+Return to Index +{% endblock %} diff --git a/templates/main.html b/templates/main.html new file mode 100644 index 0000000..86eddd4 --- /dev/null +++ b/templates/main.html @@ -0,0 +1,68 @@ +{% extends 'base.html' %} + +{% block title %}{{ path }}{% endblock %} + +{% macro render_tree(tree, root='/') %} + +{% endmacro %} + +{% block body %} +
+ + +
+ {% if not edit %} + {% autoescape false %} + {{ markdown(content, extensions=['extra']) }} + {% endautoescape %} + + {% if path != '/' %} + Edit + {% endif %} + {% else %} +
+ + + + + {% endif %} +
+
+ + {% set footer = config.get('foote') %} + {% if footer not in [None, False, ""] %} + + {% endif %} + +{% endblock %}