From 4467d5211e9537451b2362eadbc9ead7e162ab00 Mon Sep 17 00:00:00 2001 From: jeremygan2021 Date: Mon, 16 Feb 2026 19:14:45 +0800 Subject: [PATCH] sms --- README.md | 3 +- main.py | 109 +++++++++++++++++++++++++++++++++++++----------------- 2 files changed, 78 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 1b06662..dbab54c 100644 --- a/README.md +++ b/README.md @@ -148,7 +148,8 @@ docker run -d -p 9090:9090 \ ### 短信服务 -- `POST /api/send-sms` - 发送短信 +- `POST /api/send-sms` - 发送验证码 +- `POST /api/send-sms/diy` - 发送定制短信 - `GET /api/sms-records` - 获取短信记录 ### OSS 服务 diff --git a/main.py b/main.py index 01ee74e..5faee74 100644 --- a/main.py +++ b/main.py @@ -7,20 +7,13 @@ from fastapi.middleware.cors import CORSMiddleware from fastapi.security import APIKeyHeader import uuid import os -from typing import Optional, List +from typing import Optional, List, Dict, Any from pydantic import BaseModel from sms import SMS from oss_service import oss_service from config import settings -class SMSRequest(BaseModel): - phone_number: str - code: Optional[str] = None - template_code: Optional[str] = settings.sms_template_code - sign_name: Optional[str] = settings.sms_sign_name - class Config: - extra = "allow" @@ -837,33 +830,95 @@ def update_user(phone: str, user_update: UserUpdate, current_user: dict = Depend pool.putconn(conn) + + +class SMSCodeRequest(BaseModel): + phone_number: str + code: str + template_code: Optional[str] = settings.sms_template_code + sign_name: Optional[str] = settings.sms_sign_name + +class SMSCustomRequest(BaseModel): + phone_number: str + template_code: str + sign_name: str + template_params: Optional[Dict[str, Any]] = None + + class Config: + extra = "allow" + @app.post("/api/send-sms", tags=["短信服务"]) -async def send_sms(sms_request: SMSRequest): - """发送短信API""" +async def send_sms(request: SMSCodeRequest): + """发送验证码API""" + sms = SMS() + + # 构造参数 + params = {"code": request.code} + + print(f"Sending Verification Code to {request.phone_number}: {request.code}") + + result = sms.main( + self=sms, + phone_number=request.phone_number, + template_code=request.template_code, + sign_name=request.sign_name, + **params + ) + + # 保存发送记录 + _save_sms_record(request.phone_number, request.template_code, request.sign_name, params, result) + + if not result or not result.get('success'): + return {"status": "failed", "message": result.get('error_message') if result else "发送失败"} + + return {"status": "success", "message": "验证码发送请求已处理", "data": result} + +@app.post("/api/send-sms/diy", tags=["短信服务"]) +async def send_custom_sms(request: SMSCustomRequest): + """通用短信发送API (支持自定义模板和参数)""" sms = SMS() # 获取所有参数 - request_data = sms_request.dict() + request_data = request.dict() - # 提取固定参数 + # 提取已知字段 phone_number = request_data.pop('phone_number') template_code = request_data.pop('template_code') sign_name = request_data.pop('sign_name') + template_params = request_data.pop('template_params', None) - # 过滤掉值为 None 的参数,剩余的作为动态参数 - dynamic_params = {k: v for k, v in request_data.items() if v is not None} + # 剩下的作为动态参数 + dynamic_params = request_data - print(f"Sending SMS with template_code: {template_code}, sign_name: {sign_name}, params: {dynamic_params}") + # 如果有显式的 template_params,合并进去 + if template_params: + dynamic_params.update(template_params) + + # 特殊处理:兼容 Swagger UI 或某些客户端生成的 additionalProp1 + if 'additionalProp1' in dynamic_params and isinstance(dynamic_params['additionalProp1'], dict): + extra_props = dynamic_params.pop('additionalProp1') + dynamic_params.update(extra_props) + + print(f"Sending Custom SMS with template_code: {template_code}, params: {dynamic_params}") result = sms.main( - self=sms, - phone_number=phone_number, - template_code=template_code, + self=sms, + phone_number=phone_number, + template_code=template_code, sign_name=sign_name, **dynamic_params ) - # 保存发送记录到数据库 + # 保存发送记录 + _save_sms_record(phone_number, template_code, sign_name, dynamic_params, result) + + if not result or not result.get('success'): + return {"status": "failed", "message": result.get('error_message') if result else "发送失败"} + + return {"status": "success", "message": "短信发送请求已处理", "data": result} + +def _save_sms_record(phone_number, template_code, sign_name, params, result): + """辅助函数:保存短信记录到数据库""" conn = pool.getconn() try: with conn.cursor() as cur: @@ -871,15 +926,7 @@ async def send_sms(sms_request: SMSRequest): biz_id = result.get('biz_id') if result else None error_message = result.get('error_message') if result else 'Unknown error' - # 将参数转换为字符串存储 - if dynamic_params: - # 如果只有 code 参数,为了保持兼容性,优先尝试只存 code 值(如果这是之前的习惯) - # 但考虑到现在支持多参数,存 JSON 更加通用。 - # 这里为了直观,如果有多个参数或没有 code,存 JSON。 - # 如果只有 code,也可以存 JSON,因为 sms.py 内部最终是转 JSON 发送的。 - saved_param = json.dumps(dynamic_params, ensure_ascii=False) - else: - saved_param = "" + saved_param = json.dumps(params, ensure_ascii=False) if params else "" cur.execute(""" INSERT INTO sms_records (phone_number, template_code, template_param, sign_name, status, biz_id, error_message) @@ -890,11 +937,7 @@ async def send_sms(sms_request: SMSRequest): print(f"Error saving SMS record: {e}") finally: pool.putconn(conn) - - if not result or not result.get('success'): - return {"status": "failed", "message": result.get('error_message') if result else "发送失败"} - - return {"status": "success", "message": "短信发送请求已处理", "data": result} + class ConversationCreate(BaseModel): user_phone: str | None = None