jerry 2 ヶ月 前
コミット
fcf9737558

+ 5 - 0
.env

@@ -4,3 +4,8 @@ REDIS_URL=redis://:STEs2x6ML0U1HlpE9SojM6YU7QPhqzY8@45.137.220.138:6379/0
 OPENAI_API_KEY=sk-893e895724c6403d81374e515ffaf427
 STRIPE_API_KEY=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
 STRIPE_WEBHOOK_SECRET=whsec_MRfGMJZVv1v8xnwnGl9ai8yXqpLSeQVL
+TELEGRAM_API_TOKEN=6771183256:AAEd0Tenq4z6hk5toUGrCpEVPfP00bpYT1s
+WECHAT_API_TOKEN=a8f79817-e18b-4739-8459-adb2ed5e2e32
+WHATSAPP_API_BASE_URL=https://waha.visafly.top
+WHATSAPP_API_KEY=51fc877539064f5882fae0f6f0661123
+WHATSAPP_SESSION=default

+ 34 - 3
app/api/router.py

@@ -46,9 +46,9 @@ from app.schemas.vas_task import VasTaskCreate, VasTaskUpdate, VasExpiringTaskIt
 from app.schemas.ticket import VasTicketCreate, VasTicketOut, VasTicketStatusUpdate, VasTicketMessageCreate, VasTicketMessageOut
 from app.schemas.slot_snapshot import SlotSnapshotCreate, SlotSnapshotOut, SlotOverviewOut
 from app.schemas.slot_refresh_status import RefreshBase, RefreshFail, RefreshStatusOut
-from app.schemas.telegram import TelegramIn
-from app.schemas.wechat import WechatIn
-from app.schemas.whatsapp import WhatsappIn
+from app.schemas.telegram import TelegramIn, TelegramNoTokenIn
+from app.schemas.wechat import WechatIn, WechatNoTokenIn
+from app.schemas.whatsapp import WhatsappIn, WhatsappNoTokenIn
 from app.schemas.notification_outbox import NotificationOutboxCreate, NotificationOutboxUpdate, NotificationOutboxOut
 from app.schemas.resource import FileUploadOut
 from app.schemas.statistics import VasStatisticsOverviewOut
@@ -724,6 +724,13 @@ async def tg_send_message(
     await TelegramService.push_text(payload)
     return success()
 
+@admin_required_router.post("/tg/send_message_no_token", summary="推送电报消息(无需token)", tags=["消息推送接口"], response_model=ApiResponse)
+async def tg_send_message_no_token(
+    payload: TelegramNoTokenIn
+):
+    await TelegramService.push_text_no_token(payload)
+    return success()
+
 @admin_required_router.post("/wechat/send", summary="推送微信文本消息", tags=["消息推送接口"], response_model=ApiResponse)
 async def wechat_send(
     payload: WechatIn
@@ -731,6 +738,20 @@ async def wechat_send(
     await WechatService.push_text(payload.api_token, payload.message)
     return success()
 
+@admin_required_router.post("/wechat/send_no_token", summary="推送微信文本消息(无需token)", tags=["消息推送接口"], response_model=ApiResponse)
+async def wechat_send_no_token(
+    payload: WechatNoTokenIn
+):
+    await WechatService.push_text_no_token(payload.message)
+    return success()
+
+@admin_required_router.post("/wechat/send_markdown_no_token", summary="推送微信Markdown消息(无需token)", tags=["消息推送接口"], response_model=ApiResponse)
+async def wechat_send_markdown_no_token(
+    payload: WechatNoTokenIn
+):
+    await WechatService.push_markdown_no_token(payload.message)
+    return success()
+
 @admin_required_router.post("/wechat/send_markdown", summary="推送微信Markdown消息", tags=["消息推送接口"], response_model=ApiResponse)
 async def wechat_send_markdown(
     payload: WechatIn
@@ -752,6 +773,16 @@ async def whatsapp_send(
     )
     return success()
 
+@admin_required_router.post("/whatsapp/send_no_token", summary="推送WhatsApp消息(无需token)", tags=["消息推送接口"], response_model=ApiResponse)
+async def whatsapp_send_no_token(
+    payload: WhatsappNoTokenIn
+):
+    await WhatsappService.send_text_no_token(
+        chat_id=payload.chat_id,
+        message=payload.message,
+    )
+    return success()
+
 
 @admin_required_router.post("/notification/outbox/create", summary="创建通知消息", tags=["消息推送接口"], response_model=ApiResponse[NotificationOutboxOut])
 async def notification_outbox_create(

+ 5 - 0
app/core/config.py

@@ -23,6 +23,11 @@ class Settings(BaseSettings):
     openai_api_key: str
     stripe_api_key: str
     stripe_webhook_secret: str
+    telegram_api_token: str = Field("", description="Telegram bot API token")
+    wechat_api_token: str = Field("", description="Wechat webhook API token")
+    whatsapp_api_base_url: str = Field("https://waha.visafly.top", description="Whatsapp API base url")
+    whatsapp_api_key: str = Field("", description="Whatsapp API key")
+    whatsapp_session: str = Field("default", description="Whatsapp session")
 
     model_config = SettingsConfigDict(
         env_file=".env",

+ 6 - 1
app/schemas/telegram.py

@@ -7,4 +7,9 @@ class TelegramIn(BaseModel):
     chat_id: str
     api_token: str
     message: str
-    image: str    
+    image: str    
+
+
+class TelegramNoTokenIn(BaseModel):
+    chat_id: str
+    message: str

+ 4 - 0
app/schemas/wechat.py

@@ -6,3 +6,7 @@ from datetime import datetime
 class WechatIn(BaseModel):
     api_token: str
     message: str
+
+
+class WechatNoTokenIn(BaseModel):
+    message: str

+ 5 - 0
app/schemas/whatsapp.py

@@ -8,3 +8,8 @@ class WhatsappIn(BaseModel):
     message: str
     api_base_url: Optional[str] = None
     api_key: Optional[str] = None
+
+
+class WhatsappNoTokenIn(BaseModel):
+    chat_id: str
+    message: str

+ 26 - 1
app/services/telegram_service.py

@@ -2,12 +2,15 @@
 
 import aiohttp
 from app.core.biz_exception import BizLogicError
-from app.schemas.telegram import TelegramIn
+from app.core.config import settings
+from app.schemas.telegram import TelegramIn, TelegramNoTokenIn
 
 class TelegramService:
 
     @staticmethod
     async def push_text(payload: TelegramIn):
+        if not payload.api_token:
+            raise BizLogicError("Telegram api_token missing")
         url = f"https://api.telegram.org/bot{payload.api_token}/sendMessage"
 
         body = {
@@ -24,3 +27,25 @@ class TelegramService:
                     raise BizLogicError(
                         f"Telegram push failed: {resp.status}, {text}"
                     )
+
+    @staticmethod
+    async def push_text_no_token(payload: TelegramNoTokenIn):
+        api_token = settings.telegram_api_token
+        if not api_token:
+            raise BizLogicError("Telegram api_token missing in env")
+        url = f"https://api.telegram.org/bot{api_token}/sendMessage"
+
+        body = {
+            "chat_id": payload.chat_id,
+            "text": payload.message,
+            "parse_mode": "HTML",
+        }
+
+        timeout = aiohttp.ClientTimeout(total=10)
+        async with aiohttp.ClientSession(timeout=timeout) as client:
+            async with client.post(url, json=body) as resp:
+                if resp.status != 200:
+                    text = await resp.text()
+                    raise BizLogicError(
+                        f"Telegram push failed: {resp.status}, {text}"
+                    )

+ 15 - 0
app/services/wechat_service.py

@@ -1,6 +1,7 @@
 import aiohttp
 from typing import Dict, Any
 from app.core.biz_exception import BizLogicError
+from app.core.config import settings
 
 class WechatService:
     
@@ -46,3 +47,17 @@ class WechatService:
             }
         }
         return await WechatService._send_webhook(api_token, body)
+
+    @staticmethod
+    async def push_text_no_token(content: str):
+        api_token = settings.wechat_api_token
+        if not api_token:
+            raise BizLogicError("Wechat api_token missing in settings")
+        return await WechatService.push_text(api_token, content)
+
+    @staticmethod
+    async def push_markdown_no_token(content: str):
+        api_token = settings.wechat_api_token
+        if not api_token:
+            raise BizLogicError("Wechat api_token missing in settings")
+        return await WechatService.push_markdown(api_token, content)

+ 17 - 0
app/services/whatsapp_service.py

@@ -1,6 +1,7 @@
 import aiohttp
 from typing import Optional
 from app.core.biz_exception import BizLogicError
+from app.core.config import settings
 
 
 class WhatsappService:
@@ -44,3 +45,19 @@ class WhatsappService:
             raise BizLogicError(f"Whatsapp push request error: {e}")
 
         return True
+
+    @staticmethod
+    async def send_text_no_token(
+        chat_id: str,
+        message: str,
+    ):
+        api_base_url = settings.whatsapp_api_base_url
+        api_key = settings.whatsapp_api_key or None
+        session = settings.whatsapp_session
+        return await WhatsappService.send_text(
+            api_base_url=api_base_url,
+            session=session,
+            chat_id=chat_id,
+            message=message,
+            api_key=api_key,
+        )

+ 7 - 15
scripts/iris.py

@@ -14,11 +14,6 @@ API_BASE_URL = "https://visafly.top"
 BEARER_TOKEN = "tok_e946329a60ff45ba807f3f41b0e8b7fc"
 MAX_ATTEMPTS = 5
 
-DEFAULT_TG_TOKEN = "6771183256:AAEd0Tenq4z6hk5toUGrCpEVPfP00bpYT1s"
-DEFAULT_WECHAT_TOKEN = "a8f79817-e18b-4739-8459-adb2ed5e2e32"
-DEFAULT_WA_API_KEY = "51fc877539064f5882fae0f6f0661123"
-DEFAULT_WA_SESSION = "default"
-
 logging.basicConfig(level=logging.INFO, format='%(asctime)s [%(levelname)s] %(message)s')
 logger = logging.getLogger("Iris")
 
@@ -131,9 +126,8 @@ class IrisWorker:
     async def send_wechat(self, task_payload: Dict) -> bool:
         try:
             content = render_wechat_markdown(task_payload.get("template_id"), task_payload.get("payload", {}))
-            api_token = task_payload.get("api_token") or DEFAULT_WECHAT_TOKEN
-            async with self.session.post(f"{API_BASE_URL}/api/wechat/send_markdown", 
-                                       json={"api_token": api_token, "message": content}) as resp:
+            async with self.session.post(f"{API_BASE_URL}/api/wechat/send_markdown_no_token", 
+                                       json={"message": content}) as resp:
                 if resp.status == 200: return True
                 await self._log_response_error(resp, "WeChat Dispatch")
                 return False
@@ -144,12 +138,11 @@ class IrisWorker:
     async def send_whatsapp(self, task_payload: Dict) -> bool:
         try:
             content = render_whatsapp_text(task_payload.get("template_id"), task_payload.get("payload", {}))
-            api_key = task_payload.get("api_key") or DEFAULT_WA_API_KEY
             recs = task_payload.get("receivers", [])
             success = True
             for r in recs:
-                data = {"session": DEFAULT_WA_SESSION, "chat_id": r, "message": content, "api_key": api_key}
-                async with self.session.post(f"{API_BASE_URL}/api/whatsapp/send", json=data) as resp:
+                data = {"chat_id": r, "message": content}
+                async with self.session.post(f"{API_BASE_URL}/api/whatsapp/send_no_token", json=data) as resp:
                     if resp.status != 200:
                         await self._log_response_error(resp, f"WhatsApp to {r}")
                         success = False
@@ -162,11 +155,10 @@ class IrisWorker:
         try:
             data = task_payload.get("payload", {})
             content = render_telegram_html(task_payload.get("template_id"), data)
-            api_token = task_payload.get("api_token") or DEFAULT_TG_TOKEN
             chat_id = task_payload.get("chat_id") or data.get("chat_id")
             if not chat_id: return False
-            async with self.session.post(f"{API_BASE_URL}/api/tg/send_message", 
-                                       json={"chat_id": str(chat_id), "api_token": api_token, "message": content}) as resp:
+            async with self.session.post(f"{API_BASE_URL}/api/tg/send_message_no_token", 
+                                       json={"chat_id": str(chat_id), "message": content}) as resp:
                 if resp.status == 200: return True
                 await self._log_response_error(resp, "Telegram Dispatch")
                 return False
@@ -238,4 +230,4 @@ if __name__ == "__main__":
     except KeyboardInterrupt:
         logger.info("Iris stopped by user.")
     except Exception:
-        logger.critical(f"Iris Engine Crashed: {traceback.format_exc()}")
+        logger.critical(f"Iris Engine Crashed: {traceback.format_exc()}")