mirror of
https://gitee.com/dromara/sms4j.git
synced 2025-12-07 01:18:33 +08:00
!77 短信发送返回值添加属性:本次发送使用的配置标识
Merge pull request !77 from handy/dev-3.0.x
This commit is contained in:
commit
4ff01c76ad
4
pom.xml
4
pom.xml
@ -50,7 +50,7 @@
|
|||||||
</scm>
|
</scm>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
<revision>2.2.0</revision>
|
<revision>3.0.0</revision>
|
||||||
|
|
||||||
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
|
||||||
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
|
||||||
@ -58,7 +58,7 @@
|
|||||||
<solon.version>2.2.0</solon.version>
|
<solon.version>2.2.0</solon.version>
|
||||||
<redisson.version>3.17.0</redisson.version>
|
<redisson.version>3.17.0</redisson.version>
|
||||||
<jdcloud.version>1.3.3</jdcloud.version>
|
<jdcloud.version>1.3.3</jdcloud.version>
|
||||||
<hutool.version>5.8.18</hutool.version>
|
<hutool.version>5.8.20</hutool.version>
|
||||||
<xmlblend.version>2.3.0</xmlblend.version>
|
<xmlblend.version>2.3.0</xmlblend.version>
|
||||||
<activation.version>1.1.1</activation.version>
|
<activation.version>1.1.1</activation.version>
|
||||||
<mail.version>1.6.2</mail.version>
|
<mail.version>1.6.2</mail.version>
|
||||||
|
|||||||
@ -25,4 +25,11 @@ public class SmsResponse {
|
|||||||
* @since 2.3.0
|
* @since 2.3.0
|
||||||
*/
|
*/
|
||||||
private Object data;
|
private Object data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置标识名 如未配置取对应渠道名例如 Alibaba
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
private String configId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -38,7 +38,14 @@ public class BaseConfig {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 权重
|
* 权重
|
||||||
* */
|
*/
|
||||||
@Builder.Default
|
@Builder.Default
|
||||||
private Integer weight = 1;
|
private Integer weight = 1;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置标识名 如未配置取对应渠道名例如 Alibaba
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
private String configId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,36 +0,0 @@
|
|||||||
package org.dromara.sms4j.core;
|
|
||||||
|
|
||||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
|
||||||
import org.dromara.sms4j.comm.exception.SmsBlendException;
|
|
||||||
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class ReflectUtil {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 反射获取接口对象的原类名
|
|
||||||
*/
|
|
||||||
public static String getObjectName(SupplierConfig parameter) {
|
|
||||||
return parameter.getClass().getTypeName();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 将对象的属性和属性值变为map
|
|
||||||
* */
|
|
||||||
public static Map<String, String> getValues(SupplierConfig parameter) {
|
|
||||||
try {
|
|
||||||
Map<String ,String> map = new HashMap<>();
|
|
||||||
Class<?> clazz = Class.forName(getObjectName(parameter));
|
|
||||||
Field[] declaredFields = clazz.getDeclaredFields();
|
|
||||||
for (Field declaredField : declaredFields) {
|
|
||||||
declaredField.setAccessible(true);
|
|
||||||
map.put(declaredField.getName(), (String) declaredField.get(parameter));
|
|
||||||
}
|
|
||||||
return map;
|
|
||||||
} catch (Exception e) {
|
|
||||||
throw new SmsBlendException(e.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,10 +1,8 @@
|
|||||||
package org.dromara.sms4j.core.load;
|
package org.dromara.sms4j.core.load;
|
||||||
|
|
||||||
|
import cn.hutool.core.bean.BeanUtil;
|
||||||
import org.dromara.sms4j.api.SmsBlend;
|
import org.dromara.sms4j.api.SmsBlend;
|
||||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
|
||||||
import org.dromara.sms4j.core.ReflectUtil;
|
|
||||||
import org.dromara.sms4j.core.config.SupplierFactory;
|
|
||||||
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
import org.dromara.sms4j.provider.base.BaseProviderFactory;
|
||||||
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
import org.dromara.sms4j.provider.enumerate.SupplierType;
|
||||||
|
|
||||||
@ -16,6 +14,7 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* SmsLoad
|
* SmsLoad
|
||||||
* <p> 自定义的一个平滑加权负载服务,可以用于存放多个短信实现负载
|
* <p> 自定义的一个平滑加权负载服务,可以用于存放多个短信实现负载
|
||||||
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
* 2023/4/21 20:49
|
* 2023/4/21 20:49
|
||||||
**/
|
**/
|
||||||
@ -36,23 +35,25 @@ public class SmsLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* addLoadServer
|
* addLoadServer
|
||||||
* <p> 添加服务及其权重
|
* <p> 添加服务及其权重
|
||||||
* <p>添加权重应注意,不要把某个权重设置的与其他权重相差过大,否则容易出现无法负载,单一选择的情况
|
* <p>添加权重应注意,不要把某个权重设置的与其他权重相差过大,否则容易出现无法负载,单一选择的情况
|
||||||
|
*
|
||||||
* @param LoadServer 短信实现
|
* @param LoadServer 短信实现
|
||||||
* @param weight 权重
|
* @param weight 权重
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public void addLoadServer(SmsBlend LoadServer, int weight) {
|
public void addLoadServer(SmsBlend LoadServer, int weight) {
|
||||||
LoadServers.add(new LoadServer(LoadServer, weight, weight));
|
LoadServers.add(new LoadServer(LoadServer, weight, weight));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* removeLoadServer
|
* removeLoadServer
|
||||||
* <p>移除短信服务
|
* <p>移除短信服务
|
||||||
* @param LoadServer 要移除的服务
|
*
|
||||||
|
* @param LoadServer 要移除的服务
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public void removeLoadServer(SmsBlend LoadServer) {
|
public void removeLoadServer(SmsBlend LoadServer) {
|
||||||
for (int i = 0; i < LoadServers.size(); i++) {
|
for (int i = 0; i < LoadServers.size(); i++) {
|
||||||
if (LoadServers.get(i).getSmsServer().equals(LoadServer)) {
|
if (LoadServers.get(i).getSmsServer().equals(LoadServer)) {
|
||||||
@ -63,11 +64,12 @@ public class SmsLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* getLoadServer
|
* getLoadServer
|
||||||
* <p>根据负载算法获取一个可获取到的短信服务,这里获取到的服务必然是addLoadServer方法中添加过的服务,不会凭空出现
|
* <p>根据负载算法获取一个可获取到的短信服务,这里获取到的服务必然是addLoadServer方法中添加过的服务,不会凭空出现
|
||||||
|
*
|
||||||
* @return SmsBlend 短信实现
|
* @return SmsBlend 短信实现
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public synchronized SmsBlend getLoadServer() {
|
public synchronized SmsBlend getLoadServer() {
|
||||||
int totalWeight = 0;
|
int totalWeight = 0;
|
||||||
LoadServer selectedLoadServer = null;
|
LoadServer selectedLoadServer = null;
|
||||||
@ -91,19 +93,22 @@ public class SmsLoad {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* starConfig
|
* starConfig
|
||||||
* <p> 创建smsBlend并加入到负载均衡器
|
* <p> 创建smsBlend并加入到负载均衡器
|
||||||
|
*
|
||||||
* @param supplierConfig 厂商配置
|
* @param supplierConfig 厂商配置
|
||||||
* @param supplierType 厂商枚举
|
* @param supplierType 厂商枚举
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public static void starConfig(SupplierConfig supplierConfig, SupplierType supplierType){
|
public static void starConfig(SupplierConfig supplierConfig, SupplierType supplierType) {
|
||||||
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
BaseProviderFactory providerFactory = supplierType.getProviderFactory();
|
||||||
SmsBlend smsBlend = providerFactory.createMultitonSms(supplierConfig);
|
SmsBlend smsBlend = providerFactory.createMultitonSms(supplierConfig);
|
||||||
smsLoad.addLoadServer(smsBlend, Integer.parseInt(ReflectUtil.getValues(supplierConfig).get("weight")));
|
Map<String, Object> supplierConfigMap = BeanUtil.beanToMap(supplierConfig);
|
||||||
|
Object weight = supplierConfigMap.getOrDefault("weight", 1);
|
||||||
|
smsLoad.addLoadServer(smsBlend, Integer.parseInt(weight.toString()));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static SmsLoad getBeanLoad(){
|
public static SmsLoad getBeanLoad() {
|
||||||
return smsLoad;
|
return smsLoad;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,7 +28,7 @@ import java.util.concurrent.Executor;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class AlibabaSmsImpl extends AbstractSmsBlend {
|
public class AlibabaSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final AlibabaConfig alibabaSmsConfig;
|
private final AlibabaConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AlibabaSmsImpl
|
* AlibabaSmsImpl
|
||||||
@ -36,17 +36,17 @@ public class AlibabaSmsImpl extends AbstractSmsBlend {
|
|||||||
*
|
*
|
||||||
* @author :Wind
|
* @author :Wind
|
||||||
*/
|
*/
|
||||||
public AlibabaSmsImpl(AlibabaConfig alibabaSmsConfig, Executor pool, DelayedTime delayedTime) {
|
public AlibabaSmsImpl(AlibabaConfig config, Executor pool, DelayedTime delayedTime) {
|
||||||
super(pool, delayedTime);
|
super(pool, delayedTime);
|
||||||
this.alibabaSmsConfig = alibabaSmsConfig;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse sendMessage(String phone, String message) {
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(alibabaSmsConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return sendMessage(phone, alibabaSmsConfig.getTemplateId(), map);
|
return sendMessage(phone, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -60,8 +60,8 @@ public class AlibabaSmsImpl extends AbstractSmsBlend {
|
|||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(alibabaSmsConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return massTexting(phones, alibabaSmsConfig.getTemplateId(), map);
|
return massTexting(phones, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -75,8 +75,8 @@ public class AlibabaSmsImpl extends AbstractSmsBlend {
|
|||||||
String requestUrl;
|
String requestUrl;
|
||||||
String paramStr;
|
String paramStr;
|
||||||
try {
|
try {
|
||||||
requestUrl = AliyunUtils.generateSendSmsRequestUrl(this.alibabaSmsConfig, message, phone, templateId);
|
requestUrl = AliyunUtils.generateSendSmsRequestUrl(this.config, message, phone, templateId);
|
||||||
paramStr = AliyunUtils.generateParamBody(alibabaSmsConfig, phone, message, templateId);
|
paramStr = AliyunUtils.generateParamBody(config, phone, message, templateId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("aliyun send message error", e);
|
log.error("aliyun send message error", e);
|
||||||
throw new SmsBlendException(e.getMessage());
|
throw new SmsBlendException(e.getMessage());
|
||||||
@ -95,6 +95,7 @@ public class AlibabaSmsImpl extends AbstractSmsBlend {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess("OK".equals(resJson.getStr("Code")));
|
smsResponse.setSuccess("OK".equals(resJson.getStr("Code")));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -51,6 +51,7 @@ public class CloopenHelper {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess("000000".equals(resJson.getStr("statusCode")));
|
smsResponse.setSuccess("000000".equals(resJson.getStr("statusCode")));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,19 +28,19 @@ import java.util.concurrent.Executor;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class CtyunSmsImpl extends AbstractSmsBlend {
|
public class CtyunSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final CtyunConfig ctyunConfig;
|
private final CtyunConfig config;
|
||||||
|
|
||||||
public CtyunSmsImpl(CtyunConfig ctyunConfig, Executor pool, DelayedTime delayedTime) {
|
public CtyunSmsImpl(CtyunConfig config, Executor pool, DelayedTime delayedTime) {
|
||||||
super(pool, delayedTime);
|
super(pool, delayedTime);
|
||||||
this.ctyunConfig = ctyunConfig;
|
this.config = config;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse sendMessage(String phone, String message) {
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(ctyunConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return sendMessage(phone, ctyunConfig.getTemplateId(), map);
|
return sendMessage(phone, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -54,8 +54,8 @@ public class CtyunSmsImpl extends AbstractSmsBlend {
|
|||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(ctyunConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return massTexting(phones, ctyunConfig.getTemplateId(), map);
|
return massTexting(phones, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -69,15 +69,15 @@ public class CtyunSmsImpl extends AbstractSmsBlend {
|
|||||||
String requestUrl;
|
String requestUrl;
|
||||||
String paramStr;
|
String paramStr;
|
||||||
try {
|
try {
|
||||||
requestUrl = ctyunConfig.getRequestUrl();
|
requestUrl = config.getRequestUrl();
|
||||||
paramStr = CtyunUtils.generateParamJsonStr(ctyunConfig, phone, message, templateId);
|
paramStr = CtyunUtils.generateParamJsonStr(config, phone, message, templateId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("ctyun send message error", e);
|
log.error("ctyun send message error", e);
|
||||||
throw new SmsBlendException(e.getMessage());
|
throw new SmsBlendException(e.getMessage());
|
||||||
}
|
}
|
||||||
log.debug("requestUrl {}", requestUrl);
|
log.debug("requestUrl {}", requestUrl);
|
||||||
try(HttpResponse response = HttpRequest.post(requestUrl)
|
try(HttpResponse response = HttpRequest.post(requestUrl)
|
||||||
.addHeaders(CtyunUtils.signHeader(paramStr, ctyunConfig.getAccessKeyId(), ctyunConfig.getAccessKeySecret()))
|
.addHeaders(CtyunUtils.signHeader(paramStr, config.getAccessKeyId(), config.getAccessKeySecret()))
|
||||||
.body(paramStr)
|
.body(paramStr)
|
||||||
.execute()){
|
.execute()){
|
||||||
JSONObject body = JSONUtil.parseObj(response.body());
|
JSONObject body = JSONUtil.parseObj(response.body());
|
||||||
@ -89,6 +89,7 @@ public class CtyunSmsImpl extends AbstractSmsBlend {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess("OK".equals(resJson.getStr("code")));
|
smsResponse.setSuccess("OK".equals(resJson.getStr("code")));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -23,4 +23,11 @@ public class EmayConfig implements SupplierConfig {
|
|||||||
private String secretKey ;
|
private String secretKey ;
|
||||||
/** APP接入地址*/
|
/** APP接入地址*/
|
||||||
private String requestUrl;
|
private String requestUrl;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置标识名 如未配置取对应渠道名例如 Alibaba
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
private String configId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,6 +94,7 @@ public class EmaySmsImpl extends AbstractSmsBlend {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess("success".equalsIgnoreCase(resJson.getStr("code")));
|
smsResponse.setSuccess("success".equalsIgnoreCase(resJson.getStr("code")));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -28,4 +28,11 @@ public class HuaweiConfig implements SupplierConfig {
|
|||||||
private String statusCallBack;
|
private String statusCallBack;
|
||||||
/** APP接入地址*/
|
/** APP接入地址*/
|
||||||
private String url;
|
private String url;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 配置标识名 如未配置取对应渠道名例如 Alibaba
|
||||||
|
*
|
||||||
|
* @since 3.0.0
|
||||||
|
*/
|
||||||
|
private String configId;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -78,6 +78,7 @@ public class HuaweiSmsImpl extends AbstractSmsBlend {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess("000000".equals(resJson.getStr("Code")));
|
smsResponse.setSuccess("000000".equals(resJson.getStr("Code")));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -87,6 +87,7 @@ public class JdCloudSmsImpl extends AbstractSmsBlend {
|
|||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
smsResponse.setSuccess(res.getStatus() != null && res.getStatus());
|
smsResponse.setSuccess(res.getStatus() != null && res.getStatus());
|
||||||
smsResponse.setData(res);
|
smsResponse.setData(res);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -118,10 +118,11 @@ public class NeteaseSmsImpl extends AbstractSmsBlend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getResponse(JSONObject jsonObject) {
|
private SmsResponse getResponse(JSONObject jsonObject) {
|
||||||
SmsResponse response = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
response.setSuccess(jsonObject.getInt("code") <= 200);
|
smsResponse.setSuccess(jsonObject.getInt("code") <= 200);
|
||||||
response.setData(jsonObject);
|
smsResponse.setData(jsonObject);
|
||||||
return response;
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -28,11 +28,11 @@ import java.util.concurrent.Executor;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class TencentSmsImpl extends AbstractSmsBlend {
|
public class TencentSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final TencentConfig tencentSmsConfig;
|
private final TencentConfig config;
|
||||||
|
|
||||||
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
|
public TencentSmsImpl(TencentConfig tencentSmsConfig, Executor pool, DelayedTime delayed) {
|
||||||
super(pool, delayed);
|
super(pool, delayed);
|
||||||
this.tencentSmsConfig = tencentSmsConfig;
|
this.config = tencentSmsConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -43,7 +43,7 @@ public class TencentSmsImpl extends AbstractSmsBlend {
|
|||||||
for (int i = 0; i < split.length; i++) {
|
for (int i = 0; i < split.length; i++) {
|
||||||
map.put(String.valueOf(i), split[i]);
|
map.put(String.valueOf(i), split[i]);
|
||||||
}
|
}
|
||||||
return sendMessage(phone, tencentSmsConfig.getTemplateId(), map);
|
return sendMessage(phone, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -65,7 +65,7 @@ public class TencentSmsImpl extends AbstractSmsBlend {
|
|||||||
for (int i = 0; i < split.length; i++) {
|
for (int i = 0; i < split.length; i++) {
|
||||||
map.put(String.valueOf(i), split[i]);
|
map.put(String.valueOf(i), split[i]);
|
||||||
}
|
}
|
||||||
return massTexting(phones, tencentSmsConfig.getTemplateId(), map);
|
return massTexting(phones, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -83,16 +83,16 @@ public class TencentSmsImpl extends AbstractSmsBlend {
|
|||||||
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
String timestamp = String.valueOf(System.currentTimeMillis() / 1000);
|
||||||
String signature;
|
String signature;
|
||||||
try {
|
try {
|
||||||
signature = TencentUtils.generateSignature(this.tencentSmsConfig, templateId, messages, phones, timestamp);
|
signature = TencentUtils.generateSignature(this.config, templateId, messages, phones, timestamp);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.error("tencent send message error", e);
|
log.error("tencent send message error", e);
|
||||||
throw new SmsBlendException(e.getMessage());
|
throw new SmsBlendException(e.getMessage());
|
||||||
}
|
}
|
||||||
Map<String, String> headsMap = TencentUtils.generateHeadsMap(signature, timestamp, tencentSmsConfig.getAction(),
|
Map<String, String> headsMap = TencentUtils.generateHeadsMap(signature, timestamp, config.getAction(),
|
||||||
tencentSmsConfig.getVersion(), tencentSmsConfig.getTerritory(), tencentSmsConfig.getRequestUrl());
|
config.getVersion(), config.getTerritory(), config.getRequestUrl());
|
||||||
Map<String, Object> requestBody = TencentUtils.generateRequestBody(phones, tencentSmsConfig.getSdkAppId(),
|
Map<String, Object> requestBody = TencentUtils.generateRequestBody(phones, config.getSdkAppId(),
|
||||||
tencentSmsConfig.getSignature(), templateId, messages);
|
config.getSignature(), templateId, messages);
|
||||||
String url = Constant.HTTPS_PREFIX + tencentSmsConfig.getRequestUrl();
|
String url = Constant.HTTPS_PREFIX + config.getRequestUrl();
|
||||||
try(HttpResponse response = HttpRequest.post(url)
|
try(HttpResponse response = HttpRequest.post(url)
|
||||||
.addHeaders(headsMap)
|
.addHeaders(headsMap)
|
||||||
.body(JSONUtil.toJsonStr(requestBody))
|
.body(JSONUtil.toJsonStr(requestBody))
|
||||||
@ -108,6 +108,7 @@ public class TencentSmsImpl extends AbstractSmsBlend {
|
|||||||
String error = response.getStr("Error");
|
String error = response.getStr("Error");
|
||||||
smsResponse.setSuccess(StringUtils.isBlank(error));
|
smsResponse.setSuccess(StringUtils.isBlank(error));
|
||||||
smsResponse.setData(resJson);
|
smsResponse.setData(resJson);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -87,6 +87,7 @@ public class UniSmsImpl extends AbstractSmsBlend {
|
|||||||
UniResponse send = Uni.getClient().request("sms.message.send", data);
|
UniResponse send = Uni.getClient().request("sms.message.send", data);
|
||||||
smsResponse.setSuccess("Success".equals(send.message));
|
smsResponse.setSuccess("Success".equals(send.message));
|
||||||
smsResponse.setData(send);
|
smsResponse.setData(send);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
smsResponse.setSuccess(false);
|
smsResponse.setSuccess(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -31,7 +31,7 @@ public class YunPianSmsImpl extends AbstractSmsBlend {
|
|||||||
|
|
||||||
private final YunpianConfig config;
|
private final YunpianConfig config;
|
||||||
|
|
||||||
private static SmsResponse getResponse(JSONObject execute) {
|
private SmsResponse getResponse(JSONObject execute) {
|
||||||
SmsResponse smsResponse = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
if (execute == null) {
|
if (execute == null) {
|
||||||
smsResponse.setSuccess(false);
|
smsResponse.setSuccess(false);
|
||||||
@ -39,6 +39,7 @@ public class YunPianSmsImpl extends AbstractSmsBlend {
|
|||||||
}
|
}
|
||||||
smsResponse.setSuccess(execute.getInt("code") == 0);
|
smsResponse.setSuccess(execute.getInt("code") == 0);
|
||||||
smsResponse.setData(execute);
|
smsResponse.setData(execute);
|
||||||
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
return smsResponse;
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,10 @@
|
|||||||
package org.dromara.sms4j.zhutong.config;
|
package org.dromara.sms4j.zhutong.config;
|
||||||
|
|
||||||
import lombok.*;
|
import lombok.Builder;
|
||||||
|
import lombok.Getter;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import lombok.Setter;
|
||||||
|
import lombok.ToString;
|
||||||
import lombok.experimental.SuperBuilder;
|
import lombok.experimental.SuperBuilder;
|
||||||
import org.dromara.sms4j.api.universal.SupplierConfig;
|
import org.dromara.sms4j.api.universal.SupplierConfig;
|
||||||
import org.dromara.sms4j.comm.config.BaseConfig;
|
import org.dromara.sms4j.comm.config.BaseConfig;
|
||||||
|
|||||||
@ -33,7 +33,7 @@ import java.util.concurrent.Executor;
|
|||||||
@Slf4j
|
@Slf4j
|
||||||
public class ZhutongSmsImpl extends AbstractSmsBlend {
|
public class ZhutongSmsImpl extends AbstractSmsBlend {
|
||||||
|
|
||||||
private final ZhutongConfig zhutongConfig;
|
private final ZhutongConfig config;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ZhutongSmsImpl
|
* ZhutongSmsImpl
|
||||||
@ -41,20 +41,20 @@ public class ZhutongSmsImpl extends AbstractSmsBlend {
|
|||||||
*/
|
*/
|
||||||
public ZhutongSmsImpl(ZhutongConfig zhutongConfig, Executor pool, DelayedTime delayedTime) {
|
public ZhutongSmsImpl(ZhutongConfig zhutongConfig, Executor pool, DelayedTime delayedTime) {
|
||||||
super(pool, delayedTime);
|
super(pool, delayedTime);
|
||||||
this.zhutongConfig = zhutongConfig;
|
this.config = zhutongConfig;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse sendMessage(String phone, String message) {
|
public SmsResponse sendMessage(String phone, String message) {
|
||||||
//如果模板id为空 or 模板变量名称为空,使用无模板的自定义短信发送
|
//如果模板id为空 or 模板变量名称为空,使用无模板的自定义短信发送
|
||||||
if (StrUtil.hasBlank(zhutongConfig.getSignature(), zhutongConfig.getTemplateId(), zhutongConfig.getTemplateName())) {
|
if (StrUtil.hasBlank(config.getSignature(), config.getTemplateId(), config.getTemplateName())) {
|
||||||
return getSmsResponse(phone, message);
|
return getSmsResponse(phone, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(zhutongConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return sendMessage(phone, zhutongConfig.getTemplateId(), map);
|
return sendMessage(phone, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -67,13 +67,13 @@ public class ZhutongSmsImpl extends AbstractSmsBlend {
|
|||||||
@Restricted
|
@Restricted
|
||||||
public SmsResponse massTexting(List<String> phones, String message) {
|
public SmsResponse massTexting(List<String> phones, String message) {
|
||||||
//如果模板id为空 or 模板变量名称为空,使用无模板的自定义短信发送
|
//如果模板id为空 or 模板变量名称为空,使用无模板的自定义短信发送
|
||||||
if (StrUtil.hasBlank(zhutongConfig.getSignature(), zhutongConfig.getTemplateId(), zhutongConfig.getTemplateName())) {
|
if (StrUtil.hasBlank(config.getSignature(), config.getTemplateId(), config.getTemplateName())) {
|
||||||
return getSmsResponse(phones, message);
|
return getSmsResponse(phones, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
LinkedHashMap<String, String> map = new LinkedHashMap<>();
|
||||||
map.put(zhutongConfig.getTemplateName(), message);
|
map.put(config.getTemplateName(), message);
|
||||||
return massTexting(phones, zhutongConfig.getTemplateId(), map);
|
return massTexting(phones, config.getTemplateId(), map);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -86,9 +86,9 @@ public class ZhutongSmsImpl extends AbstractSmsBlend {
|
|||||||
* 发送 自定义短信:https://doc.zthysms.com/web/#/1/14
|
* 发送 自定义短信:https://doc.zthysms.com/web/#/1/14
|
||||||
*/
|
*/
|
||||||
protected SmsResponse getSmsResponse(List<String> phones, String content) {
|
protected SmsResponse getSmsResponse(List<String> phones, String content) {
|
||||||
String requestUrl = zhutongConfig.getRequestUrl();
|
String requestUrl = config.getRequestUrl();
|
||||||
String username = zhutongConfig.getAccessKeyId();
|
String username = config.getAccessKeyId();
|
||||||
String password = zhutongConfig.getAccessKeySecret();
|
String password = config.getAccessKeySecret();
|
||||||
|
|
||||||
validator(requestUrl, username, password);
|
validator(requestUrl, username, password);
|
||||||
if (CollectionUtil.isEmpty(phones)) {
|
if (CollectionUtil.isEmpty(phones)) {
|
||||||
@ -139,10 +139,10 @@ public class ZhutongSmsImpl extends AbstractSmsBlend {
|
|||||||
* 发送 模板短信:https://doc.zthysms.com/web/#/1/13
|
* 发送 模板短信:https://doc.zthysms.com/web/#/1/13
|
||||||
*/
|
*/
|
||||||
protected SmsResponse getSmsResponseTemplate(String templateId, List<String> phones, LinkedHashMap<String, String> messages) {
|
protected SmsResponse getSmsResponseTemplate(String templateId, List<String> phones, LinkedHashMap<String, String> messages) {
|
||||||
String requestUrl = zhutongConfig.getRequestUrl();
|
String requestUrl = config.getRequestUrl();
|
||||||
String username = zhutongConfig.getAccessKeyId();
|
String username = config.getAccessKeyId();
|
||||||
String password = zhutongConfig.getAccessKeySecret();
|
String password = config.getAccessKeySecret();
|
||||||
String signature = zhutongConfig.getSignature();
|
String signature = config.getSignature();
|
||||||
|
|
||||||
validator(requestUrl, username, password);
|
validator(requestUrl, username, password);
|
||||||
if (StrUtil.isBlank(signature)) {
|
if (StrUtil.isBlank(signature)) {
|
||||||
@ -208,10 +208,11 @@ public class ZhutongSmsImpl extends AbstractSmsBlend {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SmsResponse getResponse(JSONObject jsonObject) {
|
private SmsResponse getResponse(JSONObject jsonObject) {
|
||||||
SmsResponse response = new SmsResponse();
|
SmsResponse smsResponse = new SmsResponse();
|
||||||
response.setSuccess(jsonObject.getInt("code", -1) <= 200);
|
smsResponse.setSuccess(jsonObject.getInt("code", -1) <= 200);
|
||||||
response.setData(jsonObject);
|
smsResponse.setData(jsonObject);
|
||||||
return response;
|
smsResponse.setConfigId(this.config.getConfigId());
|
||||||
|
return smsResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void validator(String requestUrl, String username, String password) {
|
private void validator(String requestUrl, String username, String password) {
|
||||||
|
|||||||
@ -8,74 +8,76 @@ import org.dromara.sms4j.emay.config.EmayConfig;
|
|||||||
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
import org.dromara.sms4j.huawei.config.HuaweiConfig;
|
||||||
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
import org.dromara.sms4j.jdcloud.config.JdCloudConfig;
|
||||||
import org.dromara.sms4j.netease.config.NeteaseConfig;
|
import org.dromara.sms4j.netease.config.NeteaseConfig;
|
||||||
import org.dromara.sms4j.starter.utils.SmsSpringUtil;
|
|
||||||
import org.dromara.sms4j.tencent.config.TencentConfig;
|
import org.dromara.sms4j.tencent.config.TencentConfig;
|
||||||
import org.dromara.sms4j.unisms.config.UniConfig;
|
import org.dromara.sms4j.unisms.config.UniConfig;
|
||||||
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
import org.dromara.sms4j.yunpian.config.YunpianConfig;
|
||||||
import org.dromara.sms4j.zhutong.config.ZhutongConfig;
|
import org.dromara.sms4j.zhutong.config.ZhutongConfig;
|
||||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
|
||||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
public class SupplierConfig {
|
public class SupplierConfig {
|
||||||
|
|
||||||
|
|
||||||
/** 阿里差异化配置*/
|
/**
|
||||||
|
* 阿里差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.alibaba")
|
@ConfigurationProperties(prefix = "sms.alibaba")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "alibaba")
|
protected AlibabaConfig alibabaConfig() {
|
||||||
protected AlibabaConfig alibabaConfig(){
|
|
||||||
return SupplierFactory.getAlibabaConfig();
|
return SupplierFactory.getAlibabaConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 华为差异化配置*/
|
/**
|
||||||
|
* 华为差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.huawei")
|
@ConfigurationProperties(prefix = "sms.huawei")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "huawei")
|
protected HuaweiConfig huaweiConfig() {
|
||||||
protected HuaweiConfig huaweiConfig(){
|
|
||||||
return SupplierFactory.getHuaweiConfig();
|
return SupplierFactory.getHuaweiConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 云片短信差异化配置*/
|
/**
|
||||||
|
* 云片短信差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.yunpian")
|
@ConfigurationProperties(prefix = "sms.yunpian")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "yunpian")
|
protected YunpianConfig yunpianConfig() {
|
||||||
protected YunpianConfig yunpianConfig(){
|
|
||||||
return SupplierFactory.getYunpianConfig();
|
return SupplierFactory.getYunpianConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 合一短信差异化配置*/
|
/**
|
||||||
|
* 合一短信差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.uni")
|
@ConfigurationProperties(prefix = "sms.uni")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "uni")
|
protected UniConfig uniConfig() {
|
||||||
protected UniConfig uniConfig(){
|
|
||||||
return SupplierFactory.getUniConfig();
|
return SupplierFactory.getUniConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 腾讯短信差异化配置*/
|
/**
|
||||||
|
* 腾讯短信差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.tencent")
|
@ConfigurationProperties(prefix = "sms.tencent")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "tencent")
|
protected TencentConfig tencentConfig() {
|
||||||
protected TencentConfig tencentConfig(){
|
|
||||||
return SupplierFactory.getTencentConfig();
|
return SupplierFactory.getTencentConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 京东云短信差异化配置 */
|
/**
|
||||||
|
* 京东云短信差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.jdcloud")
|
@ConfigurationProperties(prefix = "sms.jdcloud")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "jdcloud")
|
protected JdCloudConfig jdCloudConfig() {
|
||||||
protected JdCloudConfig jdCloudConfig(){
|
|
||||||
return SupplierFactory.getJdCloudConfig();
|
return SupplierFactory.getJdCloudConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 容联云短信差异化配置 */
|
/**
|
||||||
|
* 容联云短信差异化配置
|
||||||
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.cloopen")
|
@ConfigurationProperties(prefix = "sms.cloopen")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "cloopen")
|
protected CloopenConfig cloopenConfig() {
|
||||||
protected CloopenConfig cloopenConfig(){
|
|
||||||
return SupplierFactory.getCloopenConfig();
|
return SupplierFactory.getCloopenConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,8 +86,7 @@ public class SupplierConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.emay")
|
@ConfigurationProperties(prefix = "sms.emay")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "emay")
|
protected EmayConfig emayConfig() {
|
||||||
protected EmayConfig emayConfig(){
|
|
||||||
return SupplierFactory.getEmayConfig();
|
return SupplierFactory.getEmayConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -94,8 +95,7 @@ public class SupplierConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.ctyun")
|
@ConfigurationProperties(prefix = "sms.ctyun")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "ctyun")
|
protected CtyunConfig ctyunConfig() {
|
||||||
protected CtyunConfig ctyunConfig(){
|
|
||||||
return SupplierFactory.getCtyunConfig();
|
return SupplierFactory.getCtyunConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -105,8 +105,7 @@ public class SupplierConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.netease")
|
@ConfigurationProperties(prefix = "sms.netease")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "netease")
|
protected NeteaseConfig neteaseConfig() {
|
||||||
protected NeteaseConfig neteaseConfig(){
|
|
||||||
return SupplierFactory.getNeteaseConfig();
|
return SupplierFactory.getNeteaseConfig();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -115,8 +114,7 @@ public class SupplierConfig {
|
|||||||
*/
|
*/
|
||||||
@Bean
|
@Bean
|
||||||
@ConfigurationProperties(prefix = "sms.zhutong")
|
@ConfigurationProperties(prefix = "sms.zhutong")
|
||||||
@ConditionalOnProperty(prefix = "sms", name = "zhutong")
|
protected ZhutongConfig zhutongConfig() {
|
||||||
protected ZhutongConfig zhutongConfig(){
|
|
||||||
return SupplierFactory.getZhutongConfig();
|
return SupplierFactory.getZhutongConfig();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user