mirror of
https://gitee.com/huangge1199_admin/vue-pro.git
synced 2024-11-26 17:21:53 +08:00
code review:订单评论、订单积分的变更
This commit is contained in:
parent
f8952f8e34
commit
b75d777670
@ -38,10 +38,9 @@ public class ProductCommentController {
|
||||
@PreAuthorize("@ss.hasPermission('product:comment:query')")
|
||||
public CommonResult<PageResult<ProductCommentRespVO>> getCommentPage(@Valid ProductCommentPageReqVO pageVO) {
|
||||
PageResult<ProductCommentDO> pageResult = productCommentService.getCommentPage(pageVO);
|
||||
|
||||
// 拼接返回
|
||||
List<ProductSkuDO> skuList = productSkuService.getSkuList(
|
||||
convertSet(pageResult.getList(), ProductCommentDO::getSkuId));
|
||||
|
||||
return success(ProductCommentConvert.INSTANCE.convertPage(pageResult, skuList));
|
||||
}
|
||||
|
||||
|
@ -117,26 +117,26 @@ public interface ProductCommentConvert {
|
||||
|
||||
List<AppProductCommentRespVO> convertList02(List<ProductCommentDO> list);
|
||||
|
||||
default ProductCommentDO convert(ProductCommentCreateReqVO createReq, ProductSpuDO spuDO) {
|
||||
default ProductCommentDO convert(ProductCommentCreateReqVO createReq, ProductSpuDO spu) {
|
||||
ProductCommentDO commentDO = convert(createReq);
|
||||
if (spuDO != null) {
|
||||
commentDO.setSpuId(spuDO.getId());
|
||||
commentDO.setSpuName(spuDO.getName());
|
||||
if (spu != null) {
|
||||
commentDO.setSpuId(spu.getId()).setSpuName(spu.getName());
|
||||
}
|
||||
return commentDO;
|
||||
}
|
||||
|
||||
default PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> pageResult, List<ProductSkuDO> skuList) {
|
||||
Map<Long, ProductSkuDO> skuMap = convertMap(skuList, ProductSkuDO::getId);
|
||||
|
||||
default PageResult<ProductCommentRespVO> convertPage(PageResult<ProductCommentDO> pageResult,
|
||||
List<ProductSkuDO> skus) {
|
||||
PageResult<ProductCommentRespVO> result = convertPage(pageResult);
|
||||
// 拼接数据
|
||||
Map<Long, ProductSkuDO> skuMap = convertMap(skus, ProductSkuDO::getId);
|
||||
for (ProductCommentRespVO vo : result.getList()) {
|
||||
findAndThen(skuMap, vo.getSkuId(), sku -> {
|
||||
String propertyNames = sku.getProperties().stream()
|
||||
.map(ProductSkuDO.Property::getValueName)
|
||||
.filter(Objects::nonNull)
|
||||
.collect(Collectors.joining(" "));
|
||||
|
||||
// TODO @疯狂:要不写入评论的时候,把商品图片、商品属性,都冗余进去。因为这种东西有“快照”的需求。商品后续会编辑掉
|
||||
vo.setSkuPicUrl(sku.getPicUrl());
|
||||
vo.setSpuName(vo.getSpuName() + " " + propertyNames);
|
||||
});
|
||||
|
@ -1,6 +1,5 @@
|
||||
package cn.iocoder.yudao.module.product.dal.mysql.comment;
|
||||
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageParam;
|
||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||
@ -54,11 +53,10 @@ public interface ProductCommentMapper extends BaseMapperX<ProductCommentDO> {
|
||||
return selectPage(reqVO, queryWrapper);
|
||||
}
|
||||
|
||||
default ProductCommentDO selectByUserIdAndOrderItemIdAndSpuId(Long userId, Long orderItemId, Long skuId) {
|
||||
default ProductCommentDO selectByUserIdAndOrderItemId(Long userId, Long orderItemId) {
|
||||
return selectOne(new LambdaQueryWrapperX<ProductCommentDO>()
|
||||
.eq(ProductCommentDO::getUserId, userId)
|
||||
.eq(ProductCommentDO::getOrderItemId, orderItemId)
|
||||
.eq(ProductCommentDO::getSpuId, skuId));
|
||||
.eq(ProductCommentDO::getOrderItemId, orderItemId));
|
||||
}
|
||||
|
||||
default Long selectCountBySpuId(Long spuId, Boolean visible, Integer type) {
|
||||
|
@ -24,38 +24,6 @@ import java.util.List;
|
||||
@Validated
|
||||
public interface ProductCommentService {
|
||||
|
||||
/**
|
||||
* 获得商品评价分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 商品评价分页
|
||||
*/
|
||||
PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 修改评论是否可见
|
||||
*
|
||||
* @param updateReqVO 修改评论可见
|
||||
*/
|
||||
void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 商家回复
|
||||
*
|
||||
* @param replyVO 商家回复
|
||||
* @param loginUserId 管理后台商家登陆人 ID
|
||||
*/
|
||||
void replyComment(ProductCommentReplyReqVO replyVO, Long loginUserId);
|
||||
|
||||
/**
|
||||
* 获得商品评价分页
|
||||
*
|
||||
* @param pageVO 分页查询
|
||||
* @param visible 是否可见
|
||||
* @return 商品评价分页
|
||||
*/
|
||||
PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
|
||||
|
||||
/**
|
||||
* 创建商品评论
|
||||
* 后台管理员创建评论使用
|
||||
@ -73,6 +41,38 @@ public interface ProductCommentService {
|
||||
*/
|
||||
Long createComment(ProductCommentCreateReqDTO createReqDTO);
|
||||
|
||||
/**
|
||||
* 修改评论是否可见
|
||||
*
|
||||
* @param updateReqVO 修改评论可见
|
||||
*/
|
||||
void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO);
|
||||
|
||||
/**
|
||||
* 商家回复
|
||||
*
|
||||
* @param replyVO 商家回复
|
||||
* @param userId 管理后台商家登陆人 ID
|
||||
*/
|
||||
void replyComment(ProductCommentReplyReqVO replyVO, Long userId);
|
||||
|
||||
/**
|
||||
* 【管理员】获得商品评价分页
|
||||
*
|
||||
* @param pageReqVO 分页查询
|
||||
* @return 商品评价分页
|
||||
*/
|
||||
PageResult<ProductCommentDO> getCommentPage(ProductCommentPageReqVO pageReqVO);
|
||||
|
||||
/**
|
||||
* 【会员】获得商品评价分页
|
||||
*
|
||||
* @param pageVO 分页查询
|
||||
* @param visible 是否可见
|
||||
* @return 商品评价分页
|
||||
*/
|
||||
PageResult<ProductCommentDO> getCommentPage(AppCommentPageReqVO pageVO, Boolean visible);
|
||||
|
||||
/**
|
||||
* 获得商品的评价统计
|
||||
*
|
||||
|
@ -20,7 +20,6 @@ import cn.iocoder.yudao.module.product.service.sku.ProductSkuService;
|
||||
import cn.iocoder.yudao.module.product.service.spu.ProductSpuService;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@ -53,71 +52,43 @@ public class ProductCommentServiceImpl implements ProductCommentService {
|
||||
private MemberUserApi memberUserApi;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO) {
|
||||
// 校验评论是否存在
|
||||
ProductCommentDO productCommentDO = validateCommentExists(updateReqVO.getId());
|
||||
productCommentDO.setVisible(updateReqVO.getVisible());
|
||||
|
||||
// 更新可见状态
|
||||
productCommentMapper.updateById(productCommentDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void replyComment(ProductCommentReplyReqVO replyVO, Long loginUserId) {
|
||||
// 校验评论是否存在
|
||||
ProductCommentDO productCommentDO = validateCommentExists(replyVO.getId());
|
||||
productCommentDO.setReplyTime(LocalDateTime.now());
|
||||
productCommentDO.setReplyUserId(loginUserId);
|
||||
productCommentDO.setReplyStatus(Boolean.TRUE);
|
||||
productCommentDO.setReplyContent(replyVO.getReplyContent());
|
||||
|
||||
// 回复评论
|
||||
productCommentMapper.updateById(productCommentDO);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createComment(ProductCommentCreateReqVO createReqVO) {
|
||||
// 校验商品
|
||||
ProductSpuDO spuDO = validateProduct(createReqVO.getSkuId());
|
||||
ProductSpuDO spu = validateSpuBySkuId(createReqVO.getSkuId());
|
||||
|
||||
ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqVO, spuDO);
|
||||
productCommentMapper.insert(commentDO);
|
||||
// 创建评论
|
||||
ProductCommentDO comment = ProductCommentConvert.INSTANCE.convert(createReqVO, spu);
|
||||
productCommentMapper.insert(comment);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createComment(ProductCommentCreateReqDTO createReqDTO) {
|
||||
// 校验商品
|
||||
ProductSpuDO spuDO = validateProduct(createReqDTO.getSkuId());
|
||||
ProductSpuDO spuDO = validateSpuBySkuId(createReqDTO.getSkuId());
|
||||
// 校验评论
|
||||
validateComment(spuDO.getId(), createReqDTO.getUserId(), createReqDTO.getOrderId());
|
||||
validateCommentExists(createReqDTO.getUserId(), createReqDTO.getOrderId());
|
||||
// 获取用户详细信息
|
||||
MemberUserRespDTO user = memberUserApi.getUser(createReqDTO.getUserId());
|
||||
|
||||
// 创建评论
|
||||
ProductCommentDO commentDO = ProductCommentConvert.INSTANCE.convert(createReqDTO, spuDO, user);
|
||||
productCommentMapper.insert(commentDO);
|
||||
return commentDO.getId();
|
||||
ProductCommentDO comment = ProductCommentConvert.INSTANCE.convert(createReqDTO, spuDO, user);
|
||||
productCommentMapper.insert(comment);
|
||||
return comment.getId();
|
||||
}
|
||||
|
||||
private void validateComment(Long skuId, Long userId, Long orderItemId) {
|
||||
// 判断当前订单的当前商品用户是否评价过
|
||||
ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemIdAndSpuId(userId, orderItemId, skuId);
|
||||
if (null != exist) {
|
||||
/**
|
||||
* 判断当前订单的当前商品用户是否评价过
|
||||
*
|
||||
* @param userId 用户编号
|
||||
* @param orderItemId 订单项编号
|
||||
*/
|
||||
private void validateCommentExists(Long userId, Long orderItemId) {
|
||||
ProductCommentDO exist = productCommentMapper.selectByUserIdAndOrderItemId(userId, orderItemId);
|
||||
if (exist != null) {
|
||||
throw exception(COMMENT_ORDER_EXISTS);
|
||||
}
|
||||
}
|
||||
|
||||
private ProductSpuDO validateProduct(Long skuId) {
|
||||
// 通过 sku ID 拿到 spu 相关信息
|
||||
ProductSkuDO sku = validateSku(skuId);
|
||||
// 校验 spu 如果存在返回详情
|
||||
return validateSpu(sku.getSpuId());
|
||||
}
|
||||
|
||||
private ProductSkuDO validateSku(Long skuId) {
|
||||
ProductSkuDO sku = productSkuService.getSku(skuId);
|
||||
if (sku == null) {
|
||||
@ -134,6 +105,33 @@ public class ProductCommentServiceImpl implements ProductCommentService {
|
||||
return spu;
|
||||
}
|
||||
|
||||
private ProductSpuDO validateSpuBySkuId(Long skuId) {
|
||||
// 通过 sku ID 拿到 spu 相关信息
|
||||
ProductSkuDO sku = validateSku(skuId);
|
||||
// 校验 spu 如果存在返回详情
|
||||
return validateSpu(sku.getSpuId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateCommentVisible(ProductCommentUpdateVisibleReqVO updateReqVO) {
|
||||
// 校验评论是否存在
|
||||
validateCommentExists(updateReqVO.getId());
|
||||
|
||||
// 更新可见状态
|
||||
productCommentMapper.updateById(new ProductCommentDO().setId(updateReqVO.getId())
|
||||
.setVisible(true));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void replyComment(ProductCommentReplyReqVO replyVO, Long userId) {
|
||||
// 校验评论是否存在
|
||||
validateCommentExists(replyVO.getId());
|
||||
// 回复评论
|
||||
productCommentMapper.updateById(new ProductCommentDO().setId(replyVO.getId())
|
||||
.setReplyTime(LocalDateTime.now()).setReplyUserId(userId)
|
||||
.setReplyStatus(Boolean.TRUE).setReplyContent(replyVO.getReplyContent()));
|
||||
}
|
||||
|
||||
private ProductCommentDO validateCommentExists(Long id) {
|
||||
ProductCommentDO productComment = productCommentMapper.selectById(id);
|
||||
if (productComment == null) {
|
||||
|
@ -667,6 +667,7 @@ public class TradeOrderUpdateServiceImpl implements TradeOrderUpdateService {
|
||||
TradeOrderItemAfterSaleStatusEnum.SUCCESS.getStatus()));
|
||||
}
|
||||
|
||||
// TODO @疯狂:直接 this 调用,async 不生效哈。全局搜下 getSelf();
|
||||
@Async
|
||||
protected void addUserExperienceAsync(Long userId, Integer payPrice, Long orderId) {
|
||||
int bizType = MemberExperienceBizTypeEnum.ORDER.getType();
|
||||
|
@ -58,6 +58,7 @@ public interface MemberUserApi {
|
||||
*/
|
||||
MemberUserRespDTO getUserByMobile(String mobile);
|
||||
|
||||
// TODO @疯狂:是不是新的类,MemberPointApi?
|
||||
/**
|
||||
* 增加用户积分
|
||||
*
|
||||
@ -67,4 +68,5 @@ public interface MemberUserApi {
|
||||
* @param bizId 业务编号
|
||||
*/
|
||||
void addPoint(Long userId, Integer point, Integer bizType, String bizId);
|
||||
|
||||
}
|
||||
|
@ -32,6 +32,7 @@ public enum MemberPointBizTypeEnum implements IntArrayValuable {
|
||||
* 描述
|
||||
*/
|
||||
private final String description;
|
||||
// TODO @疯狂:改成 add 会好点。一个是属性我们尽量不要 isXXX;另外尽量正向思维,不取反;
|
||||
/**
|
||||
* 是否为扣减积分
|
||||
*/
|
||||
@ -42,7 +43,6 @@ public enum MemberPointBizTypeEnum implements IntArrayValuable {
|
||||
return new int[0];
|
||||
}
|
||||
|
||||
|
||||
public static MemberPointBizTypeEnum getByType(Integer type) {
|
||||
return EnumUtil.getBy(MemberPointBizTypeEnum.class,
|
||||
e -> Objects.equals(type, e.getType()));
|
||||
|
@ -99,7 +99,6 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
if (ObjUtil.notEqual(levelDO.getName(), name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (id == null || !id.equals(levelDO.getId())) {
|
||||
throw exception(LEVEL_NAME_EXISTS, levelDO.getName());
|
||||
}
|
||||
@ -151,7 +150,6 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
validateExperienceOutRange(list, id, level, experience);
|
||||
}
|
||||
|
||||
// TODO 有 Service 提供接口哈,不直接调用对方的 memberUserMapper
|
||||
@VisibleForTesting
|
||||
void validateLevelHasUser(Long id) {
|
||||
Long count = memberUserService.getUserCountByLevelId(id);
|
||||
@ -195,37 +193,36 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
return;
|
||||
}
|
||||
|
||||
// 记录等级变动
|
||||
// 1. 记录等级变动
|
||||
MemberLevelRecordDO levelRecord = new MemberLevelRecordDO()
|
||||
.setUserId(user.getId())
|
||||
.setRemark(updateReqVO.getReason());
|
||||
.setUserId(user.getId()).setRemark(updateReqVO.getReason());
|
||||
MemberLevelDO memberLevel = null;
|
||||
if (updateReqVO.getLevelId() == null) {
|
||||
// 取消用户等级时,为扣减经验
|
||||
// 取消用户等级时,需要扣减经验
|
||||
levelRecord.setExperience(-user.getExperience());
|
||||
// TODO @疯狂:这里是不是也要设置下 setUserExperience 属性;
|
||||
levelRecord.setDescription("管理员取消了等级");
|
||||
} else {
|
||||
memberLevel = validateLevelExists(updateReqVO.getLevelId());
|
||||
// 复制等级配置
|
||||
memberLevel = validateLevelExists(updateReqVO.getLevelId());
|
||||
MemberLevelRecordConvert.INSTANCE.copyTo(memberLevel, levelRecord);
|
||||
// 变动经验值 = 等级的升级经验 - 会员当前的经验;正数为增加经验,负数为扣减经验
|
||||
levelRecord.setExperience(memberLevel.getExperience() - user.getExperience());
|
||||
// 会员当前的经验 = 等级的升级经验
|
||||
levelRecord.setUserExperience(memberLevel.getExperience());
|
||||
levelRecord.setUserExperience(memberLevel.getExperience()); // 会员当前的经验 = 等级的升级经验
|
||||
levelRecord.setDescription("管理员调整为:" + memberLevel.getName());
|
||||
}
|
||||
memberLevelRecordService.createLevelRecord(levelRecord);
|
||||
|
||||
// 记录会员经验变动
|
||||
// 2. 记录会员经验变动
|
||||
memberExperienceRecordService.createExperienceRecord(user.getId(),
|
||||
levelRecord.getExperience(), levelRecord.getUserExperience(),
|
||||
MemberExperienceBizTypeEnum.ADMIN, String.valueOf(MemberExperienceBizTypeEnum.ADMIN.getType()));
|
||||
|
||||
// 更新会员表上的等级编号、经验值
|
||||
// 3. 更新会员表上的等级编号、经验值
|
||||
memberUserService.updateUserLevel(user.getId(), updateReqVO.getLevelId(),
|
||||
levelRecord.getUserExperience());
|
||||
|
||||
// 给会员发送等级变动消息
|
||||
// 4. 给会员发送等级变动消息
|
||||
notifyMemberLevelChange(user.getId(), memberLevel);
|
||||
}
|
||||
|
||||
@ -239,31 +236,27 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
experience = -experience;
|
||||
}
|
||||
|
||||
// 1. 创建经验记录
|
||||
MemberUserDO user = memberUserService.getUser(userId);
|
||||
|
||||
int userExperience = NumberUtil.max(user.getExperience() + experience, 0);
|
||||
int userExperience = NumberUtil.max(user.getExperience() + experience, 0); // 防止扣出负数
|
||||
MemberLevelRecordDO levelRecord = new MemberLevelRecordDO()
|
||||
.setUserId(user.getId())
|
||||
.setExperience(experience)
|
||||
// 防止扣出负数
|
||||
.setUserExperience(userExperience);
|
||||
|
||||
// 创建经验记录
|
||||
memberExperienceRecordService.createExperienceRecord(userId, experience, userExperience,
|
||||
bizType, bizId);
|
||||
|
||||
// 计算会员等级
|
||||
// 2.1 保存等级变更记录
|
||||
MemberLevelDO newLevel = calculateNewLevel(user, userExperience);
|
||||
if (newLevel != null) {
|
||||
// 复制等级配置
|
||||
MemberLevelRecordConvert.INSTANCE.copyTo(newLevel, levelRecord);
|
||||
// 保存等级变更记录
|
||||
memberLevelRecordService.createLevelRecord(levelRecord);
|
||||
// 给会员发送等级变动消息
|
||||
|
||||
// 2.2 给会员发送等级变动消息
|
||||
notifyMemberLevelChange(userId, newLevel);
|
||||
}
|
||||
|
||||
// 更新会员表上的等级编号、经验值
|
||||
// 3. 更新会员表上的等级编号、经验值
|
||||
memberUserService.updateUserLevel(user.getId(), levelRecord.getLevelId(), userExperience);
|
||||
}
|
||||
|
||||
@ -301,4 +294,5 @@ public class MemberLevelServiceImpl implements MemberLevelService {
|
||||
private void notifyMemberLevelChange(Long userId, MemberLevelDO level) {
|
||||
//todo: 给会员发消息
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -72,22 +72,22 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
|
||||
public void createPointRecord(Long userId, Integer point, MemberPointBizTypeEnum bizType, String bizId) {
|
||||
MemberPointConfigDO pointConfig = memberPointConfigService.getPointConfig();
|
||||
if (pointConfig == null || pointConfig.getTradeGivePoint() == null) {
|
||||
log.warn("增加积分失败:积分配置”1 元赠送多少分“未设置, userId={}, point={}, bizType={}, bizId={}",
|
||||
log.error("[createPointRecord][增加积分失败:tradeGivePoint 未配置,userId({}) point({}) bizType({}) bizId({})]",
|
||||
userId, point, bizType.getType(), bizId);
|
||||
return;
|
||||
}
|
||||
|
||||
// 根据配置的比例,换算实际的积分
|
||||
// 1. 根据配置的比例,换算实际的积分
|
||||
point = point * pointConfig.getTradeGivePoint();
|
||||
if (bizType.isReduce() && point > 0) {
|
||||
point = -point;
|
||||
}
|
||||
|
||||
// 2. 增加积分记录
|
||||
MemberUserDO user = memberUserService.getUser(userId);
|
||||
Integer userPoint = ObjectUtil.defaultIfNull(user.getPoint(), 0);
|
||||
// 用户变动后的积分,防止扣出负数
|
||||
// 用户变动后的积分,防止扣出负数 TODO 疯狂:积分是不是允许扣到负数。因为它是跟有钱有关的东西,不能让商家出现资金损失
|
||||
Integer totalPoint = NumberUtil.max(userPoint + point, 0);
|
||||
// 增加积分记录
|
||||
MemberPointRecordDO recordDO = new MemberPointRecordDO()
|
||||
.setUserId(userId)
|
||||
.setBizId(bizId)
|
||||
@ -98,7 +98,7 @@ public class MemberPointRecordServiceImpl implements MemberPointRecordService {
|
||||
.setTotalPoint(totalPoint);
|
||||
recordMapper.insert(recordDO);
|
||||
|
||||
// 更新用户积分
|
||||
// 3. 更新用户积分
|
||||
memberUserService.updateUserPoint(userId, totalPoint);
|
||||
}
|
||||
|
||||
|
@ -162,7 +162,7 @@ public interface MemberUserService {
|
||||
/**
|
||||
* 更新用户的积分
|
||||
*
|
||||
* @param userId 用户ID
|
||||
* @param userId 用户编号
|
||||
* @param point 积分数量
|
||||
*/
|
||||
void updateUserPoint(Long userId, Integer point);
|
||||
|
Loading…
Reference in New Issue
Block a user