| 22301110 | e361be5 | 2025-06-08 15:24:14 +0800 | [diff] [blame] | 1 | from flask import Flask, jsonify, request, current_app |
| 2 | from flask_cors import CORS |
| 3 | import traceback |
| 4 | import hashlib |
| 5 | import requests |
| 6 | from bs4 import BeautifulSoup, MarkupResemblesLocatorWarning |
| 7 | import warnings |
| 8 | import config |
| 9 | import pymysql.cursors # 确保导入了 pymysql 的 cursors |
| 10 | from pyngrok import ngrok |
| 11 | from flask import Flask, request, jsonify |
| 12 | from flask_cors import CORS |
| 13 | from smtplib import SMTP_SSL |
| 14 | from email.mime.text import MIMEText |
| 15 | import random, datetime |
| 16 | import bcrypt |
| 17 | import mysql.connector |
| 18 | |
| 19 | |
| 20 | app = Flask(__name__) |
| 21 | CORS(app, supports_credentials=True) # 支持 cookies(可选) |
| 22 | |
| 23 | # 商户ID和密钥 |
| 24 | merchant_id = 4058 |
| 25 | merchant_key = '2c9e609b503698c6f1dba301725ec631' |
| 26 | base_url = 'https://api.ltrhcj.cn/api/paySubmit' # 请求网关 |
| 27 | |
| 28 | def generate_md5_signature(*args): |
| 29 | """根据传入的参数生成MD5签名""" |
| 30 | sign_str = ''.join(args) |
| 31 | return hashlib.md5(sign_str.encode('utf-8')).hexdigest() |
| 32 | |
| 33 | @app.route('/paySuccess', methods=['POST', 'GET']) |
| 34 | def pay_success(): |
| 35 | data = request.form if request.method == 'POST' else request.args |
| 36 | orderid = data.get('orderid') |
| 37 | state = data.get('state') |
| 38 | amount = data.get('amount') |
| 39 | payment = data.get('payment') |
| 40 | rate = data.get('rate') |
| 41 | sign = data.get('sign') |
| 42 | |
| 43 | if not orderid or not state or not amount or not payment or not sign: |
| 44 | return "Missing parameter", 400 |
| 45 | |
| 46 | try: |
| 47 | print("Received paySuccess notification:") |
| 48 | print(f"orderid: {orderid}") |
| 49 | print(f"state: {state}") |
| 50 | print(f"amount: {amount}") |
| 51 | print(f"payment: {payment}") |
| 52 | print(f"rate: {rate}") |
| 53 | print(f"sign: {sign}") |
| 54 | |
| 55 | # 获取数据库连接 |
| 56 | connection = config.get_db_connection() |
| 57 | cursor = connection.cursor(pymysql.cursors.DictCursor) |
| 58 | |
| 59 | # 查询该订单对应的邮箱和密码 |
| 60 | cursor.execute("SELECT user_name, password FROM `order` WHERE orderid = %s", (orderid,)) |
| 61 | result = cursor.fetchone() |
| 62 | print("result内容:", result) |
| 63 | |
| 64 | if result: |
| 65 | email = result["user_name"] |
| 66 | raw_password = result["password"] |
| 67 | |
| 68 | # 查询 sys_user 是否已存在该 email |
| 69 | cursor.execute("SELECT user_id FROM sys_user WHERE email = %s", (email,)) |
| 70 | user_exists = cursor.fetchone() |
| 71 | |
| 72 | if not user_exists: |
| 73 | # 加密密码(如果已经加密过,可以略过这一步) |
| 74 | |
| 75 | cursor.execute(""" |
| 76 | INSERT INTO sys_user ( |
| 77 | user_name, nick_name, password, email, create_time, del_flag, status, user_type |
| 78 | ) VALUES (%s, %s, %s, %s, NOW(), '0', '0', '00') |
| 79 | """, (email, email, raw_password, email)) |
| 80 | else: |
| 81 | cursor.execute("UPDATE sys_user SET status = '0' WHERE email = %s", (email,)) |
| 82 | |
| 83 | # 更新订单状态为已支付 |
| 84 | cursor.execute("UPDATE `order` SET state = %s WHERE orderid = %s", ('已支付', orderid)) |
| 85 | |
| 86 | connection.commit() |
| 87 | |
| 88 | cursor.close() |
| 89 | connection.close() |
| 90 | |
| 91 | return "success", 200 |
| 92 | |
| 93 | except Exception as e: |
| 94 | import traceback |
| 95 | current_app.logger.error(f'发生异常: {e}') |
| 96 | traceback.print_exc() |
| 97 | return "Internal server error", 500 |
| 98 | |
| 99 | |
| 100 | |
| 101 | |
| 102 | @app.route('/user/createOrder', methods=['POST']) |
| 103 | def create_order(): |
| 104 | data = request.json |
| 105 | print(data) |
| 106 | orderid = data.get('orderid') |
| 107 | paytype = data.get('paytype') |
| 108 | money = data.get('money') |
| 109 | notifyUrl = data.get('notifyUrl', '') |
| 110 | returnUrl = data.get('returnUrl', '') |
| 111 | returnmsg = 2 |
| 112 | user_name = data.get('user_name') |
| 113 | password = data.get('password') # 👈 获取前端传来的加密密码 |
| 114 | |
| 115 | print(data) |
| 116 | if not orderid or not paytype or not money or not user_name: |
| 117 | return jsonify({'success': False, 'message': '缺少必传参数'}), 400 |
| 118 | |
| 119 | try: |
| 120 | sign = generate_md5_signature(str(merchant_id), orderid, str(paytype), str(money), merchant_key) |
| 121 | payload = { |
| 122 | 'appid': merchant_id, |
| 123 | 'orderid': orderid, |
| 124 | 'paytype': paytype, |
| 125 | 'money': money, |
| 126 | 'sign': sign, |
| 127 | 'notifyUrl': notifyUrl, |
| 128 | 'returnUrl': returnUrl, |
| 129 | 'returnmsg': returnmsg |
| 130 | } |
| 131 | |
| 132 | # 发送POST请求到外部 API |
| 133 | response = requests.post(base_url, data=payload) |
| 134 | current_app.logger.debug(f'请求URL: {base_url}') |
| 135 | current_app.logger.debug(f'请求数据: {payload}') |
| 136 | |
| 137 | if response.status_code == 200: |
| 138 | # 将订单信息插入到数据库的 order 表中 |
| 139 | connection = config.get_db_connection() |
| 140 | cursor = connection.cursor() |
| 141 | cursor.execute( |
| 142 | "INSERT INTO `order` (orderid, user_name, password, time, amount, state) VALUES (%s, %s, %s, NOW(), %s, %s)", |
| 143 | (orderid, user_name, password, money, 'pending') |
| 144 | ) |
| 145 | |
| 146 | connection.commit() |
| 147 | cursor.close() |
| 148 | connection.close() |
| 149 | |
| 150 | return response.text, 200 |
| 151 | else: |
| 152 | return jsonify({'success': False, 'message': f"外部 API 错误: {response.text}"}), response.status_code |
| 153 | except Exception as e: |
| 154 | current_app.logger.error(f'发生异常: {e}') |
| 155 | traceback.print_exc() |
| 156 | return jsonify({'success': False, 'message': f"Error: {e}"}), 530 |
| 157 | |
| 158 | |
| 159 | |
| 160 | |
| 161 | |
| 162 | |
| 163 | |
| 164 | # 邮箱配置 |
| 165 | SMTP_SERVER = 'smtp.qq.com' |
| 166 | EMAIL_ADDRESS = '3534185780@qq.com' |
| 167 | EMAIL_AUTH_CODE = 'slcsbwtrwitbcjic' |
| 168 | |
| 169 | # 数据库配置 |
| 170 | DB_CONFIG = { |
| 171 | 'host': '49.233.215.144', |
| 172 | 'port': 3306, |
| 173 | 'user': 'sy', |
| 174 | 'password': 'sy_password', |
| 175 | 'database': 'pt_station' |
| 176 | } |
| 177 | |
| 178 | |
| 179 | # === 发送验证码接口 === |
| 180 | @app.route('/send-code', methods=['POST']) |
| 181 | def send_code(): |
| 182 | data = request.get_json() |
| 183 | to_email = data.get('email') |
| 184 | |
| 185 | if not to_email: |
| 186 | return jsonify({"success": False, "message": "缺少邮箱"}), 400 |
| 187 | |
| 188 | code = str(random.randint(100000, 999999)) |
| 189 | msg = MIMEText(f"欢迎注册PTStation,您的验证码是:{code}(有效期5分钟)") |
| 190 | msg['Subject'] = '您的验证码' |
| 191 | msg['From'] = EMAIL_ADDRESS |
| 192 | msg['To'] = to_email |
| 193 | |
| 194 | try: |
| 195 | # 发送邮件 |
| 196 | with SMTP_SSL(SMTP_SERVER, 465) as smtp: |
| 197 | smtp.login(EMAIL_ADDRESS, EMAIL_AUTH_CODE) |
| 198 | smtp.send_message(msg) |
| 199 | smtp.quit() |
| 200 | # 存入数据库 |
| 201 | conn = mysql.connector.connect(**DB_CONFIG) |
| 202 | cursor = conn.cursor() |
| 203 | sql = "INSERT INTO email_verification (email, code, created_at) VALUES (%s, %s, NOW())" |
| 204 | cursor.execute(sql, (to_email, code)) |
| 205 | conn.commit() |
| 206 | cursor.close() |
| 207 | conn.close() |
| 208 | |
| 209 | return jsonify({"success": True}) |
| 210 | except Exception as e: |
| 211 | print("发送失败:", e) |
| 212 | return jsonify({"success": False, "message": f"邮件发送失败:{e}"}), 500 |
| 213 | |
| 214 | |
| 215 | # === 注册接口 === |
| 216 | @app.route('/register', methods=['POST']) |
| 217 | def register(): |
| 218 | data = request.get_json() |
| 219 | email = data.get('email') |
| 220 | password = data.get('password') # 可以保留做哈希后传给支付回调存库 |
| 221 | code = data.get('code') |
| 222 | |
| 223 | if not all([email, password, code]): |
| 224 | return jsonify({"success": False, "message": "缺少参数"}), 400 |
| 225 | |
| 226 | try: |
| 227 | conn = mysql.connector.connect(**DB_CONFIG) |
| 228 | cursor = conn.cursor(dictionary=True) |
| 229 | |
| 230 | # 1. 验证验证码是否有效(5分钟内) |
| 231 | cursor.execute(""" |
| 232 | SELECT * FROM email_verification |
| 233 | WHERE email = %s AND code = %s AND created_at > NOW() - INTERVAL 5 MINUTE |
| 234 | ORDER BY created_at DESC LIMIT 1 |
| 235 | """, (email, code)) |
| 236 | result = cursor.fetchone() |
| 237 | |
| 238 | if not result: |
| 239 | return jsonify({"success": False, "message": "验证码无效或已过期"}), 400 |
| 240 | |
| 241 | # 2. 检查邮箱是否已注册 |
| 242 | cursor.execute("SELECT user_id FROM sys_user WHERE email = %s", (email,)) |
| 243 | if cursor.fetchone(): |
| 244 | return jsonify({"success": False, "message": "该邮箱已注册"}), 400 |
| 245 | |
| 246 | # ⚠️ 不再插入数据库,只返回验证通过 |
| 247 | return jsonify({"success": True, "message": "验证通过"}) |
| 248 | |
| 249 | except Exception as e: |
| 250 | print("注册失败:", e) |
| 251 | return jsonify({"success": False, "message": f"注册失败:{e}"}), 500 |
| 252 | finally: |
| 253 | cursor.close() |
| 254 | conn.close() |
| 255 | |
| 256 | |
| 257 | |
| 258 | @app.route('/reset-password', methods=['POST']) |
| 259 | def reset_password(): |
| 260 | data = request.get_json() |
| 261 | email = data.get('email') |
| 262 | code = data.get('code') |
| 263 | new_password = data.get('newPassword') |
| 264 | |
| 265 | if not all([email, code, new_password]): |
| 266 | return jsonify({"success": False, "message": "参数缺失"}), 400 |
| 267 | |
| 268 | try: |
| 269 | conn = mysql.connector.connect(**DB_CONFIG) |
| 270 | cursor = conn.cursor() |
| 271 | |
| 272 | # 验证验证码是否正确且在有效期内 |
| 273 | cursor.execute(""" |
| 274 | SELECT * FROM email_verification |
| 275 | WHERE email = %s AND code = %s |
| 276 | AND created_at > NOW() - INTERVAL 5 MINUTE |
| 277 | ORDER BY created_at DESC LIMIT 1 |
| 278 | """, (email, code)) |
| 279 | result = cursor.fetchone() |
| 280 | |
| 281 | if not result: |
| 282 | return jsonify({"success": False, "message": "验证码错误或已过期"}), 400 |
| 283 | |
| 284 | # 加密密码 |
| 285 | import bcrypt |
| 286 | hashed_pwd = bcrypt.hashpw(new_password.encode(), bcrypt.gensalt()).decode() |
| 287 | |
| 288 | # 检查用户是否存在 |
| 289 | cursor.execute("SELECT user_id FROM sys_user WHERE email = %s", (email,)) |
| 290 | user = cursor.fetchone() |
| 291 | if not user: |
| 292 | return jsonify({"success": False, "message": "用户不存在"}), 404 |
| 293 | |
| 294 | # 更新密码 |
| 295 | cursor.execute(""" |
| 296 | UPDATE sys_user |
| 297 | SET password = %s |
| 298 | WHERE email = %s |
| 299 | """, (hashed_pwd, email)) |
| 300 | |
| 301 | conn.commit() |
| 302 | return jsonify({"success": True, "message": "密码已重置"}) |
| 303 | |
| 304 | except Exception as e: |
| 305 | print("重置失败:", e) |
| 306 | return jsonify({"success": False, "message": f"服务器异常:{e}"}), 500 |
| 307 | |
| 308 | finally: |
| 309 | if cursor: |
| 310 | cursor.close() |
| 311 | if conn: |
| 312 | conn.close() |
| 313 | |
| 314 | from flask import send_file, jsonify |
| 315 | |
| 316 | @app.route('/ngrok-url', methods=['GET']) |
| 317 | def ngrok_url(): |
| 318 | try: |
| 319 | with open("ngrok_url.txt", "r", encoding="utf-8") as f: |
| 320 | url = f.read().strip() |
| 321 | print(url) |
| 322 | return jsonify({"backUrl": f"{url}"}) |
| 323 | except FileNotFoundError: |
| 324 | # 回退到本地,避免前端报错 |
| 325 | return jsonify({"backUrl": "http://localhost:6001"}) |
| 326 | |
| 327 | if __name__ == '__main__': |
| 328 | try: |
| 329 | conn = config.get_db_connection() |
| 330 | print("数据库连接成功!") |
| 331 | conn.close() |
| 332 | except Exception as e: |
| 333 | print(f"数据库连接失败: {e}") |
| 334 | app.run(host='0.0.0.0', port=6001,debug =True) |