mirror of
https://codeup.aliyun.com/67c68d4e484ca2f0a13ac3c1/ydc/jsowell-charger-web.git
synced 2026-05-08 20:10:16 +08:00
对接浙江平台
This commit is contained in:
@@ -1,10 +1,12 @@
|
|||||||
package com.jsowell.thirdparty.platform.domain;
|
package com.jsowell.thirdparty.platform.domain;
|
||||||
|
|
||||||
import com.alibaba.fastjson2.annotation.JSONField;
|
import com.alibaba.fastjson2.annotation.JSONField;
|
||||||
|
import com.jsowell.common.util.DateUtils;
|
||||||
import lombok.*;
|
import lombok.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 充电设备接口状态信息
|
* 充电设备接口状态信息
|
||||||
|
* 对充电设备接口实时状态对象的描述,包含充电设备接口编码、充电设备接口状态等。
|
||||||
*/
|
*/
|
||||||
@Getter
|
@Getter
|
||||||
@Setter
|
@Setter
|
||||||
@@ -74,14 +76,14 @@ public class SupConnectorStatusInfo {
|
|||||||
* 描述: 0:未知10:空闲50:占用
|
* 描述: 0:未知10:空闲50:占用
|
||||||
*/
|
*/
|
||||||
@JSONField(name = "ParkStatus")
|
@JSONField(name = "ParkStatus")
|
||||||
private String parkStatus;
|
private Integer parkStatus = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 名称: 地锁状态
|
* 名称: 地锁状态
|
||||||
* 描述: 0:未知10:已解锁50:已上锁
|
* 描述: 0:未知10:已解锁50:已上锁
|
||||||
*/
|
*/
|
||||||
@JSONField(name = "LockStatus")
|
@JSONField(name = "LockStatus")
|
||||||
private String lockStatus = "0";
|
private Integer lockStatus = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 名称: 电池状态
|
* 名称: 电池状态
|
||||||
@@ -102,5 +104,12 @@ public class SupConnectorStatusInfo {
|
|||||||
* 描述: 最近一次状态变化的时间,格式“yyyy-MM-ddHH:mm:ss”
|
* 描述: 最近一次状态变化的时间,格式“yyyy-MM-ddHH:mm:ss”
|
||||||
*/
|
*/
|
||||||
@JSONField(name = "LastChangeTime")
|
@JSONField(name = "LastChangeTime")
|
||||||
private String lastChangeTime;
|
private String lastChangeTime = DateUtils.getDateTime();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 状态更新时间
|
||||||
|
* 本次状态变化的时间,格式“yyyy-MM-dd HH:mm:ss”
|
||||||
|
*/
|
||||||
|
@JSONField(name = "UpdateTime")
|
||||||
|
private String UpdateTime = DateUtils.getDateTime();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -417,8 +417,8 @@ public class NeiMengGuPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
.equipmentClassification(Constants.ONE)
|
.equipmentClassification(Constants.ONE)
|
||||||
.status(Integer.parseInt(status))
|
.status(Integer.parseInt(status))
|
||||||
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
||||||
.parkStatus(Constants.ZERO)
|
.parkStatus(Constants.zero)
|
||||||
.lockStatus(Constants.ZERO)
|
.lockStatus(Constants.zero)
|
||||||
.batteryStatus(Constants.ZERO)
|
.batteryStatus(Constants.ZERO)
|
||||||
.batteryPackID("")
|
.batteryPackID("")
|
||||||
.lastChangeTime(DateUtils.getDateTime())
|
.lastChangeTime(DateUtils.getDateTime())
|
||||||
|
|||||||
@@ -379,8 +379,8 @@ public class NingXiaPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
.equipmentClassification(Constants.ONE)
|
.equipmentClassification(Constants.ONE)
|
||||||
.status(Integer.parseInt(status))
|
.status(Integer.parseInt(status))
|
||||||
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
||||||
.parkStatus(Constants.ZERO)
|
.parkStatus(Constants.zero)
|
||||||
.lockStatus(Constants.ZERO)
|
.lockStatus(Constants.zero)
|
||||||
.batteryStatus(Constants.ZERO)
|
.batteryStatus(Constants.ZERO)
|
||||||
.batteryPackID("")
|
.batteryPackID("")
|
||||||
.lastChangeTime(DateUtils.getDateTime())
|
.lastChangeTime(DateUtils.getDateTime())
|
||||||
@@ -427,8 +427,8 @@ public class NingXiaPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
.equipmentClassification(Constants.ONE)
|
.equipmentClassification(Constants.ONE)
|
||||||
.status(Integer.parseInt(status))
|
.status(Integer.parseInt(status))
|
||||||
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
||||||
.parkStatus(Constants.ZERO)
|
.parkStatus(Constants.zero)
|
||||||
.lockStatus(Constants.ZERO)
|
.lockStatus(Constants.zero)
|
||||||
.batteryStatus(Constants.ZERO)
|
.batteryStatus(Constants.ZERO)
|
||||||
.batteryPackID("")
|
.batteryPackID("")
|
||||||
.lastChangeTime(DateUtils.getDateTime())
|
.lastChangeTime(DateUtils.getDateTime())
|
||||||
|
|||||||
@@ -8,32 +8,41 @@ import com.google.common.collect.Lists;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import com.jsowell.common.constant.Constants;
|
import com.jsowell.common.constant.Constants;
|
||||||
import com.jsowell.common.enums.lianlian.StationPaymentEnum;
|
import com.jsowell.common.enums.lianlian.StationPaymentEnum;
|
||||||
|
import com.jsowell.common.enums.thirdparty.BusinessInformationExchangeEnum;
|
||||||
|
import com.jsowell.common.enums.thirdparty.ThirdPartyOperatorIdEnum;
|
||||||
import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum;
|
import com.jsowell.common.enums.thirdparty.ThirdPlatformTypeEnum;
|
||||||
|
import com.jsowell.common.enums.ykc.PileConnectorDataBaseStatusEnum;
|
||||||
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
import com.jsowell.common.enums.ykc.ReturnCodeEnum;
|
||||||
import com.jsowell.common.exception.BusinessException;
|
import com.jsowell.common.exception.BusinessException;
|
||||||
import com.jsowell.common.util.JWTUtils;
|
import com.jsowell.common.util.JWTUtils;
|
||||||
import com.jsowell.common.util.PageUtils;
|
import com.jsowell.common.util.PageUtils;
|
||||||
import com.jsowell.common.util.StringUtils;
|
import com.jsowell.common.util.StringUtils;
|
||||||
|
import com.jsowell.pile.domain.OrderBasicInfo;
|
||||||
import com.jsowell.pile.domain.PileStationInfo;
|
import com.jsowell.pile.domain.PileStationInfo;
|
||||||
|
import com.jsowell.pile.domain.ThirdPartyPlatformConfig;
|
||||||
|
import com.jsowell.pile.domain.ThirdPartyStationRelation;
|
||||||
|
import com.jsowell.pile.dto.QueryEquipChargeStatusDTO;
|
||||||
import com.jsowell.pile.dto.QueryOperatorInfoDTO;
|
import com.jsowell.pile.dto.QueryOperatorInfoDTO;
|
||||||
import com.jsowell.pile.dto.QueryStationInfoDTO;
|
import com.jsowell.pile.dto.QueryStationInfoDTO;
|
||||||
import com.jsowell.pile.service.PileBasicInfoService;
|
import com.jsowell.pile.service.*;
|
||||||
import com.jsowell.pile.service.PileMerchantInfoService;
|
|
||||||
import com.jsowell.pile.service.PileStationInfoService;
|
|
||||||
import com.jsowell.pile.service.ThirdPartyStationRelationService;
|
|
||||||
import com.jsowell.pile.thirdparty.CommonParamsDTO;
|
import com.jsowell.pile.thirdparty.CommonParamsDTO;
|
||||||
import com.jsowell.pile.thirdparty.EquipmentInfo;
|
import com.jsowell.pile.thirdparty.EquipmentInfo;
|
||||||
import com.jsowell.pile.util.MerchantUtils;
|
import com.jsowell.pile.util.MerchantUtils;
|
||||||
import com.jsowell.pile.vo.ThirdPartySecretInfoVO;
|
import com.jsowell.pile.vo.ThirdPartySecretInfoVO;
|
||||||
import com.jsowell.pile.vo.base.MerchantInfoVO;
|
import com.jsowell.pile.vo.base.MerchantInfoVO;
|
||||||
import com.jsowell.pile.vo.base.ThirdPartyStationInfoVO;
|
import com.jsowell.pile.vo.base.ThirdPartyStationInfoVO;
|
||||||
|
import com.jsowell.pile.vo.base.ThirdPartyStationRelationVO;
|
||||||
|
import com.jsowell.pile.vo.web.PileConnectorInfoVO;
|
||||||
import com.jsowell.thirdparty.lianlian.vo.AccessTokenVO;
|
import com.jsowell.thirdparty.lianlian.vo.AccessTokenVO;
|
||||||
|
import com.jsowell.thirdparty.lianlian.vo.QueryChargingStatusVO;
|
||||||
import com.jsowell.thirdparty.platform.common.StationInfo;
|
import com.jsowell.thirdparty.platform.common.StationInfo;
|
||||||
|
import com.jsowell.thirdparty.platform.domain.SupConnectorStatusInfo;
|
||||||
import com.jsowell.thirdparty.platform.domain.SupOperatorInfo;
|
import com.jsowell.thirdparty.platform.domain.SupOperatorInfo;
|
||||||
import com.jsowell.thirdparty.platform.domain.SupStationInfo;
|
import com.jsowell.thirdparty.platform.domain.SupStationInfo;
|
||||||
import com.jsowell.thirdparty.platform.factory.ThirdPartyPlatformFactory;
|
import com.jsowell.thirdparty.platform.factory.ThirdPartyPlatformFactory;
|
||||||
import com.jsowell.thirdparty.platform.service.ThirdPartyPlatformService;
|
import com.jsowell.thirdparty.platform.service.ThirdPartyPlatformService;
|
||||||
import com.jsowell.thirdparty.platform.util.Cryptos;
|
import com.jsowell.thirdparty.platform.util.Cryptos;
|
||||||
|
import com.jsowell.thirdparty.platform.util.Encodes;
|
||||||
import com.jsowell.thirdparty.platform.util.HttpRequestUtil;
|
import com.jsowell.thirdparty.platform.util.HttpRequestUtil;
|
||||||
import com.jsowell.thirdparty.platform.util.ThirdPartyPlatformUtils;
|
import com.jsowell.thirdparty.platform.util.ThirdPartyPlatformUtils;
|
||||||
import com.jsowell.thirdparty.service.ThirdpartySecretInfoService;
|
import com.jsowell.thirdparty.service.ThirdpartySecretInfoService;
|
||||||
@@ -43,10 +52,8 @@ import org.springframework.stereotype.Service;
|
|||||||
|
|
||||||
import java.math.BigDecimal;
|
import java.math.BigDecimal;
|
||||||
import java.math.RoundingMode;
|
import java.math.RoundingMode;
|
||||||
import java.util.ArrayList;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.*;
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 浙江省平台
|
* 浙江省平台
|
||||||
@@ -57,6 +64,9 @@ import java.util.Map;
|
|||||||
@Service
|
@Service
|
||||||
public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
||||||
|
|
||||||
|
// 平台类型
|
||||||
|
private final String thirdPlatformType = ThirdPlatformTypeEnum.ZHE_JIANG_PLATFORM.getTypeCode();
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private ThirdpartySecretInfoService thirdpartySecretInfoService;
|
private ThirdpartySecretInfoService thirdpartySecretInfoService;
|
||||||
|
|
||||||
@@ -72,9 +82,15 @@ public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
@Autowired
|
@Autowired
|
||||||
private PileMerchantInfoService pileMerchantInfoService;
|
private PileMerchantInfoService pileMerchantInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private PileConnectorInfoService pileConnectorInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private OrderBasicInfoService orderBasicInfoService;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ThirdPartyPlatformConfigService thirdPartyPlatformConfigService;
|
||||||
|
|
||||||
// 平台类型
|
|
||||||
private final String thirdPlatformType = ThirdPlatformTypeEnum.ZHE_JIANG_PLATFORM.getTypeCode();
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void afterPropertiesSet() throws Exception {
|
public void afterPropertiesSet() throws Exception {
|
||||||
@@ -272,7 +288,7 @@ public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
String dataSecretIv = thirdPartySecretInfoVO.getTheirDataSecretIv();
|
String dataSecretIv = thirdPartySecretInfoVO.getTheirDataSecretIv();
|
||||||
String urlAddress = thirdPartySecretInfoVO.getTheirUrlPrefix();
|
String urlAddress = thirdPartySecretInfoVO.getTheirUrlPrefix();
|
||||||
|
|
||||||
// 组装联联平台所需要的数据格式
|
// 组装所需要的数据格式
|
||||||
StationInfo info = StationInfo.builder()
|
StationInfo info = StationInfo.builder()
|
||||||
.stationID(stationId)
|
.stationID(stationId)
|
||||||
.operatorID(operatorId)
|
.operatorID(operatorId)
|
||||||
@@ -303,8 +319,6 @@ public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
.printerFlag(Integer.valueOf(pileStationInfo.getPrinterFlag()))
|
.printerFlag(Integer.valueOf(pileStationInfo.getPrinterFlag()))
|
||||||
.barrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag()))
|
.barrierFlag(Integer.valueOf(pileStationInfo.getBarrierFlag()))
|
||||||
.parkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag()))
|
.parkingLockFlag(Integer.valueOf(pileStationInfo.getParkingLockFlag()))
|
||||||
// .parkNums()
|
|
||||||
// .supportOrder()
|
|
||||||
.build();
|
.build();
|
||||||
String areaCode = pileStationInfo.getAreaCode(); // 330000,330200,330213
|
String areaCode = pileStationInfo.getAreaCode(); // 330000,330200,330213
|
||||||
// 根据逗号分组
|
// 根据逗号分组
|
||||||
@@ -327,8 +341,7 @@ public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String payment = StationPaymentEnum.getPaymentByCode(pileStationInfo.getPayment());
|
info.setPayment(StationPaymentEnum.getPaymentByCode(pileStationInfo.getPayment()));
|
||||||
info.setPayment(payment);
|
|
||||||
if (StringUtils.isNotBlank(pileStationInfo.getParkingNumber())) {
|
if (StringUtils.isNotBlank(pileStationInfo.getParkingNumber())) {
|
||||||
info.setIsPublicParkingLot(1);
|
info.setIsPublicParkingLot(1);
|
||||||
info.setParkingLotNumber(pileStationInfo.getParkingNumber());
|
info.setParkingLotNumber(pileStationInfo.getParkingNumber());
|
||||||
@@ -366,11 +379,103 @@ public class ZheJiangPlatformServiceImpl implements ThirdPartyPlatformService {
|
|||||||
* 推送充电设备接口状态信息
|
* 推送充电设备接口状态信息
|
||||||
* supervise_notification_connector_status
|
* supervise_notification_connector_status
|
||||||
*/
|
*/
|
||||||
|
public String notificationStationStatus(String stationId, String pileConnectorCode, String status, ThirdPartySecretInfoVO secretInfoVO) {
|
||||||
|
// 查询充电枪口状态
|
||||||
|
PileConnectorInfoVO connectorInfo = pileConnectorInfoService.getPileConnectorInfoByConnectorCode(pileConnectorCode);
|
||||||
|
if (Objects.isNull(connectorInfo)) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_CONNECTOR_INFO_NULL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
String merchantId = connectorInfo.getMerchantId();
|
||||||
|
MerchantInfoVO merchantInfoVO = pileMerchantInfoService.getMerchantInfoVO(merchantId);
|
||||||
|
if (Objects.isNull(merchantInfoVO)) {
|
||||||
|
throw new BusinessException(ReturnCodeEnum.CODE_CONNECTOR_INFO_NULL_ERROR);
|
||||||
|
}
|
||||||
|
|
||||||
|
SupConnectorStatusInfo info = SupConnectorStatusInfo.builder()
|
||||||
|
.operatorID(Constants.JSOWELL_OPERATORID)
|
||||||
|
.equipmentOwnerID(MerchantUtils.getOperatorID(merchantInfoVO.getOrganizationCode()))
|
||||||
|
.stationID(connectorInfo.getStationId())
|
||||||
|
.equipmentID(connectorInfo.getPileSn())
|
||||||
|
.connectorID(pileConnectorCode)
|
||||||
|
.equipmentClassification(Constants.ONE)
|
||||||
|
.status(Integer.parseInt(status))
|
||||||
|
.statusDesc(PileConnectorDataBaseStatusEnum.getStatusDescription(status))
|
||||||
|
.parkStatus(Constants.zero)
|
||||||
|
.lockStatus(Constants.zero)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
// 调用联联平台接口
|
||||||
|
String operatorId = secretInfoVO.getTheirOperatorId();
|
||||||
|
String operatorSecret = secretInfoVO.getTheirOperatorSecret();
|
||||||
|
String signSecret = secretInfoVO.getTheirSigSecret();
|
||||||
|
String dataSecret = secretInfoVO.getTheirDataSecret();
|
||||||
|
String dataSecretIv = secretInfoVO.getTheirDataSecretIv();
|
||||||
|
String urlAddress = secretInfoVO.getTheirUrlPrefix();
|
||||||
|
String url = urlAddress + "supervise_notification_connector_status";
|
||||||
|
|
||||||
|
String jsonString = JSON.toJSONString(info);
|
||||||
|
// 获取令牌
|
||||||
|
String token = getToken(urlAddress, operatorId, operatorSecret, dataSecretIv, signSecret, dataSecret);
|
||||||
|
String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送充电状态信息
|
* 推送充电状态 notification_equip_charge_status
|
||||||
* supervise_notification_equip_charge_status
|
* 推送充电状态信息 supervise_notification_equip_charge_status
|
||||||
|
*
|
||||||
|
* @param orderCode 订单编号
|
||||||
|
* @throws UnsupportedOperationException 未实现异常
|
||||||
*/
|
*/
|
||||||
|
@Override
|
||||||
|
public String notificationEquipChargeStatus(String orderCode) {
|
||||||
|
// 根据订单号查询订单信息
|
||||||
|
OrderBasicInfo orderInfo = orderBasicInfoService.getOrderInfoByOrderCode(orderCode);
|
||||||
|
// 通过第三方平台类型查询相关配置信息
|
||||||
|
ThirdPartyStationRelation relation = new ThirdPartyStationRelation();
|
||||||
|
relation.setThirdPartyType(orderInfo.getThirdPartyType());
|
||||||
|
ThirdPartyStationRelationVO relationInfo = thirdPartyStationRelationService.selectRelationInfo(relation);
|
||||||
|
if (relationInfo == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String operatorId = relationInfo.getOperatorId();
|
||||||
|
String operatorSecret = relationInfo.getOperatorSecret();
|
||||||
|
String signSecret = relationInfo.getSignSecret();
|
||||||
|
String dataSecret = relationInfo.getDataSecret();
|
||||||
|
String dataSecretIv = relationInfo.getDataSecretIv();
|
||||||
|
String urlAddress = relationInfo.getUrlAddress();
|
||||||
|
String thirdPartyType = relationInfo.getThirdPartyType();
|
||||||
|
|
||||||
|
// 调用 查询充电状态方法
|
||||||
|
QueryEquipChargeStatusDTO dto = new QueryEquipChargeStatusDTO();
|
||||||
|
dto.setStartChargeSeq(orderCode);
|
||||||
|
// 根据type获取operatorId
|
||||||
|
String operatorIdByType = ThirdPartyOperatorIdEnum.getOperatorIdByType(thirdPartyType);
|
||||||
|
dto.setOperatorID(operatorIdByType);
|
||||||
|
Map<String, String> map = queryEquipChargeStatus(dto);
|
||||||
|
if (map == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
String data = map.get("Data");
|
||||||
|
// 解密data (此处解密需用 thirdparty_platform_config 的密钥配置)
|
||||||
|
ThirdPartyPlatformConfig configInfo = thirdPartyPlatformConfigService.getInfoByOperatorId(operatorIdByType);
|
||||||
|
ThirdPartySecretInfoVO thirdPartySecretInfoVO = thirdpartySecretInfoService.queryByThirdPlatformType(thirdPlatformType);
|
||||||
|
byte[] plainText = Cryptos.aesDecrypt(Encodes.decodeBase64(data),
|
||||||
|
configInfo.getDataSecret().getBytes(), configInfo.getDataSecretIv().getBytes());
|
||||||
|
String dataStr = new String(plainText, StandardCharsets.UTF_8);
|
||||||
|
// 转成对应的对象
|
||||||
|
QueryChargingStatusVO vo = JSONObject.parseObject(dataStr, QueryChargingStatusVO.class);
|
||||||
|
|
||||||
|
String url = urlAddress + BusinessInformationExchangeEnum.NOTIFICATION_EQUIP_CHARGE_STATUS.getValue();
|
||||||
|
// 调用联联平台接口
|
||||||
|
String jsonString = JSON.toJSONString(vo);
|
||||||
|
|
||||||
|
// 获取令牌
|
||||||
|
String token = getToken(urlAddress, operatorId, operatorSecret, dataSecretIv, signSecret, dataSecret);
|
||||||
|
String result = HttpRequestUtil.sendPost(token, jsonString, url, dataSecret, dataSecretIv, operatorId, signSecret);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 推送充电订单信息
|
* 推送充电订单信息
|
||||||
|
|||||||
Reference in New Issue
Block a user