handle yaml errors
This commit is contained in:
parent
c661d09926
commit
01ae1d7e92
71
octomode.py
71
octomode.py
|
|
@ -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=""):
|
def get_pad_content(pad_name, ext=""):
|
||||||
if ext:
|
if ext:
|
||||||
pad_name = f'{ pad_name }{ ext }'
|
pad_name = f'{ pad_name }{ ext }'
|
||||||
|
|
@ -62,6 +69,22 @@ def all_pads():
|
||||||
|
|
||||||
return response
|
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):
|
def create_pad_on_first_run(name, ext):
|
||||||
pads = all_pads()
|
pads = all_pads()
|
||||||
pad = name+ext
|
pad = name+ext
|
||||||
|
|
@ -87,7 +110,21 @@ def create_pad_on_first_run(name, ext):
|
||||||
def md_to_html(md_pad_content):
|
def md_to_html(md_pad_content):
|
||||||
# Convert Markdown to HTML
|
# Convert Markdown to HTML
|
||||||
# html = markdown.markdown(md_pad_content, extensions=['meta', 'attr_list']) # attr_list does not work
|
# html = markdown.markdown(md_pad_content, extensions=['meta', 'attr_list']) # attr_list does not work
|
||||||
html = pypandoc.convert_text(md_pad_content, 'html', format='md')
|
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
|
# Sanitize the Markdown
|
||||||
# html = bleach.clean(html)
|
# html = bleach.clean(html)
|
||||||
|
|
@ -125,6 +162,17 @@ def get_app_root():
|
||||||
def get_meta(metadata, key, default=None):
|
def get_meta(metadata, key, default=None):
|
||||||
return metadata.get(key, [default])[0]
|
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'])
|
@APP.route('/', methods=['GET', 'POST'])
|
||||||
|
|
@ -140,7 +188,8 @@ def index():
|
||||||
create_pad_on_first_run(name, ext)
|
create_pad_on_first_run(name, ext)
|
||||||
return redirect(url_for("pad", name=name))
|
return redirect(url_for("pad", name=name))
|
||||||
else:
|
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>/')
|
@APP.route('/<name>/')
|
||||||
def main(name):
|
def main(name):
|
||||||
|
|
@ -190,7 +239,10 @@ def css(name):
|
||||||
def preview(name):
|
def preview(name):
|
||||||
# TO GENERATE THE PREVIEW WEBPAGE
|
# TO GENERATE THE PREVIEW WEBPAGE
|
||||||
md_pad_content = get_pad_content(name, ext='.md')
|
md_pad_content = get_pad_content(name, ext='.md')
|
||||||
html = md_to_html(md_pad_content)
|
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)
|
metadata = get_md_metadata(md_pad_content)
|
||||||
lang = get_meta(metadata, 'language', 'en')
|
lang = get_meta(metadata, 'language', 'en')
|
||||||
title = get_meta(metadata, 'title', 'Untitled')
|
title = get_meta(metadata, 'title', 'Untitled')
|
||||||
|
|
@ -201,21 +253,26 @@ def preview(name):
|
||||||
def pagedjs(name):
|
def pagedjs(name):
|
||||||
# TO GENERATE THE PAGED.JS WEBPAGE
|
# TO GENERATE THE PAGED.JS WEBPAGE
|
||||||
md_pad_content = get_pad_content(name, ext='.md')
|
md_pad_content = get_pad_content(name, ext='.md')
|
||||||
html = md_to_html(md_pad_content)
|
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)
|
metadata = get_md_metadata(md_pad_content)
|
||||||
lang = get_meta(metadata, 'language', 'en')
|
lang = get_meta(metadata, 'language', 'en')
|
||||||
title = get_meta(metadata, 'title', 'Untitled')
|
title = get_meta(metadata, 'title', 'Untitled')
|
||||||
cover = get_meta(metadata, 'cover', None)
|
cover = get_meta(metadata, 'cover', None)
|
||||||
|
|
||||||
impose = False #request.args.get("impose") == "true"
|
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)
|
return render_template('pagedjs.html', name=name.strip(), pad_content=html, lang=lang, title=title, cover=cover, impose=impose)
|
||||||
|
|
||||||
@APP.route('/<name>/imposed.html')
|
@APP.route('/<name>/imposed.html')
|
||||||
def imposed(name):
|
def imposed(name):
|
||||||
# TO GENERATE THE IMPOSED WEBPAGE
|
# TO GENERATE THE IMPOSED WEBPAGE
|
||||||
md_pad_content = get_pad_content(name, ext='.md')
|
md_pad_content = get_pad_content(name, ext='.md')
|
||||||
html = md_to_html(md_pad_content)
|
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)
|
metadata = get_md_metadata(md_pad_content)
|
||||||
lang = get_meta(metadata, 'language', 'en')
|
lang = get_meta(metadata, 'language', 'en')
|
||||||
title = get_meta(metadata, 'title', 'Untitled')
|
title = get_meta(metadata, 'title', 'Untitled')
|
||||||
|
|
@ -230,4 +287,6 @@ def imposed(name):
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
APP.debug = True
|
APP.debug = True
|
||||||
APP.env = "development"
|
APP.env = "development"
|
||||||
|
# APP.debug = False
|
||||||
|
# APP.env = "production"
|
||||||
APP.run(host="0.0.0.0", port=APP.config["PORTNUMBER"], threaded=True)
|
APP.run(host="0.0.0.0", port=APP.config["PORTNUMBER"], threaded=True)
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,8 @@ from filter_registry import register_filter
|
||||||
@register_filter
|
@register_filter
|
||||||
def remove_star_before_img(text):
|
def remove_star_before_img(text):
|
||||||
# regex version
|
# regex version
|
||||||
return re.sub(r'\*\s*!?\[\]\(', '
|
# return re.sub(r'\*\s*!?\[\]\(', '
|
||||||
|
return re.sub(r'\*\s*!?\[\.*]\(', '
|
||||||
|
|
||||||
# @register_filter
|
# @register_filter
|
||||||
# def remove_star_before_img(text):
|
# def remove_star_before_img(text):
|
||||||
|
|
|
||||||
10
settings.py
10
settings.py
|
|
@ -1,16 +1,18 @@
|
||||||
import os
|
import os
|
||||||
|
from pathlib import Path
|
||||||
from dotenv import load_dotenv
|
from dotenv import load_dotenv
|
||||||
|
|
||||||
# Load environment variables from the .env file
|
# Load environment variables from the .env file alongside this module.
|
||||||
load_dotenv()
|
ENV_PATH = Path(__file__).resolve().parent / ".env"
|
||||||
|
load_dotenv(dotenv_path=ENV_PATH)
|
||||||
|
|
||||||
# Bind them to Python variables
|
# Bind them to Python variables
|
||||||
APPLICATION_ROOT = os.environ.get('OCTOMODE_APPLICATION_ROOT', '/')
|
APPLICATION_ROOT = os.environ.get('OCTOMODE_APPLICATION_ROOT', '/')
|
||||||
PORTNUMBER = int(os.environ.get('OCTOMODE_PORTNUMBER', 5001))
|
PORTNUMBER = int(os.environ.get('OCTOMODE_PORTNUMBER', 5001))
|
||||||
PAD_URL = os.environ.get('OCTOMODE_PAD_URL', 'https://pad.vvvvvvaria.org')
|
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_URL = os.environ.get('OCTOMODE_PAD_API_URL', 'https://pad.vvvvvvaria.org/api/1.2.15')
|
||||||
PAD_API_KEY = "97e3bf6a626eaaa3426833db3d936f3a"
|
HOME_PAD_URL = os.environ.get('OCTOMODE_HOME_PAD_URL', '')
|
||||||
#os.environ.get('OCTOMODE_PAD_API_KEY', '')
|
PAD_API_KEY = os.environ.get('OCTOMODE_PAD_API_KEY', '')
|
||||||
|
|
||||||
# Check if API key is provided
|
# Check if API key is provided
|
||||||
if not PAD_API_KEY or PAD_API_KEY == "XXX":
|
if not PAD_API_KEY or PAD_API_KEY == "XXX":
|
||||||
|
|
|
||||||
|
|
@ -100,10 +100,16 @@ div#nav{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.cols {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 3fr;
|
||||||
|
margin-top: 3rem;
|
||||||
|
}
|
||||||
|
|
||||||
.home_pad_iframe {
|
.home_pad_iframe {
|
||||||
height: 75vh;
|
height: 75vh;
|
||||||
margin: 5rem;
|
/* margin: 5rem; */
|
||||||
width: calc(100vw - 13rem);
|
/* width: calc(100vw - 13rem); */
|
||||||
border: 1px solid black;
|
border: 1px solid black;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
35
templates/error.html
Normal file
35
templates/error.html
Normal 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>
|
||||||
|
|
@ -5,11 +5,23 @@
|
||||||
<title>octomode</title>
|
<title>octomode</title>
|
||||||
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
|
<link rel="stylesheet" type="text/css" href="{{ url_for('static', filename='main.css') }}">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body class="start-page">
|
<body class="start-page">
|
||||||
<form action="{{ url_for('index') }}" method="POST">
|
<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>
|
<h1><input type="submit" value="open"> <input type="text" name="name"> <em class="octomode">in octomode</em></h1>
|
||||||
</form>
|
</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>
|
<iframe class="home_pad_iframe" src="{{ home_pad_url }}"></iframe>
|
||||||
|
</div>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue