add motd editor and motd display

This commit is contained in:
2026-05-27 02:02:55 +03:00
parent e74b9403e9
commit 303750a281
8 changed files with 96 additions and 12 deletions

View File

@@ -1,7 +1,8 @@
from flask import Blueprint, abort, redirect, url_for, request, render_template, flash
from ..constants import InfoboxKind, PermissionLevel
from ..constants import InfoboxKind, PermissionLevel, MOTD_BANNED_TAGS
from ..auth import is_logged_in, get_active_user, csrf_verified
from ..models import Topics, Threads, Users
from ..models import Topics, Threads, Users, MOTD
from ..lib.babycode import babycode_to_html, BABYCODE_VERSION
from slugify import slugify
from functools import wraps
import time
@@ -24,7 +25,49 @@ def admin_only(view_func):
@bp.get('/')
def index():
return 'stub'
motd = MOTD.get_all()[0] if MOTD.has_motd() else None
return render_template('mod/panel.html', MOTD_BANNED_TAGS=MOTD_BANNED_TAGS, motd=motd)
@bp.post('/motd/set/')
def set_motd():
title = request.form.get('motd_title', '')
if not title:
flash('MOTD must have a title.', InfoboxKind.ERROR)
return redirect(url_for('.index'))
orig_body = request.form.get('babycode_content', '')
if not orig_body:
flash('MOTD must have a body.', InfoboxKind.ERROR)
return redirect(url_for('.index'))
user = get_active_user()
data = {
'title': title.strip(),
'body_original_markup': orig_body,
'body_rendered': babycode_to_html(orig_body, banned_tags=MOTD_BANNED_TAGS).result,
'format_version': BABYCODE_VERSION,
'edited_at': int(time.time()),
'user_id': user.id,
}
if MOTD.has_motd():
motd = MOTD.get_all()[0]
motd.update(data)
message = 'MOTD updated.'
else:
data['created_at'] = int(time.time())
motd = MOTD.create(data)
message = 'MOTD created.'
flash(message, InfoboxKind.INFO)
return redirect(url_for('.index'))
@bp.post('/motd/clear/')
def clear_motd():
if not MOTD.has_motd():
return redirect(url_for('.index'))
current = MOTD.get_all()[0]
current.delete()
flash('MOTD cleared.', InfoboxKind.INFO)
return redirect(url_for('.index'))
@bp.get('/topics/new/')
def new_topic():
@@ -35,10 +78,6 @@ def new_topic_post():
topic = Topics.new(request.form.get('name'), request.form.get('description'))
return redirect(url_for('topics.topic_by_id', topic_id=topic.id))
@bp.get('/topics/sort/')
def sort_topics():
return 'stub'
@bp.get('/topics/<int:topic_id>/edit/')
def edit_topic(topic_id):
topic = Topics.find({'id': topic_id})

View File

@@ -10,6 +10,10 @@
<img src="/static/icons/error.svg" alt="error" style="width: {{width}}px;">
{%- endmacro -%}
{%- macro icn_megaphone(width=48) -%}
<img src="/static/icons/megaphone.svg" alt="megaphone" style="width: {{width}}px;">
{%- endmacro -%}
{%- macro icn_bookmark(width=16) -%}
<img src="/static/icons/bookmark.svg" alt="bookmark" style="width: {{width}}px;">
{%- endmacro -%}

View File

@@ -1,4 +1,4 @@
{%- from 'common/icons.html' import icn_info, icn_warn, icn_error, icn_bookmark -%}
{%- from 'common/icons.html' import icn_info, icn_warn, icn_error, icn_bookmark, icn_megaphone -%}
{% macro timestamp(unix_ts) -%}
<time datetime="{{ unix_ts | iso8601 }}">{{ unix_ts | ts_datetime('%Y-%m-%d %H:%M')}} <abbr title="Server Time">ST</abbr></time>
@@ -238,3 +238,18 @@
{%- endif -%}
</div>
{%- endmacro %}
{% macro motd(motd_objs) -%}
{%- if motd_objs -%}
<div class="motd plank contrast-bg">
<div class="contain-svg">
{{ icn_megaphone(64) }}
<i><abbr title="Message of the Day">MOTD</abbr></i>
</div>
<div class="motd-content mobile-fill-flex">
<h2 class="info">{{ motd_objs[0].title }}</h2>
<div class="motd-body">{{ motd_objs[0].body_rendered | safe }}</div>
</div>
</div>
{%- endif -%}
{%- endmacro %}

View File

@@ -0,0 +1,23 @@
{%- from 'common/macros.html' import subheader, babycode_editor_component -%}
{%- extends 'base.html' -%}
{%- block title -%}settings{%- endblock -%}
{%- block content -%}
{{- subheader('Moderation panel') -}}
<fieldset class="plank">
<legend>Message of the Day</legend>
<p>The Message of the Day is shown on the front page and on each topic's thread list.</p>
<form class="full-width" method="POST" action="{{url_for('mod.set_motd')}}" id="motd-form">
<label for="motd-title">Title</label>
<input type="text" id="motd-title" name="motd_title" autocomplete="off" value="{{motd.title}}" required>
<label for="motd-content">Body</label>
{{ babycode_editor_component(placeholder='MOTD content', prefill=motd.body_original_markup, id='motd-content', banned_tags=MOTD_BANNED_TAGS) }}
</form>
<input type="submit" value="Save MOTD" form="motd-form">
<form method="POST" action="{{url_for('mod.clear_motd')}}">
<input type="submit" value="Clear MOTD" class="warn">
</form>
</fieldset>
<fieldset class="plank" id="sort-topics">
<legend>Sort topics</legend>
</fieldset>
{%- endblock -%}

View File

@@ -1,4 +1,4 @@
{% from 'common/macros.html' import timestamp, subheader, pager %}
{% from 'common/macros.html' import timestamp, subheader, pager, motd %}
{% from 'common/icons.html' import icn_locked, icn_stickied %}
{%- extends 'base.html' -%}
{%- block title -%}browsing topic {{topic.name}}{%- endblock -%}
@@ -46,6 +46,7 @@
{%- if threads | length == 0 -%}
<div class="plank"><p>There are no threads in this topic yet.{%- if is_logged_in() and get_active_user().can_post_to_thread_or_topic(topic) %} Be the first to start a discussion!{%- endif -%}</p></div>
{%- endif -%}
{{ motd(get_motds()) }}
{%- for thread in threads -%}
<div class="topic-info plank">
<div class="title-container">

View File

@@ -1,4 +1,4 @@
{% from 'common/macros.html' import timestamp, subheader %}
{% from 'common/macros.html' import timestamp, subheader, motd %}
{% from 'common/icons.html' import icn_locked %}
{%- extends 'base.html' -%}
{%- block content -%}
@@ -7,10 +7,11 @@
<fieldset class="plank even no-shadow minimal thread-actions">
<legend>Moderation actions</legend>
<a href="{{url_for('mod.new_topic')}}" class="linkbutton">New topic</a>
<a href="{{url_for('mod.sort_topics')}}" class="linkbutton">Sort topics</a>
<a href="{{url_for('mod.index', _anchor='sort-topics')}}" class="linkbutton">Sort topics</a>
</fieldset>
{%- endif -%}
{%- endcall -%}
{{ motd(get_motds()) }}
{%- for topic in topics -%}
<div class="topic-info plank">
<div class="title-container">