import os import re from flask import Flask, jsonify, send_from_directory, render_template, request app = Flask(__name__) PROBLEMS_DIR = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'problems') def parse_problem_metadata(filename): filepath = os.path.join(PROBLEMS_DIR, filename) with open(filepath, 'r', encoding='utf-8') as f: content = f.read() # 默认标题为文件名 title = filename # 尝试解析 @title # 匹配 /** ... @title 标题 ... */ 或 // @title 标题 title_match = re.search(r'@title\s+(.+)', content) if title_match: title = title_match.group(1).strip() # 解析 @category category_match = re.search(r'@category\s+(.+)', content) category = category_match.group(1).strip() if category_match else '练习题' # 解析 @pinned pinned_match = re.search(r'@pinned\s+(.+)', content) is_pinned = (pinned_match.group(1).strip().lower() == 'true') if pinned_match else False return { 'id': filename, 'title': title, 'category': category, 'pinned': is_pinned, 'content': content, 'ctime': os.path.getctime(filepath) } @app.route('/') def index(): return render_template('index.html') @app.route('/api/problems', methods=['GET']) def get_problems(): files = [f for f in os.listdir(PROBLEMS_DIR) if f.endswith('.js') or f.endswith('.ts')] # 按创建时间倒序排序 (最新的在最前) files.sort(key=lambda x: os.path.getctime(os.path.join(PROBLEMS_DIR, x)), reverse=True) problems = [] for f in files: try: problems.append(parse_problem_metadata(f)) except Exception as e: print(f"Error parsing {f}: {e}") return jsonify(problems) @app.route('/api/problems', methods=['POST']) def create_problem(): data = request.json filename = data.get('filename') category = data.get('category', '练习题') if not filename: return jsonify({'error': 'Filename is required'}), 400 if not (filename.endswith('.js') or filename.endswith('.ts')): filename += '.js' filepath = os.path.join(PROBLEMS_DIR, filename) if os.path.exists(filepath): return jsonify({'error': 'File already exists'}), 409 # 默认模板 content = f"""/** * @title {filename} * @category {category} * @description 在此处添加题目描述 */ function solve() {{ // TODO: Implement solution }} console.log(solve()); """ try: with open(filepath, 'w', encoding='utf-8') as f: f.write(content) return jsonify(parse_problem_metadata(filename)), 201 except Exception as e: return jsonify({'error': str(e)}), 500 @app.route('/api/problems/', methods=['GET']) def get_problem_content(filename): return send_from_directory(PROBLEMS_DIR, filename) @app.route('/api/problems/', methods=['PUT']) def update_problem(filename): filepath = os.path.join(PROBLEMS_DIR, filename) if not os.path.exists(filepath): return jsonify({'error': 'File not found'}), 404 data = request.json # Handle Rename new_filename = data.get('new_filename') if new_filename: if not (new_filename.endswith('.js') or new_filename.endswith('.ts')): new_filename += '.js' new_filepath = os.path.join(PROBLEMS_DIR, new_filename) if os.path.exists(new_filepath) and new_filename != filename: return jsonify({'error': 'Target filename already exists'}), 409 try: os.rename(filepath, new_filepath) return jsonify(parse_problem_metadata(new_filename)) except Exception as e: return jsonify({'error': str(e)}), 500 # Handle Content Update content = data.get('content') if content is not None: try: with open(filepath, 'w', encoding='utf-8') as f: f.write(content) # 返回新的 metadata 以便前端更新标题 return jsonify(parse_problem_metadata(filename)) except Exception as e: return jsonify({'error': str(e)}), 500 return jsonify({'error': 'No valid operation specified'}), 400 @app.route('/api/problems/', methods=['DELETE']) def delete_problem(filename): filepath = os.path.join(PROBLEMS_DIR, filename) if not os.path.exists(filepath): return jsonify({'error': 'File not found'}), 404 try: os.remove(filepath) return jsonify({'message': 'Deleted successfully'}) except Exception as e: return jsonify({'error': str(e)}), 500 if __name__ == '__main__': # 确保 problems 目录存在 if not os.path.exists(PROBLEMS_DIR): os.makedirs(PROBLEMS_DIR) app.run(host='0.0.0.0', port=7860, debug=True)