handle yaml errors

This commit is contained in:
my 2026-01-29 12:24:19 +01:00
parent c661d09926
commit 01ae1d7e92
6 changed files with 128 additions and 13 deletions

View file

@ -25,6 +25,13 @@ APP.config.from_pyfile('settings.py')
# ---
# my attempt as showing helpful error messages.
class MarkdownRenderError(RuntimeError):
def __init__(self, kind, message, original):
super().__init__(message)
self.kind = kind
self.original = original
def get_pad_content(pad_name, ext=""):
if ext:
pad_name = f'{ pad_name }{ ext }'
@ -62,6 +69,22 @@ def all_pads():
return response
# get all pads that end in .md
def all_publications():
pads = all_pads()
pubs = []
print(pads)
if(pads and pads['data'] and pads['data']['padIDs']):
for pad in pads['data']['padIDs']:
# if extension is .md add it to pubs
if pad.endswith('.md'):
# strip the .md
name = pad.removesuffix('.md')
pubs.append(name)
return pubs
else:
return []
def create_pad_on_first_run(name, ext):
pads = all_pads()
pad = name+ext
@ -87,7 +110,21 @@ def create_pad_on_first_run(name, ext):
def md_to_html(md_pad_content):
# Convert Markdown to HTML
# html = markdown.markdown(md_pad_content, extensions=['meta', 'attr_list']) # attr_list does not work
try:
html = pypandoc.convert_text(md_pad_content, 'html', format='md')
except RuntimeError as exc:
message = str(exc)
if "YAML" in message or "YAML metadata" in message:
raise MarkdownRenderError(
kind="yaml",
message="Invalid YAML metadata. Use `key: value` and add a blank line.",
original=str(exc)
) from exc
raise MarkdownRenderError(
kind="markdown",
message = "Markdown conversion failed. Please check the markdown for errors.",
original = str(exc)
) from exc
# Sanitize the Markdown
# html = bleach.clean(html)
@ -125,6 +162,17 @@ def get_app_root():
def get_meta(metadata, key, default=None):
return metadata.get(key, [default])[0]
def render_markdown_error(name, error):
print("ERROR", error)
return render_template(
'error.html',
name=name.strip(),
error_text=str(error),
error=error,
lang="en",
title="Markdown error"
), 400
# ---
@APP.route('/', methods=['GET', 'POST'])
@ -140,7 +188,8 @@ def index():
create_pad_on_first_run(name, ext)
return redirect(url_for("pad", name=name))
else:
return render_template('start.html', home_pad_url=APP.config['HOME_PAD_URL'])
pubs = all_publications()
return render_template('start.html', pubs = pubs, home_pad_url=APP.config['HOME_PAD_URL'])
@APP.route('/<name>/')
def main(name):
@ -190,7 +239,10 @@ def css(name):
def preview(name):
# TO GENERATE THE PREVIEW WEBPAGE
md_pad_content = get_pad_content(name, ext='.md')
try:
html = md_to_html(md_pad_content)
except MarkdownRenderError as exc:
return render_markdown_error(name, exc)
metadata = get_md_metadata(md_pad_content)
lang = get_meta(metadata, 'language', 'en')
title = get_meta(metadata, 'title', 'Untitled')
@ -201,21 +253,26 @@ def preview(name):
def pagedjs(name):
# TO GENERATE THE PAGED.JS WEBPAGE
md_pad_content = get_pad_content(name, ext='.md')
try:
html = md_to_html(md_pad_content)
except MarkdownRenderError as exc:
return render_markdown_error(name, exc)
metadata = get_md_metadata(md_pad_content)
lang = get_meta(metadata, 'language', 'en')
title = get_meta(metadata, 'title', 'Untitled')
cover = get_meta(metadata, 'cover', None)
impose = False #request.args.get("impose") == "true"
return render_template('pagedjs.html', name=name.strip(), pad_content=html, lang=lang, title=title, cover=cover, impose=impose)
@APP.route('/<name>/imposed.html')
def imposed(name):
# TO GENERATE THE IMPOSED WEBPAGE
md_pad_content = get_pad_content(name, ext='.md')
try:
html = md_to_html(md_pad_content)
except MarkdownRenderError as exc:
return render_markdown_error(name, exc)
metadata = get_md_metadata(md_pad_content)
lang = get_meta(metadata, 'language', 'en')
title = get_meta(metadata, 'title', 'Untitled')
@ -230,4 +287,6 @@ def imposed(name):
if __name__ == '__main__':
APP.debug = True
APP.env = "development"
# APP.debug = False
# APP.env = "production"
APP.run(host="0.0.0.0", port=APP.config["PORTNUMBER"], threaded=True)

View file

@ -4,7 +4,8 @@ from filter_registry import register_filter
@register_filter
def remove_star_before_img(text):
# regex version
return re.sub(r'\*\s*!?\[\]\(', '![](', text)
# return re.sub(r'\*\s*!?\[\]\(', '![](', text)
return re.sub(r'\*\s*!?\[\.*]\(', '![](', text)
# @register_filter
# def remove_star_before_img(text):

View file

@ -1,16 +1,18 @@
import os
from pathlib import Path
from dotenv import load_dotenv
# Load environment variables from the .env file
load_dotenv()
# Load environment variables from the .env file alongside this module.
ENV_PATH = Path(__file__).resolve().parent / ".env"
load_dotenv(dotenv_path=ENV_PATH)
# Bind them to Python variables
APPLICATION_ROOT = os.environ.get('OCTOMODE_APPLICATION_ROOT', '/')
PORTNUMBER = int(os.environ.get('OCTOMODE_PORTNUMBER', 5001))
PAD_URL = os.environ.get('OCTOMODE_PAD_URL', 'https://pad.vvvvvvaria.org')
PAD_API_URL = os.environ.get('OCTOMODE_PAD_API_URL', 'https://pad.vvvvvvaria.org/api/1.2.15')
PAD_API_KEY = "97e3bf6a626eaaa3426833db3d936f3a"
#os.environ.get('OCTOMODE_PAD_API_KEY', '')
HOME_PAD_URL = os.environ.get('OCTOMODE_HOME_PAD_URL', '')
PAD_API_KEY = os.environ.get('OCTOMODE_PAD_API_KEY', '')
# Check if API key is provided
if not PAD_API_KEY or PAD_API_KEY == "XXX":

View file

@ -100,10 +100,16 @@ div#nav{
}
.cols {
display: grid;
grid-template-columns: 1fr 3fr;
margin-top: 3rem;
}
.home_pad_iframe {
height: 75vh;
margin: 5rem;
width: calc(100vw - 13rem);
/* margin: 5rem; */
/* width: calc(100vw - 13rem); */
border: 1px solid black;
border-radius: 5px;
}

35
templates/error.html Normal file
View file

@ -0,0 +1,35 @@
<!DOCTYPE html>
<html lang="{{ lang }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="{{ url_for('css', name=name) }}" rel="stylesheet" type="text/css" media="print">
<title>{{ title }} - {{ name }}</title>
</head>
<body>
<h1>{{ title }}</h1>
<p>The document "{{name}}" has an error.</p>
{% if error.kind == "yaml" %}
<p>It seems like that there's something wrong with the YAML at the top of your document. <br />
It should be structured like this:
</p>
<pre>
---
title: My Title
lang: en
cover: https://example.com/image.jpg
---
</pre>
<p>
Make sure that there is a space between the ":" and the value.
</p>
{% endif %}
{% elif error.kind == "markdown" %}
There's something wrong with the markdown in your pad. Please check the document or revert some of your recent changes.
{% endif %}
<details>
<summary>Details</summary>
{{error.original}}
</details>
</body>
</html>

View file

@ -5,11 +5,23 @@
<title>octomode</title>
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<style>
</style>
</head>
<body class="start-page">
<form action="{{ url_for('index') }}" method="POST">
<h1><input type="submit" value="open"> <input type="text" name="name"> <em class="octomode">in octomode</em></h1>
</form>
<div class="cols">
<h2>Publications</h2>
<p>Below a list of the publications on the server.</p>
<ul>
{% for pub in pubs %}
<a href="{{ url_for('pdf',name=pub)}}">{{pub}}</a>
{% endfor %}
</ul>
<iframe class="home_pad_iframe" src="{{ home_pad_url }}"></iframe>
</div>
</body>
</html>