init: TEALab 2025 实验室网站项目
从百度网盘 /apps/bypy/dofile/ 下载的完整项目结构,包含: - dofile/: Flask 后端(端口 5000)+ 静态前端(端口 6002) - officefile/: 项目相关文档 - .gitignore: Python venv / 日志 / 缓存 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,227 @@
|
||||
from flask import Blueprint, request, jsonify, send_file, current_app
|
||||
from flask_login import login_required, current_user
|
||||
from werkzeug.utils import secure_filename
|
||||
import sys
|
||||
import os
|
||||
|
||||
# 添加父目录到路径
|
||||
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
|
||||
from models import db, Article, Resource, TeamMember
|
||||
from datetime import datetime
|
||||
|
||||
bp = Blueprint('cms', __name__)
|
||||
|
||||
def allowed_file(filename, allowed_extensions):
|
||||
"""检查文件扩展名是否允许"""
|
||||
return '.' in filename and filename.rsplit('.', 1)[1].lower() in allowed_extensions
|
||||
|
||||
# 文章管理
|
||||
@bp.route('/articles', methods=['GET'])
|
||||
def get_articles():
|
||||
"""获取文章列表"""
|
||||
category = request.args.get('category', 'news')
|
||||
published_only = request.args.get('published_only', 'true').lower() == 'true'
|
||||
|
||||
query = Article.query.filter_by(category=category)
|
||||
|
||||
if published_only:
|
||||
query = query.filter_by(published=True)
|
||||
|
||||
# 如果未登录,过滤受保护内容
|
||||
if not current_user.is_authenticated:
|
||||
query = query.filter_by(is_protected=False)
|
||||
|
||||
articles = query.order_by(Article.created_at.desc()).all()
|
||||
|
||||
return jsonify({
|
||||
'articles': [article.to_dict() for article in articles]
|
||||
}), 200
|
||||
|
||||
@bp.route('/articles/<int:article_id>', methods=['GET'])
|
||||
def get_article(article_id):
|
||||
"""获取单篇文章"""
|
||||
article = Article.query.get_or_404(article_id)
|
||||
|
||||
# 检查是否需要登录
|
||||
if article.is_protected and not current_user.is_authenticated:
|
||||
return jsonify({'error': 'Authentication required'}), 401
|
||||
|
||||
if not article.published:
|
||||
if not current_user.is_authenticated or not current_user.is_admin:
|
||||
return jsonify({'error': 'Article not found'}), 404
|
||||
|
||||
return jsonify({'article': article.to_dict()}), 200
|
||||
|
||||
@bp.route('/articles', methods=['POST'])
|
||||
@login_required
|
||||
def create_article():
|
||||
"""创建文章(需要管理员权限)"""
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
data = request.get_json()
|
||||
|
||||
article = Article(
|
||||
title=data.get('title'),
|
||||
content=data.get('content'),
|
||||
summary=data.get('summary'),
|
||||
category=data.get('category', 'news'),
|
||||
is_protected=data.get('is_protected', False),
|
||||
author_id=current_user.id,
|
||||
published=data.get('published', True)
|
||||
)
|
||||
|
||||
db.session.add(article)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Article created successfully',
|
||||
'article': article.to_dict()
|
||||
}), 201
|
||||
|
||||
@bp.route('/articles/<int:article_id>', methods=['PUT'])
|
||||
@login_required
|
||||
def update_article(article_id):
|
||||
"""更新文章(需要管理员权限)"""
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
article = Article.query.get_or_404(article_id)
|
||||
data = request.get_json()
|
||||
|
||||
article.title = data.get('title', article.title)
|
||||
article.content = data.get('content', article.content)
|
||||
article.summary = data.get('summary', article.summary)
|
||||
article.category = data.get('category', article.category)
|
||||
article.is_protected = data.get('is_protected', article.is_protected)
|
||||
article.published = data.get('published', article.published)
|
||||
article.updated_at = datetime.utcnow()
|
||||
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Article updated successfully',
|
||||
'article': article.to_dict()
|
||||
}), 200
|
||||
|
||||
@bp.route('/articles/<int:article_id>', methods=['DELETE'])
|
||||
@login_required
|
||||
def delete_article(article_id):
|
||||
"""删除文章(需要管理员权限)"""
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
article = Article.query.get_or_404(article_id)
|
||||
db.session.delete(article)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({'message': 'Article deleted successfully'}), 200
|
||||
|
||||
# 资源管理
|
||||
@bp.route('/resources', methods=['GET'])
|
||||
def get_resources():
|
||||
"""获取资源列表"""
|
||||
category = request.args.get('category')
|
||||
|
||||
query = Resource.query
|
||||
|
||||
if category:
|
||||
query = query.filter_by(category=category)
|
||||
|
||||
# 如果未登录,过滤受保护资源
|
||||
if not current_user.is_authenticated:
|
||||
query = query.filter_by(is_protected=False)
|
||||
|
||||
resources = query.order_by(Resource.created_at.desc()).all()
|
||||
|
||||
return jsonify({
|
||||
'resources': [resource.to_dict() for resource in resources]
|
||||
}), 200
|
||||
|
||||
@bp.route('/resources', methods=['POST'])
|
||||
@login_required
|
||||
def upload_resource():
|
||||
"""上传资源文件(需要管理员权限)"""
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
if 'file' not in request.files:
|
||||
return jsonify({'error': 'No file provided'}), 400
|
||||
|
||||
file = request.files['file']
|
||||
if file.filename == '':
|
||||
return jsonify({'error': 'No file selected'}), 400
|
||||
|
||||
if file and allowed_file(file.filename, {'pdf', 'zip', 'rar', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx'}):
|
||||
filename = secure_filename(file.filename)
|
||||
uploads_dir = current_app.config['UPLOAD_FOLDER']
|
||||
os.makedirs(uploads_dir, exist_ok=True)
|
||||
filepath = os.path.join(uploads_dir, filename)
|
||||
file.save(filepath)
|
||||
|
||||
resource = Resource(
|
||||
name=request.form.get('name', filename),
|
||||
description=request.form.get('description', ''),
|
||||
file_path=f'/uploads/{filename}',
|
||||
file_size=os.path.getsize(filepath),
|
||||
file_type=filename.rsplit('.', 1)[1].lower(),
|
||||
category=request.form.get('category', 'document'),
|
||||
is_protected=request.form.get('is_protected', 'false').lower() == 'true'
|
||||
)
|
||||
|
||||
db.session.add(resource)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Resource uploaded successfully',
|
||||
'resource': resource.to_dict()
|
||||
}), 201
|
||||
|
||||
return jsonify({'error': 'Invalid file type'}), 400
|
||||
|
||||
# 团队成员管理
|
||||
@bp.route('/team', methods=['GET'])
|
||||
def get_team():
|
||||
"""获取团队成员列表"""
|
||||
role = request.args.get('role')
|
||||
|
||||
query = TeamMember.query
|
||||
|
||||
if role:
|
||||
query = query.filter_by(role=role)
|
||||
|
||||
members = query.order_by(TeamMember.order, TeamMember.created_at).all()
|
||||
|
||||
return jsonify({
|
||||
'members': [member.to_dict() for member in members]
|
||||
}), 200
|
||||
|
||||
@bp.route('/team', methods=['POST'])
|
||||
@login_required
|
||||
def create_team_member():
|
||||
"""创建团队成员(需要管理员权限)"""
|
||||
if not current_user.is_admin:
|
||||
return jsonify({'error': 'Admin access required'}), 403
|
||||
|
||||
data = request.get_json()
|
||||
|
||||
member = TeamMember(
|
||||
name=data.get('name'),
|
||||
title=data.get('title'),
|
||||
title_en=data.get('title_en'),
|
||||
bio=data.get('bio'),
|
||||
bio_en=data.get('bio_en'),
|
||||
role=data.get('role', 'student'),
|
||||
email=data.get('email'),
|
||||
website=data.get('website'),
|
||||
order=data.get('order', 0)
|
||||
)
|
||||
|
||||
db.session.add(member)
|
||||
db.session.commit()
|
||||
|
||||
return jsonify({
|
||||
'message': 'Team member created successfully',
|
||||
'member': member.to_dict()
|
||||
}), 201
|
||||
|
||||
Reference in New Issue
Block a user