Files
2026-06-16 03:30:57 +08:00

288 lines
8.5 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
from flask import Flask, request, jsonify, render_template, session, redirect, url_for
from flask_cors import CORS
import json
import os
from datetime import datetime
import hashlib
from config import *
app = Flask(__name__)
CORS(app) # 允许跨域请求
app.secret_key = SECRET_KEY
# 数据文件路径已在 config.py 中定义
# DATA_FILE = os.path.join(os.path.dirname(__file__), 'data', 'comments.json')
def read_comments():
"""读取评论数据"""
try:
if os.path.exists(DATA_FILE):
with open(DATA_FILE, 'r', encoding='utf-8') as f:
return json.load(f)
return {"comments": []}
except Exception as e:
print(f"读取数据失败: {e}")
return {"comments": []}
def save_comments(data):
"""保存评论数据"""
os.makedirs(os.path.dirname(DATA_FILE), exist_ok=True)
with open(DATA_FILE, 'w', encoding='utf-8') as f:
json.dump(data, f, ensure_ascii=False, indent=2)
def parse_user_agent(ua):
"""解析 User Agent 获取浏览器和系统信息"""
browser = 'Unknown'
os_name = 'Unknown'
# 浏览器检测
if 'Chrome' in ua and 'Edge' not in ua:
browser = 'Chrome'
elif 'Firefox' in ua:
browser = 'Firefox'
elif 'Safari' in ua and 'Chrome' not in ua:
browser = 'Safari'
elif 'Edge' in ua:
browser = 'Edge'
# 系统检测
if 'Windows' in ua:
os_name = 'Windows'
elif 'Mac' in ua:
os_name = 'macOS'
elif 'Linux' in ua:
os_name = 'Linux'
elif 'Android' in ua:
os_name = 'Android'
elif 'iPhone' in ua or 'iPad' in ua:
os_name = 'iOS'
return browser, os_name
@app.route('/api/comment', methods=['GET'])
def get_comments():
"""获取评论列表(前端展示用,仅返回已审核)"""
try:
page = int(request.args.get('page', 1))
page_size = int(request.args.get('pageSize', PAGE_SIZE_FRONTEND))
data = read_comments()
# 过滤已审核的评论
filtered = [c for c in data['comments']
if c.get('status') == 'approved']
# 按时间倒序排序
filtered.sort(key=lambda x: x.get('time', 0), reverse=True)
total_count = len(filtered)
total_pages = (total_count + page_size - 1) // page_size
# 分页
start = (page - 1) * page_size
end = start + page_size
paged_comments = filtered[start:end]
return jsonify({
'errno': 0,
'errmsg': '',
'data': {
'page': page,
'totalPages': total_pages,
'pageSize': page_size,
'count': total_count,
'data': paged_comments
}
})
except Exception as e:
return jsonify({
'errno': 1,
'errmsg': str(e)
}), 500
# 管理员账号配置已在 config.py 中定义
# ADMIN_USERNAME = 'admin'
# ADMIN_PASSWORD = 'zhaoyang0902'
def login_required(f):
"""登录验证装饰器"""
from functools import wraps
@wraps(f)
def decorated_function(*args, **kwargs):
if not session.get('logged_in'):
return redirect(url_for('login_page'))
return f(*args, **kwargs)
return decorated_function
@app.route('/login')
def login_page():
"""登录页面"""
return render_template('login.html')
@app.route('/api/login', methods=['POST'])
def do_login():
"""处理登录请求"""
data = request.get_json()
username = data.get('username')
password = data.get('password')
if username == ADMIN_USERNAME and password == ADMIN_PASSWORD:
session['logged_in'] = True
return jsonify({'errno': 0, 'errmsg': '登录成功'})
else:
return jsonify({'errno': 1, 'errmsg': '用户名或密码错误'}), 401
@app.route('/logout')
def logout():
"""退出登录"""
session.pop('logged_in', None)
return redirect(url_for('login_page'))
@app.route('/admin')
@login_required
def admin_page():
"""后台管理页面"""
return render_template('admin.html')
@app.route('/api/admin/comments', methods=['GET'])
@login_required
def get_admin_comments():
"""获取所有评论(后台管理用)"""
try:
status_filter = request.args.get('status', '')
keyword = request.args.get('keyword', '').lower()
page = int(request.args.get('page', 1))
page_size = int(request.args.get('pageSize', PAGE_SIZE_ADMIN))
data = read_comments()
comments = data['comments']
# 状态过滤
if status_filter:
comments = [c for c in comments if c.get('status') == status_filter]
else:
# 全部状态下默认不显示已删除的评论
comments = [c for c in comments if c.get('status') != 'deleted']
# 关键词搜索(昵称或内容)
if keyword:
comments = [c for c in comments if
keyword in c.get('nick', '').lower() or
keyword in c.get('comment', '').lower()]
# 按时间倒序排序
comments.sort(key=lambda x: x.get('time', 0), reverse=True)
total_count = len(comments)
total_pages = (total_count + page_size - 1) // page_size if total_count > 0 else 0
# 分页
start = (page - 1) * page_size
end = start + page_size
paged_comments = comments[start:end]
return jsonify({
'errno': 0,
'data': {
'list': paged_comments,
'total': total_count,
'page': page,
'pageSize': page_size,
'totalPages': total_pages
}
})
except Exception as e:
return jsonify({
'errno': 1,
'errmsg': str(e)
}), 500
@app.route('/api/admin/comment/<int:comment_id>', methods=['PUT'])
@login_required
def update_comment_status(comment_id):
"""更新评论状态"""
try:
update_data = request.get_json()
new_status = update_data.get('status')
if new_status not in ['approved', 'spam', 'deleted']:
return jsonify({'errno': 1, 'errmsg': '无效的状态'}), 400
data = read_comments()
found = False
for c in data['comments']:
if c['id'] == comment_id:
c['status'] = new_status
found = True
break
if not found:
return jsonify({'errno': 1, 'errmsg': '评论不存在'}), 404
save_comments(data)
return jsonify({'errno': 0, 'errmsg': '更新成功'})
except Exception as e:
return jsonify({
'errno': 1,
'errmsg': str(e)
}), 500
@app.route('/api/comment', methods=['POST'])
def add_comment():
"""添加评论"""
try:
comment_data = request.get_json()
if not comment_data:
return jsonify({
'errno': 1,
'errmsg': '无效的数据'
}), 400
data = read_comments()
# 生成新 ID
new_id = max([c.get('id', 0) for c in data['comments']], default=0) + 1
# 解析 User Agent
ua = comment_data.get('ua', '')
browser, os_name = parse_user_agent(ua)
# 生成头像(基于邮箱 MD5
email = comment_data.get('mail', '')
avatar_hash = hashlib.md5(email.encode('utf-8')).hexdigest()
avatar = f'https://seccdn.libravatar.org/avatar/{avatar_hash}'
# 创建新评论
new_comment = {
'id': new_id,
'nick': comment_data.get('nick', '匿名'),
'mail': comment_data.get('mail', ''),
'link': comment_data.get('link', ''),
'comment': f"<p>{comment_data.get('comment', '')}</p>\n",
'ua': ua,
'browser': browser,
'os': os_name,
'avatar': avatar,
'time': int(datetime.now().timestamp() * 1000),
'status': 'approved' # 直接审核通过
}
# 添加到数据中
data['comments'].append(new_comment)
save_comments(data)
return jsonify({
'errno': 0,
'errmsg': '',
'data': new_comment
})
except Exception as e:
return jsonify({
'errno': 1,
'errmsg': str(e)
}), 500
if __name__ == '__main__':
app.run(host=HOST, port=PORT, debug=DEBUG)