from flask import Blueprint, render_template, request, jsonify, redirect, url_for, session, flash, send_file, current_app import os from app.models import db, Article, Image from app.utils import handle_image_upload, login_required, check_auth from app.ai_service import generate_summary, chat_with_ai import io import json # Blueprints main = Blueprint('main', __name__) admin = Blueprint('admin', __name__) api = Blueprint('api', __name__) # Main routes @main.route('/') def index(): articles = Article.query.order_by(Article.created_at.desc()).all() return render_template('index.html', articles=articles) @main.route('/article/') def article(slug): article = Article.query.filter_by(slug=slug).first_or_404() return render_template('article.html', article=article) # Admin routes # @admin.route('/login', methods=['GET', 'POST']) # def login(): # if request.method == 'POST': # if check_auth(request.form['username'], request.form['password']): # session['logged_in'] = True # return redirect(url_for('admin.dashboard')) # flash('Invalid credentials') # return render_template('admin/login.html') @admin.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'POST': if session.get('logged_in'): session.pop('logged_in', None) flash('已成功退出登录') return redirect(url_for('main.index')) if check_auth(request.form['username'], request.form['password']): session['logged_in'] = True return redirect(url_for('admin.dashboard')) flash('用户名或密码错误') return render_template('admin/login.html') @api.route('/search', methods=['GET']) def search(): query = request.args.get('q', '') if not query: return jsonify({'articles': []}) # 简单的模糊搜索:标题或内容包含搜索词 articles = Article.query.filter( db.or_( Article.title.ilike(f'%{query}%'), Article.content.ilike(f'%{query}%') ) ).order_by(Article.created_at.desc()).all() # 转换为JSON格式 articles_data = [{ 'title': article.title, 'summary': article.summary, 'slug': article.slug, 'created_at': article.created_at.strftime('%Y-%m-%d') } for article in articles] return jsonify({'articles': articles_data}) @admin.route('/dashboard') @login_required def dashboard(): articles = Article.query.order_by(Article.created_at.desc()).all() return render_template('admin/dashboard.html', articles=articles) @admin.route('/editor', defaults={'slug': None}) @admin.route('/editor/') @login_required def editor(slug): article = Article.query.filter_by(slug=slug).first() if slug else None return render_template('editor.html', article=article) # API routes @api.route('/articles', methods=['POST']) @login_required def create_article(): try: data = request.get_json() if not data or 'title' not in data or 'content' not in data: return jsonify({'error': '标题和内容不能为空'}), 400 article = Article( title=data['title'], content=data['content'] ) article.summary = generate_summary(data['content']) db.session.add(article) db.session.commit() return jsonify({'slug': article.slug}) except Exception as e: db.session.rollback() return jsonify({'error': str(e)}), 500 @api.errorhandler(500) def handle_500(error): return jsonify({'error': '服务器内部错误'}), 500 @api.route('/articles/', methods=['PUT']) @login_required def update_article(slug): article = Article.query.filter_by(slug=slug).first_or_404() data = request.get_json() article.title = data['title'] article.content = data['content'] article.summary = generate_summary(data['content']) db.session.commit() return jsonify({'success': True}) @api.route('/articles/', methods=['DELETE']) @login_required def delete_article(slug): article = Article.query.filter_by(slug=slug).first_or_404() db.session.delete(article) db.session.commit() return jsonify({'success': True}) @api.route('/upload', methods=['POST']) @login_required def upload(): if 'file' not in request.files: return jsonify({'error': 'No file provided'}), 400 file = request.files['file'] path = handle_image_upload(file) if path: return jsonify({'url': path}) return jsonify({'error': 'Invalid file'}), 400 @api.route('/images/') def get_image(image_id): image = Image.query.get_or_404(image_id) return send_file( io.BytesIO(image.data), mimetype=image.mime_type, as_attachment=False ) @api.route('/chat', methods=['POST']) def chat(): data = request.get_json() response = chat_with_ai(data['messages']) return jsonify({'response': response}) @api.route('/export', methods=['GET']) @login_required def export_data(): db_path = os.path.join(current_app.root_path, '..', 'instance', 'blog.db') return send_file( db_path, as_attachment=True, download_name='blog-backup.db', mimetype='application/x-sqlite3' ) @api.route('/import', methods=['POST']) @login_required def import_data(): 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 not file.filename.endswith('.db'): return jsonify({'error': 'Invalid file type'}), 400 try: db_path = os.path.join(current_app.root_path, '..', 'instance', 'blog.db') file.save(db_path) db.session.remove() # Close any existing connections return jsonify({'success': True}) except Exception as e: return jsonify({'error': str(e)}), 500