plugins/navManager:导航 CRUD + 导航分类 CRUD(独立 blueprint) plugins/friendManager:友情链接 CRUD plugins/aboutManager:关于本站 CRUD plugins/siteStats:访问统计主页 + JSON 接口 + /site/* GET 埋点 + nav 卡片点击埋点 applications/view/public/nav.py:导航聚合页 / 分类详情 / JSON 接口,支持 visit_count 注入 applications/view/public/about.py:关于本站公开页 applications/view/public/friend.py:友情链接公开页 templates/public/base.html:响应式首页(搜索框 / 分类抽屉 / 5 主题切换 / footer 隐私小字) templates/public/index.html / category.html:卡片右下角访问次数 templates/public/about.html / friend.html:关于 + 友链前台页 docs/plugins-development.md:插件开发完整指南(生命周期 + 4 个示例 + FAQ + framework 迁移) scripts/:探针与端到端验证脚本(probe_*/verify_*/test_*)
50 lines
1.4 KiB
Python
50 lines
1.4 KiB
Python
"""
|
|
前台公开"关于本站"页面。
|
|
|
|
不需要登录,匿名可访问。Markdown 在模板里渲染。
|
|
"""
|
|
import re
|
|
|
|
import markdown as _markdown
|
|
from flask import Blueprint, render_template
|
|
|
|
from applications.models import About
|
|
|
|
bp = Blueprint('public_about', __name__, url_prefix='/site')
|
|
|
|
|
|
def _get_about() -> About:
|
|
"""复用 model 的种子逻辑,避免空表时炸"""
|
|
a = About.query.get(1)
|
|
if a is None:
|
|
from applications.extensions import db
|
|
a = About(id=1, site_name='旺珂 · 导航')
|
|
db.session.add(a)
|
|
db.session.commit()
|
|
return a
|
|
|
|
|
|
@bp.get('/about')
|
|
def about():
|
|
a = _get_about()
|
|
html = _render_md(a.content_md)
|
|
return render_template('public/about.html', about=a, content_html=html)
|
|
|
|
|
|
_URL_RE = re.compile(r'(https?://[^\s)<>"\\]+|[\w.+-]+@[\w-]+\.[\w.-]+)')
|
|
|
|
|
|
def _render_md(text: str) -> str:
|
|
"""Markdown → HTML;自动把裸链接/邮箱变可点;同时禁掉 script/iframe。"""
|
|
if not text or not text.strip():
|
|
return ''
|
|
html = _markdown.markdown(
|
|
text,
|
|
extensions=['fenced_code', 'tables', 'nl2br', 'sane_lists'],
|
|
output_format='html5',
|
|
)
|
|
# 防御:清掉 <script>/<iframe>
|
|
html = re.sub(r'<\s*script[^>]*>.*?<\s*/\s*script\s*>', '', html, flags=re.I | re.S)
|
|
html = re.sub(r'<\s*iframe[^>]*>.*?<\s*/\s*iframe\s*>', '', html, flags=re.I | re.S)
|
|
return html
|