"""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