Browse Source

feat: update

jerry 2 tháng trước cách đây
mục cha
commit
e32daa45ae

+ 14 - 2
app/api/router.py

@@ -23,7 +23,7 @@ from app.models.product import VasProduct
 from app.models.payment import VasPayment
 from app.schemas.common import ApiResponse, PageResponse
 from app.schemas.troov import TroovRate, TroovCheckForbiddenInput, TroovProb
-from app.schemas.sms import ShortMessageDetail
+from app.schemas.sms import ShortMessageDetail, SmsSendIn
 from app.schemas.configuration import ConfigurationCreate, ConfigurationUpdate, ConfigurationOut
 from app.schemas.email_authorizations import EmailContent, EmailAuthorizationCreate, EmailAuthorizationUpdate, EmailAuthorizationOut
 from app.schemas.emails import VasEmailCreate, VasEmailOut
@@ -60,7 +60,7 @@ from app.services.docker_remote_service import DockerRemoteService
 from app.services.configuration_service import ConfigurationService
 from app.services.troov_service import TroovService
 from app.services.visametric_service import VisametricService
-from app.services.sms_service import save_short_message, query_short_message
+from app.services.sms_service import save_short_message, query_short_message, send_sms
 from app.services.email_authorizations_service import EmailAuthorizationService
 from app.services.emails_service import EmailsService
 from app.services.short_url_service import ShortUrlService
@@ -291,6 +291,18 @@ async def sms_download(
     obj = await query_short_message(redis_client, phone, keyword or None, sent_at or None)
     return success(data=obj)
 
+
+@admin_required_router.post("/sms/send", summary="发送短信", tags=["短信接口"], response_model=ApiResponse[str])
+async def sms_send(
+    payload: SmsSendIn,
+):
+    res = await send_sms(
+        send_to=payload.send_to,
+        sender=payload.sender,
+        content=payload.content,
+    )
+    return success(data=res)
+
 @admin_required_router.get("/troov/rate", summary="TROOV 查询rate", tags=["通用接口"], response_model=ApiResponse[List[TroovRate]])
 async def troov_rate(date: str = Query(..., description="查询的日期, 格式: YYYY-MM-DD"),
                redis_client: Redis = Depends(get_redis_client)):

+ 7 - 1
app/schemas/sms.py

@@ -3,4 +3,10 @@ from pydantic import BaseModel
 class ShortMessageDetail(BaseModel):
     phone: str
     message: str
-    received_at: str
+    received_at: str
+
+
+class SmsSendIn(BaseModel):
+    send_to: str
+    sender: str
+    content: str

+ 1 - 1
app/services/slot_snapshot_service.py

@@ -46,7 +46,7 @@ class SlotSnapshotService:
             redis_client, 
             throttle_key, 
             signature, 
-            expire_seconds=1800
+            expire_seconds=2*60*60
         )
         # ==================== 修复结束 ====================
 

+ 49 - 0
app/services/sms_service.py

@@ -1,9 +1,13 @@
 # app/services/sms_service.py
 
 import json
+import os
 from typing import List
+from urllib.parse import quote
+import aiohttp
 from redis.asyncio import Redis
 from app.schemas.sms import ShortMessageDetail
+from app.core.biz_exception import BizLogicError
 
 
 async def save_short_message(
@@ -84,3 +88,48 @@ async def query_short_message(
         ]
 
     return messages
+
+
+async def send_sms(
+    send_to: str,
+    sender: str,
+    content: str,
+    cpid: str = "",
+    cppwd: str = "",
+    base_url: str = "",
+) -> str:
+    """
+    发送短信(异步版)
+    """
+    cpid = cpid or os.getenv("SMS_CPID", "6jLoZoRZ")
+    cppwd = cppwd or os.getenv("SMS_CPPWD", "LYTErsAE")
+    base_url = base_url or os.getenv("SMS_BASE_URL", "http://api2.santo.cc/submit")
+
+    if not send_to:
+        raise BizLogicError("sms send_to required")
+    if not sender:
+        raise BizLogicError("sms sender required")
+    if not content:
+        raise BizLogicError("sms content required")
+
+    encoded = quote(content, safe="")
+    url = (
+        f"{base_url}"
+        f"?command=MT_REQUEST"
+        f"&cpid={cpid}"
+        f"&cppwd={cppwd}"
+        f"&da={send_to}"
+        f"&sa={sender}"
+        f"&sm={encoded}"
+    )
+
+    timeout = aiohttp.ClientTimeout(total=10)
+    try:
+        async with aiohttp.ClientSession(timeout=timeout) as session:
+            async with session.get(url) as resp:
+                text = await resp.text()
+                if resp.status >= 300:
+                    raise BizLogicError(f"sms send failed, http_status={resp.status}, body={text}")
+                return text
+    except aiohttp.ClientError as e:
+        raise BizLogicError(f"sms send request error: {e}")