80 lines
2.8 KiB
Python
80 lines
2.8 KiB
Python
|
|
"""Tencent Cloud SMS adapter — implements SmsSender port."""
|
||
|
|
|
||
|
|
from app.core.logging import get_logger
|
||
|
|
|
||
|
|
from tencentcloud.common import credential
|
||
|
|
from tencentcloud.common.exception.tencent_cloud_sdk_exception import (
|
||
|
|
TencentCloudSDKException,
|
||
|
|
)
|
||
|
|
from tencentcloud.sms.v20210111 import models as sms_models
|
||
|
|
from tencentcloud.sms.v20210111 import sms_client
|
||
|
|
|
||
|
|
logger = get_logger(__name__)
|
||
|
|
|
||
|
|
CODE_EXPIRE_MINUTES = 5
|
||
|
|
|
||
|
|
|
||
|
|
class TencentSmsSender:
|
||
|
|
def __init__(
|
||
|
|
self,
|
||
|
|
secret_id: str,
|
||
|
|
secret_key: str,
|
||
|
|
sdk_app_id: str,
|
||
|
|
sign_name: str,
|
||
|
|
template_id: str,
|
||
|
|
template_param_count: int = 2,
|
||
|
|
):
|
||
|
|
self._secret_id = secret_id
|
||
|
|
self._secret_key = secret_key
|
||
|
|
self._sdk_app_id = sdk_app_id
|
||
|
|
self._sign_name = sign_name
|
||
|
|
self._template_id = template_id
|
||
|
|
self._template_param_count = template_param_count
|
||
|
|
|
||
|
|
def send_verification_code(self, phone: str, code: str) -> bool:
|
||
|
|
if not self._secret_id or not self._secret_key:
|
||
|
|
logger.error("Tencent SMS credentials not configured")
|
||
|
|
return False
|
||
|
|
|
||
|
|
cred = credential.Credential(self._secret_id, self._secret_key)
|
||
|
|
client = sms_client.SmsClient(cred, "ap-guangzhou")
|
||
|
|
|
||
|
|
param_configs = [
|
||
|
|
[code, str(CODE_EXPIRE_MINUTES)],
|
||
|
|
[code],
|
||
|
|
]
|
||
|
|
if self._template_param_count == 1:
|
||
|
|
param_configs = [[code], [code, str(CODE_EXPIRE_MINUTES)]]
|
||
|
|
|
||
|
|
for template_params in param_configs:
|
||
|
|
try:
|
||
|
|
req = sms_models.SendSmsRequest()
|
||
|
|
req.SmsSdkAppId = self._sdk_app_id
|
||
|
|
req.SignName = self._sign_name
|
||
|
|
req.TemplateId = self._template_id
|
||
|
|
req.TemplateParamSet = template_params
|
||
|
|
req.PhoneNumberSet = [f"+86{phone}"]
|
||
|
|
|
||
|
|
resp = client.SendSms(req)
|
||
|
|
if resp.SendStatusSet and resp.SendStatusSet[0].Code == "Ok":
|
||
|
|
return True
|
||
|
|
|
||
|
|
status = resp.SendStatusSet[0] if resp.SendStatusSet else None
|
||
|
|
error_code = status.Code if status else "UNKNOWN"
|
||
|
|
if "TemplateParamSetNotMatchApprovedTemplate" in error_code:
|
||
|
|
continue
|
||
|
|
logger.error("SMS send failed: %s - %s", error_code, status.Message if status else "")
|
||
|
|
return False
|
||
|
|
|
||
|
|
except TencentCloudSDKException as e:
|
||
|
|
if "TemplateParamSetNotMatchApprovedTemplate" in str(e):
|
||
|
|
continue
|
||
|
|
logger.error("Tencent SMS SDK error: %s", e)
|
||
|
|
return False
|
||
|
|
except Exception as e:
|
||
|
|
logger.error("SMS send exception: %s", e)
|
||
|
|
return False
|
||
|
|
|
||
|
|
logger.error("All SMS template param configs failed")
|
||
|
|
return False
|