From 71cbd9e54bc3a8148c75eac770577d21736013ee Mon Sep 17 00:00:00 2001 From: mst Date: Mon, 16 Dec 2024 16:49:42 +0300 Subject: [PATCH] improve markdown rendering, add error handlers, simplify index route logic --- app.py | 71 +++++++++++++++++++++++++++------------------------- functions.py | 63 +++++++++++++++++++++++++++------------------- 2 files changed, 74 insertions(+), 60 deletions(-) diff --git a/app.py b/app.py index 6b161cc..f18b3fe 100644 --- a/app.py +++ b/app.py @@ -110,47 +110,50 @@ def inject_stuff(): return dict(metadata=func.generateMetadata(), len=len, str=str, const=const, cfg=cfg, logged_in=logged_in, version_id=const.version_id, version=const.version, appName=const.appName, questionCount=questionCount) # -- template filters -- + +# {text} | render_markdown @app.template_filter('render_markdown') def render_markdown(text): - # app.logger.debug("[CatAsk] app.template_filter render_markdown(text) triggered") - return func.renderMarkdown(text) + if text.startswith("![") and not (text.startswith(':') and text.endswith(':')): + return text + else: + # app.logger.debug("[CatAsk] app.template_filter render_markdown(text) triggered") + return func.renderMarkdown(text) + +# render_markdown({text}, fromWho=False|True) +@app.template_global('render_markdown') +def render_markdown(text, fromWho=False): + if (text.startswith("![") or "![" in text) and not (text.startswith(':') and text.endswith(':')): + # ensuring that only inline images get escaped, not emojis + escaped = text.replace("![", "!\[") + return func.renderMarkdown(escaped) + else: + # don't want people inserting buttons and other stuff into name field + allowed_tags = ["p", "img"] if fromWho else None + return func.renderMarkdown(text, allowed_tags) + +# -- error handlers -- + +@app.errorhandler(404) +def notFound(e): + return render_template('errors/404.html'), 404 + +@app.errorhandler(500) +def internalServerError(e): + return render_template('errors/500.html'), 500 + +@app.errorhandler(502) +def badGateway(e): + return render_template('errors/502.html'), 502 # -- client (frontend) routes -- @app.route('/', methods=['GET']) def index(): - conn = func.connectToDb() - cursor = conn.cursor(dictionary=True) - - app.logger.debug("[CatAsk/Home] SELECT'ing pinned questions") - - cursor.execute("SELECT * FROM questions WHERE answered=%s AND pinned=%s ORDER BY creation_date DESC", (True, True)) - pinned_questions = cursor.fetchall() - - app.logger.debug("[CatAsk/Home] SELECT'ing non-pinned questions") - - cursor.execute("SELECT * FROM questions WHERE answered=%s AND pinned=%s ORDER BY creation_date DESC", (True, False)) - non_pinned_questions = cursor.fetchall() - - questions = pinned_questions + non_pinned_questions - - app.logger.debug("[CatAsk/Home] SELECT'ing answers") - - cursor.execute("SELECT * FROM answers ORDER BY creation_date DESC") - answers = cursor.fetchall() - - metadata = func.generateMetadata() - - combined = [] - for question in questions: - question_answers = [answer for answer in answers if answer['question_id'] == question['id']] - combined.append({ - 'question': question, - 'answers': question_answers - }) - - cursor.close() - conn.close() + # func.getAllQuestions() returns combined and metadata + func_val = func.getAllQuestions() + combined = func_val[0] + metadata = func_val[1] return render_template('index.html', combined=combined, urllib=urllib, trimContent=func.trimContent, metadata=metadata, getRandomWord=func.getRandomWord, formatRelativeTime=func.formatRelativeTime) diff --git a/functions.py b/functions.py index 6844a94..cabc3fc 100644 --- a/functions.py +++ b/functions.py @@ -506,33 +506,44 @@ def processEmojis(meta_json_path): return processed_emojis -def renderMarkdown(text): +def renderMarkdown(text, allowed_tags=None): plugins = [ 'strikethrough', button, emoji ] - allowed_tags = [ - 'p', - 'em', - 'b', - 'strong', - 'i', - 'br', - 's', - 'del', - 'a', - 'button', - 'ol', - 'li', - 'hr', - 'img' - ] - # allowed_attrs = { - # 'a': 'href', - # 'button': 'class', - # # 'img': ['src', 'width', 'height', 'alt', 'class', 'loading', 'title'] - # } + if not allowed_tags: + allowed_tags = [ + 'p', + 'em', + 'b', + 'strong', + 'i', + 'br', + 's', + 'del', + 'a', + 'button', + 'ol', + 'li', + 'hr', + 'img', + 'code', + 'pre' + ] + allowed_attrs = { + 'a': 'href', + 'button': 'class', + 'img': { + 'class': lambda value: value == "emoji", + 'src': True, # Allow specific attributes on emoji images + 'alt': True, + 'title': True, + 'width': True, + 'height': True, + 'loading': True + } + } # hard_wrap=True means that newlines will be # converted into
tags # @@ -545,10 +556,10 @@ def renderMarkdown(text): plugins=plugins, hard_wrap=True ) - cleaner = Cleaner(tags=allowed_tags) - clean_text = cleaner.clean(text) - html = md(clean_text) - return Markup(html) + html = md(text) + cleaner = Cleaner(tags=allowed_tags, attributes=allowed_attrs) + clean_html = cleaner.clean(html) + return Markup(clean_html) def generateMetadata(question=None, answer=None): metadata = {