初始化
This commit is contained in:
75
backend/routes/share.py
Normal file
75
backend/routes/share.py
Normal file
@@ -0,0 +1,75 @@
|
||||
"""分享笔记公开查看"""
|
||||
from datetime import datetime
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from fastapi.responses import HTMLResponse
|
||||
from sqlalchemy.orm import Session
|
||||
from models import get_db, Note
|
||||
|
||||
router = APIRouter(tags=["分享"])
|
||||
|
||||
CSS = """
|
||||
:root{--text:#1F2329;--text2:#646A73;--text3:#8F959E;--border:#E5E6EB;--brand:#3370FF;--bg:#F5F6F8;}
|
||||
*{margin:0;padding:0;box-sizing:border-box;}
|
||||
body{font-family:-apple-system,BlinkMacSystemFont,"PingFang SC","Microsoft YaHei",sans-serif;color:var(--text);background:var(--bg);min-height:100vh;}
|
||||
.wrap{max-width:1100px;margin:0 auto;padding:32px 16px;}
|
||||
.card{background:#fff;border-radius:12px;padding:36px;box-shadow:0 1px 3px rgba(0,0,0,.06);overflow-x:auto;word-wrap:break-word;overflow-wrap:break-word;max-width:100%;}
|
||||
h1{font-size:26px;font-weight:700;padding-bottom:16px;margin-bottom:16px;border-bottom:2px solid var(--border);line-height:1.3;}
|
||||
.meta{font-size:12px;color:var(--text3);margin-bottom:28px;display:flex;gap:20px;}
|
||||
.content{font-size:15px;line-height:1.9;color:var(--text);overflow-x:auto;word-wrap:break-word;overflow-wrap:break-word;}
|
||||
.content h2{font-size:20px;font-weight:600;margin:24px 0 10px;}
|
||||
.content h3{font-size:17px;font-weight:600;margin:18px 0 8px;}
|
||||
.content p{margin:8px 0;}
|
||||
.content ul,.content ol{padding-left:22px;margin:8px 0;}
|
||||
.content li{margin:4px 0;}
|
||||
.content blockquote{border-left:3px solid var(--brand);padding:4px 14px;margin:12px 0;color:var(--text2);}
|
||||
.content pre{background:#F7F8FA;padding:14px 18px;border-radius:8px;overflow-x:auto;font-size:13px;line-height:1.7;font-family:"SF Mono","Fira Code","Consolas",monospace;}
|
||||
.content code{background:#F2F3F5;padding:2px 6px;border-radius:3px;font-size:13px;font-family:"SF Mono","Fira Code","Consolas",monospace;}
|
||||
.content pre code{background:none;padding:0;}
|
||||
.content table{border-collapse:collapse;width:100%;margin:12px 0;}
|
||||
.content th,.content td{border:1px solid var(--border);padding:8px 14px;text-align:left;}
|
||||
.content th{background:#F7F8FA;font-weight:600;font-size:13px;}
|
||||
.content img{max-width:100%;border-radius:8px;}
|
||||
.content mark{background:#FFF3CD;padding:2px 4px;border-radius:2px;}
|
||||
.footer{text-align:center;margin-top:24px;font-size:11px;color:var(--text3);}
|
||||
.footer a{color:var(--brand);text-decoration:none;}
|
||||
"""
|
||||
|
||||
TEMPLATE = """<!DOCTYPE html>
|
||||
<html lang="zh-CN">
|
||||
<head>
|
||||
<meta charset="UTF-8"><meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||
<title>{title} - MoKeeText</title>
|
||||
<style>{css}</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="wrap">
|
||||
<div class="card">
|
||||
<h1>{title}</h1>
|
||||
<div class="meta">
|
||||
<span>创建于 {created_at}</span>
|
||||
<span>{created_by}</span>
|
||||
</div>
|
||||
<div class="content">{content}</div>
|
||||
</div>
|
||||
<div class="footer">Powered by <a href="/">MoKeeText</a></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>"""
|
||||
|
||||
|
||||
@router.get("/share/{token}")
|
||||
def view_shared(token: str, db: Session = Depends(get_db)):
|
||||
note = db.query(Note).filter_by(share_token=token).first()
|
||||
if not note:
|
||||
raise HTTPException(404, "链接无效或已取消分享")
|
||||
if note.share_expires_at and note.share_expires_at < datetime.utcnow():
|
||||
raise HTTPException(410, "分享链接已过期")
|
||||
|
||||
html = TEMPLATE.format(
|
||||
title=note.title,
|
||||
created_at=note.created_at.strftime('%Y-%m-%d %H:%M:%S') if note.created_at else '-',
|
||||
created_by=note.created_by or 'admin',
|
||||
content=note.content or '<p style="color:var(--text3);">暂无内容</p>',
|
||||
css=CSS,
|
||||
)
|
||||
return HTMLResponse(html)
|
||||
Reference in New Issue
Block a user