diff --git a/app/lib/babycode.py b/app/lib/babycode.py
index 234ef82..4c7ea7e 100644
--- a/app/lib/babycode.py
+++ b/app/lib/babycode.py
@@ -218,10 +218,14 @@ def should_collapse(text, surrounding):
return False
-def babycode_to_html(s):
+def babycode_to_html(s, banned_tags=None):
+ allowed_tags = list(TAGS.keys())
+ if banned_tags is not None:
+ for tag in banned_tags:
+ allowed_tags.remove(tag)
subj = escape(s.strip().replace('\r\n', '\n').replace('\r', '\n'))
parser = Parser(subj)
- parser.valid_bbcode_tags = TAGS.keys()
+ parser.valid_bbcode_tags = allowed_tags
parser.bbcode_tags_only_text_children = TEXT_ONLY
parser.valid_emotes = EMOJI.keys()
diff --git a/app/models.py b/app/models.py
index 500b086..0b90639 100644
--- a/app/models.py
+++ b/app/models.py
@@ -394,3 +394,19 @@ class BookmarkedThreads(Model):
def get_thread(self):
return Threads.find({'id': self.thread_id})
+
+
+class MOTD(Model):
+ table = 'motd'
+
+ @classmethod
+ def has_motd(cls):
+ q = 'SELECT EXISTS(SELECT 1 FROM motd) as e'
+ res = db.fetch_one(q)['e']
+ return int(res) == 1
+
+ @classmethod
+ def get_all(cls):
+ q = 'SELECT id FROM motd'
+ res = db.query(q)
+ return [MOTD.find({'id': i['id']}) for i in res]
diff --git a/app/routes/api.py b/app/routes/api.py
index a59b769..3442906 100644
--- a/app/routes/api.py
+++ b/app/routes/api.py
@@ -40,7 +40,8 @@ def babycode_preview():
markup = request.json.get('markup')
if not markup or not isinstance(markup, str):
return {'error': 'markup field missing or invalid type'}, 400
- rendered = babycode_to_html(markup)
+ banned_tags = request.json.get('banned_tags', [])
+ rendered = babycode_to_html(markup, banned_tags)
return {'html': rendered}
diff --git a/app/routes/mod.py b/app/routes/mod.py
index cecf8fe..0971ce2 100644
--- a/app/routes/mod.py
+++ b/app/routes/mod.py
@@ -1,8 +1,11 @@
from flask import (
- Blueprint, render_template, request, redirect, url_for
+ Blueprint, render_template, request, redirect, url_for,
+ flash
)
from .users import get_active_user, is_logged_in
-from ..models import Users, PasswordResetLinks
+from ..models import Users, PasswordResetLinks, MOTD
+from ..constants import InfoboxKind
+from ..lib.babycode import babycode_to_html, BABYCODE_VERSION
from ..db import db
import secrets
import time
@@ -55,3 +58,47 @@ def create_reset_pass(user_id):
@bp.get('/panel')
def panel():
return render_template('mod/panel.html')
+
+
+@bp.get('/motd')
+def motd_editor():
+ current = MOTD.get_all()[0] if MOTD.has_motd() else None
+ return render_template('mod/motd.html', current=current)
+
+
+@bp.post('/motd')
+def motd_editor_form():
+ orig_body = request.form.get('body', default='')
+ title = request.form.get('title', default='')
+ data = {
+ 'title': title,
+ 'body_original_markup': orig_body,
+ 'body_rendered': babycode_to_html(orig_body, banned_tags=['img', 'spoiler']),
+ 'format_version': BABYCODE_VERSION,
+ 'edited_at': int(time.time()),
+ }
+
+ if MOTD.has_motd():
+ motd = MOTD.get_all()[0]
+ motd.update(data)
+ message = 'MOTD updated.'
+ else:
+ data['created_at'] = int(time.time())
+ data['user_id'] = get_active_user().id
+ motd = MOTD.create(data)
+ message = 'MOTD created.'
+
+ flash(message, InfoboxKind.INFO)
+ return redirect(url_for('.motd_editor'))
+
+
+@bp.post('/motd/delete')
+def motd_delete():
+ if not MOTD.has_motd():
+ flash('No MOTD to delete.', InfoboxKind.WARN)
+ return redirect(url_for('.motd_editor'))
+
+ current = MOTD.get_all()[0]
+ current.delete()
+ flash('MOTD deleted.', InfoboxKind.INFO)
+ return redirect(url_for('.motd_editor'))
diff --git a/app/schema.py b/app/schema.py
index 54ba328..6158477 100644
--- a/app/schema.py
+++ b/app/schema.py
@@ -120,6 +120,18 @@ SCHEMA = [
UNIQUE(collection_id, thread_id)
)""",
+ """CREATE TABLE IF NOT EXISTS "motd" (
+ "id" INTEGER NOT NULL PRIMARY KEY,
+ "title" TEXT NOT NULL,
+ "body_original_markup" TEXT NOT NULL,
+ "body_rendered" TEXT NOT NULL,
+ "markup_language" TEXT NOT NULL DEFAULT 'babycode',
+ "format_version" INTEGER DEFAULT NULL,
+ "created_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
+ "edited_at" INTEGER DEFAULT (unixepoch(CURRENT_TIMESTAMP)),
+ "user_id" REFERENCES users(id) ON DELETE CASCADE
+ )""",
+
# INDEXES
"CREATE INDEX IF NOT EXISTS idx_post_history_post_id ON post_history(post_id)",
"CREATE INDEX IF NOT EXISTS idx_posts_thread ON posts(thread_id, created_at, id)",
diff --git a/app/templates/common/icons.html b/app/templates/common/icons.html
index 6e88cf4..4582473 100644
--- a/app/templates/common/icons.html
+++ b/app/templates/common/icons.html
@@ -47,3 +47,9 @@
[{{ tag }}]The Message of the Day will show up on the main page and in every topic.
+ +