新增模块促使两个SpringBoot 服务之间联系
This commit is contained in:
parent
38d3ae9318
commit
71bbc90bb6
@ -22,7 +22,7 @@ public class FileUploadController {
|
|||||||
// 上传文件
|
// 上传文件
|
||||||
@PostMapping("/upload")
|
@PostMapping("/upload")
|
||||||
public GlobalResponse<FileMap> upload(@NotNull MultipartFile file) {
|
public GlobalResponse<FileMap> upload(@NotNull MultipartFile file) {
|
||||||
return GlobalResponse.success(fileService.saveLocalFile(file));
|
return GlobalResponse.success(fileService.uploadOOS(file));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.service.IService;
|
|||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -35,5 +36,7 @@ public interface FileMapService extends IService<FileMap> {
|
|||||||
|
|
||||||
String getLocalFilePath(FileMap fileMap);
|
String getLocalFilePath(FileMap fileMap);
|
||||||
|
|
||||||
String uploadOOS(MultipartFile file);
|
FileMap uploadOOS(MultipartFile file);
|
||||||
|
|
||||||
|
FileMap uploadOOS(File file);
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,21 @@
|
|||||||
package com.yskj.acdr.master.file.service.impl;
|
package com.yskj.acdr.master.file.service.impl;
|
||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import com.alibaba.fastjson2.JSON;
|
||||||
|
import com.alibaba.fastjson2.JSONObject;
|
||||||
|
import com.yskj.acdr.common.cache.GlobalRedisCache;
|
||||||
import com.yskj.acdr.common.exception.BusinessException;
|
import com.yskj.acdr.common.exception.BusinessException;
|
||||||
import com.yskj.acdr.master.file.entity.FileMap;
|
import com.yskj.acdr.master.file.entity.FileMap;
|
||||||
import com.yskj.acdr.master.file.mapper.FileMapMapper;
|
import com.yskj.acdr.master.file.mapper.FileMapMapper;
|
||||||
import com.yskj.acdr.master.file.service.FileMapService;
|
import com.yskj.acdr.master.file.service.FileMapService;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.yskj.acdr.utils.FileUtils;
|
import com.yskj.acdr.utils.FileUtils;
|
||||||
|
import jakarta.annotation.Resource;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -16,6 +24,8 @@ import javax.imageio.ImageIO;
|
|||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* <p>
|
* <p>
|
||||||
@ -28,10 +38,22 @@ import java.io.IOException;
|
|||||||
@Service
|
@Service
|
||||||
public class FileMapServiceImpl extends ServiceImpl<FileMapMapper, FileMap> implements FileMapService {
|
public class FileMapServiceImpl extends ServiceImpl<FileMapMapper, FileMap> implements FileMapService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private GlobalRedisCache<String> redisCache;
|
||||||
|
|
||||||
// 从配置文件中获取自定义路径
|
// 从配置文件中获取自定义路径
|
||||||
@Value("${path.file}")
|
@Value("${path.file}")
|
||||||
private String filePath;
|
private String filePath;
|
||||||
|
|
||||||
|
@Value("${admin.password}")
|
||||||
|
private String adminPassword;
|
||||||
|
|
||||||
|
@Value("${admin.key}")
|
||||||
|
private String adminKey;
|
||||||
|
|
||||||
|
@Value("${admin.url}")
|
||||||
|
private String adminUrl;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 保存到本地服务器上面
|
* 保存到本地服务器上面
|
||||||
*
|
*
|
||||||
@ -126,9 +148,50 @@ public class FileMapServiceImpl extends ServiceImpl<FileMapMapper, FileMap> impl
|
|||||||
* 上传图片到云储存库当中
|
* 上传图片到云储存库当中
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public String uploadOOS(MultipartFile file) {
|
public FileMap uploadOOS(MultipartFile file) {
|
||||||
|
// 将 MultipartFile 转换为临时文件
|
||||||
|
File tempFile = FileUtil.createTempFile(file.getOriginalFilename(), ".tmp", null, true);
|
||||||
|
try {
|
||||||
|
file.transferTo(tempFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
return uploadOOS(tempFile);
|
||||||
|
}
|
||||||
|
|
||||||
return "";
|
@Override
|
||||||
|
public FileMap uploadOOS(File file) {
|
||||||
|
// 从 Redis 中获取管理员密钥
|
||||||
|
String adminValue = redisCache.get(adminKey);
|
||||||
|
if (StrUtil.isBlank(adminValue)) {
|
||||||
|
redisCache.set(adminKey, adminPassword);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 创建请求参数,将文件添加到请求中
|
||||||
|
Map<String, Object> formData = new HashMap<>();
|
||||||
|
formData.put("file", file); // 传递 File 对象
|
||||||
|
|
||||||
|
// 发起 POST 请求
|
||||||
|
HttpResponse response = HttpRequest.post(adminUrl + "/admin-api/contact/file/upload")
|
||||||
|
.form(formData) // 发送表单参数
|
||||||
|
.execute();
|
||||||
|
|
||||||
|
JSONObject res = JSON.parseObject(response.body());
|
||||||
|
// 检查响应状态并处理响应
|
||||||
|
if (response.isOk() && res.getInteger("code") == 0) {
|
||||||
|
// 创建 FileMap 对象并保存到数据库
|
||||||
|
FileMap fileMap = new FileMap()
|
||||||
|
.setUrl(res.getString("data")) // 这里假设 response.body() 返回的是文件的 URL
|
||||||
|
.setIsExist(true)
|
||||||
|
.setIsLocal(false)
|
||||||
|
.setIsWeb(true);
|
||||||
|
|
||||||
|
// 保存文件信息到数据库
|
||||||
|
this.save(fileMap);
|
||||||
|
return fileMap; // 返回成功的响应
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("上传失败: " + response.getStatus());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@ package com.yskj.acdr.master.order.controller;
|
|||||||
|
|
||||||
import cn.dev33.satoken.stp.StpUtil;
|
import cn.dev33.satoken.stp.StpUtil;
|
||||||
import cn.hutool.core.date.DateUtil;
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.map.MapUtil;
|
import cn.hutool.core.map.MapUtil;
|
||||||
import cn.hutool.core.util.IdUtil;
|
import cn.hutool.core.util.IdUtil;
|
||||||
import cn.hutool.core.util.RandomUtil;
|
import cn.hutool.core.util.RandomUtil;
|
||||||
@ -41,7 +42,10 @@ import org.springframework.util.DigestUtils;
|
|||||||
import org.springframework.validation.annotation.Validated;
|
import org.springframework.validation.annotation.Validated;
|
||||||
import org.springframework.web.bind.annotation.*;
|
import org.springframework.web.bind.annotation.*;
|
||||||
|
|
||||||
|
import javax.imageio.ImageIO;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
@ -188,9 +192,9 @@ public class OrderController {
|
|||||||
*/
|
*/
|
||||||
@ApiOperation(value = "确定客户预约信息")
|
@ApiOperation(value = "确定客户预约信息")
|
||||||
@PostMapping(value = "/confirm/{orderId}")
|
@PostMapping(value = "/confirm/{orderId}")
|
||||||
@Transactional(rollbackFor = Exception.class)
|
@Transactional
|
||||||
public GlobalResponse<String> confirm(
|
public GlobalResponse<String> confirm(
|
||||||
@PathVariable Long orderId) {
|
@PathVariable Long orderId) throws IOException {
|
||||||
// 判断是否是自己的订单信息,如果不是则该用户没有权限确认订单信息
|
// 判断是否是自己的订单信息,如果不是则该用户没有权限确认订单信息
|
||||||
Order order = orderService.lambdaQuery()
|
Order order = orderService.lambdaQuery()
|
||||||
.eq(Order::getPersonalServiceUserId, StpUtil.getLoginIdAsLong())
|
.eq(Order::getPersonalServiceUserId, StpUtil.getLoginIdAsLong())
|
||||||
@ -222,9 +226,11 @@ public class OrderController {
|
|||||||
|
|
||||||
// 支付成功之后生成二维码图片
|
// 支付成功之后生成二维码图片
|
||||||
BufferedImage generate = QrCodeUtil.generate(qrCode.getId().toString(), 300, 300);
|
BufferedImage generate = QrCodeUtil.generate(qrCode.getId().toString(), 300, 300);
|
||||||
|
File tempFile = FileUtil.createTempFile("qrcode", ".png", null, true);
|
||||||
|
// 将 BufferedImage 保存为 PNG 文件
|
||||||
|
ImageIO.write(generate, "png", tempFile);
|
||||||
// 写入到指定为止
|
// 写入到指定为止
|
||||||
FileMap file = fileService.saveLocalFile(generate, "png");
|
FileMap file = fileService.uploadOOS(tempFile);
|
||||||
qrCode.setImgUrl(file.getUrl());
|
qrCode.setImgUrl(file.getUrl());
|
||||||
qrCodeMapper.updateById(qrCode);
|
qrCodeMapper.updateById(qrCode);
|
||||||
|
|
||||||
|
@ -131,7 +131,6 @@ public class PetController {
|
|||||||
* 当前客户申请成为宠托师
|
* 当前客户申请成为宠托师
|
||||||
*
|
*
|
||||||
* @param pcf 申请成为宠托师的材料
|
* @param pcf 申请成为宠托师的材料
|
||||||
* @param files 宠托师的材料图片
|
|
||||||
* @return GlobalResponse<PetExpertCertification>
|
* @return GlobalResponse<PetExpertCertification>
|
||||||
*/
|
*/
|
||||||
@PostMapping("/apply")
|
@PostMapping("/apply")
|
||||||
|
@ -7,6 +7,8 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
|||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
import com.yskj.acdr.common.response.GlobalResponse;
|
import com.yskj.acdr.common.response.GlobalResponse;
|
||||||
import com.yskj.acdr.enums.PetSpecies;
|
import com.yskj.acdr.enums.PetSpecies;
|
||||||
|
import com.yskj.acdr.master.file.entity.FileMap;
|
||||||
|
import com.yskj.acdr.master.file.service.FileMapService;
|
||||||
import com.yskj.acdr.master.pet.entity.PetInfo;
|
import com.yskj.acdr.master.pet.entity.PetInfo;
|
||||||
import com.yskj.acdr.master.pet.mapper.PetInfoMapper;
|
import com.yskj.acdr.master.pet.mapper.PetInfoMapper;
|
||||||
import com.yskj.acdr.master.pet.service.PetInfoService;
|
import com.yskj.acdr.master.pet.service.PetInfoService;
|
||||||
@ -27,13 +29,19 @@ import java.io.File;
|
|||||||
@Service
|
@Service
|
||||||
public class PetInfoServiceImpl extends ServiceImpl<PetInfoMapper, PetInfo>
|
public class PetInfoServiceImpl extends ServiceImpl<PetInfoMapper, PetInfo>
|
||||||
implements PetInfoService {
|
implements PetInfoService {
|
||||||
|
|
||||||
@Value("${path.profile}")
|
@Value("${path.profile}")
|
||||||
private String profile;
|
private String profile;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private PetInfoMapper petInfoMapper;
|
private PetInfoMapper petInfoMapper;
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
private UsersMapper wechatUserInfoMapper;
|
private UsersMapper wechatUserInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileMapService fileService;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public GlobalResponse<PetInfo> addPet(MultipartFile file, PetInfo petInfo) {
|
public GlobalResponse<PetInfo> addPet(MultipartFile file, PetInfo petInfo) {
|
||||||
LambdaQueryWrapper<Users> userInfoWrapper = new LambdaQueryWrapper<>();
|
LambdaQueryWrapper<Users> userInfoWrapper = new LambdaQueryWrapper<>();
|
||||||
@ -51,10 +59,12 @@ public class PetInfoServiceImpl extends ServiceImpl<PetInfoMapper, PetInfo>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
String petId = IdUtil.getSnowflakeNextIdStr();
|
String petId = IdUtil.getSnowflakeNextIdStr();
|
||||||
String flag = StpUtil.getLoginIdAsLong() + File.separator + petId;
|
// String flag = StpUtil.getLoginIdAsLong() + File.separator + petId;
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
String fileName = FileUtils.uploadSingleFile(file, profile, flag);
|
// 这是上传到本地
|
||||||
petInfo.setId(petId).setProfileUrl("/profile/"+fileName);
|
// String fileName = FileUtils.uploadSingleFile(file, profile, flag);
|
||||||
|
FileMap fileMap = fileService.uploadOOS(file);
|
||||||
|
petInfo.setId(petId).setProfileUrl(fileMap.getUrl());
|
||||||
} else {
|
} else {
|
||||||
//使用默认头像
|
//使用默认头像
|
||||||
petInfo.setId(petId).setProfileUrl("default" + File.separator + "default-" + PetSpecies.getSortFromSortCode(petInfo.getAssort()) + ".jpg");
|
petInfo.setId(petId).setProfileUrl("default" + File.separator + "default-" + PetSpecies.getSortFromSortCode(petInfo.getAssort()) + ".jpg");
|
||||||
@ -73,12 +83,14 @@ public class PetInfoServiceImpl extends ServiceImpl<PetInfoMapper, PetInfo>
|
|||||||
}
|
}
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
//先去删除旧头像
|
//先去删除旧头像
|
||||||
if (!one.getProfileUrl().startsWith("default")) {
|
//if (!one.getProfileUrl().startsWith("default")) {
|
||||||
String path = profile + one.getProfileUrl().trim().replace("/profile/", "");
|
// String path = profile + one.getProfileUrl().trim().replace("/profile/", "");
|
||||||
FileUtil.del(path);
|
// FileUtil.del(path);
|
||||||
}
|
//}
|
||||||
String fileName = FileUtils.uploadSingleFile(file, profile, one.getUserId() + File.separator + one.getId());
|
// String fileName = FileUtils.uploadSingleFile(file, profile, one.getUserId() + File.separator + one.getId());
|
||||||
petInfo.setProfileUrl("/profile/"+fileName);
|
// petInfo.setProfileUrl("/profile/"+fileName);
|
||||||
|
FileMap fileMap = fileService.uploadOOS(file);
|
||||||
|
petInfo.setProfileUrl(fileMap.getUrl());
|
||||||
return petInfoMapper.updateById(petInfo) > 0 ? GlobalResponse.success("修改成功") : GlobalResponse.failure("修改失败");
|
return petInfoMapper.updateById(petInfo) > 0 ? GlobalResponse.success("修改成功") : GlobalResponse.failure("修改失败");
|
||||||
} else {
|
} else {
|
||||||
return petInfoMapper.updateById(petInfo) > 0 ? GlobalResponse.success("修改成功") : GlobalResponse.failure("修改失败");
|
return petInfoMapper.updateById(petInfo) > 0 ? GlobalResponse.success("修改成功") : GlobalResponse.failure("修改失败");
|
||||||
|
@ -270,10 +270,9 @@ public class AuthenticationService {
|
|||||||
// 对图片进行上传
|
// 对图片进行上传
|
||||||
if (file != null) {
|
if (file != null) {
|
||||||
// 上传图片
|
// 上传图片
|
||||||
FileMap fileName = fmService.saveLocalFile(file);
|
FileMap filemap = fmService.uploadOOS(file);
|
||||||
// 图片上传之后,对图片进行识别, 识别正面
|
// 图片上传之后,对图片进行识别, 识别正面
|
||||||
String filePath = fmService.getLocalFilePath(fileName);
|
Map<String, Object> faceFes = recognizeIDCard(filemap.getUrl(), "face");
|
||||||
Map<String, Object> faceFes = recognizeIDCard(filePath, "face");
|
|
||||||
AuthenticationResponse authRes;
|
AuthenticationResponse authRes;
|
||||||
AuthenticationErrorCode code = AuthenticationErrorCode.UNKNOWN_ERROR;
|
AuthenticationErrorCode code = AuthenticationErrorCode.UNKNOWN_ERROR;
|
||||||
try {
|
try {
|
||||||
|
@ -12,11 +12,15 @@ import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
|||||||
import com.yskj.acdr.common.exception.LoginFailedException;
|
import com.yskj.acdr.common.exception.LoginFailedException;
|
||||||
import com.yskj.acdr.common.response.GlobalResponse;
|
import com.yskj.acdr.common.response.GlobalResponse;
|
||||||
import com.yskj.acdr.master.common.WeChatProperties;
|
import com.yskj.acdr.master.common.WeChatProperties;
|
||||||
|
import com.yskj.acdr.master.file.entity.FileMap;
|
||||||
|
import com.yskj.acdr.master.file.mapper.FileMapMapper;
|
||||||
|
import com.yskj.acdr.master.file.service.FileMapService;
|
||||||
import com.yskj.acdr.master.user.entity.Users;
|
import com.yskj.acdr.master.user.entity.Users;
|
||||||
import com.yskj.acdr.master.user.mapper.UsersMapper;
|
import com.yskj.acdr.master.user.mapper.UsersMapper;
|
||||||
import com.yskj.acdr.master.user.service.WechatUserInfoService;
|
import com.yskj.acdr.master.user.service.WechatUserInfoService;
|
||||||
import com.yskj.acdr.utils.FileUtils;
|
import com.yskj.acdr.utils.FileUtils;
|
||||||
import jakarta.annotation.Resource;
|
import jakarta.annotation.Resource;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
import org.springframework.web.multipart.MultipartFile;
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
@ -44,6 +48,9 @@ public class WechatUserInfoServiceImpl extends ServiceImpl<UsersMapper, Users>
|
|||||||
@Resource
|
@Resource
|
||||||
private UsersMapper wechatUserInfoMapper;
|
private UsersMapper wechatUserInfoMapper;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private FileMapService fileService;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 微信用户登录
|
* 微信用户登录
|
||||||
*
|
*
|
||||||
@ -82,10 +89,11 @@ public class WechatUserInfoServiceImpl extends ServiceImpl<UsersMapper, Users>
|
|||||||
if (file != null) {
|
if (file != null) {
|
||||||
if (StrUtil.isNotBlank(one.getAvatar())) {
|
if (StrUtil.isNotBlank(one.getAvatar())) {
|
||||||
//删除旧头像
|
//删除旧头像
|
||||||
FileUtil.del(profile + one.getAvatar());
|
// FileUtil.del(profile + one.getAvatar());
|
||||||
}
|
}
|
||||||
String fileName = FileUtils.uploadSingleFile(file, profile, "avatar" + File.separator + one.getId());
|
// String fileName = FileUtils.uploadSingleFile(file, profile, "avatar" + File.separator + one.getId());
|
||||||
wechatUserInfo.setAvatar(fileName);
|
FileMap fileMap = fileService.uploadOOS(file);
|
||||||
|
wechatUserInfo.setAvatar(fileMap.getUrl());
|
||||||
}
|
}
|
||||||
//用户名唯一
|
//用户名唯一
|
||||||
if (StrUtil.isNotBlank(wechatUserInfo.getName())) {
|
if (StrUtil.isNotBlank(wechatUserInfo.getName())) {
|
||||||
|
@ -49,7 +49,7 @@ spring:
|
|||||||
# redis配置
|
# redis配置
|
||||||
redis:
|
redis:
|
||||||
# Redis数据库索引(默认为0)
|
# Redis数据库索引(默认为0)
|
||||||
database: 3
|
database: 0
|
||||||
# Redis服务器地址
|
# Redis服务器地址
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
# Redis服务器连接端口
|
# Redis服务器连接端口
|
||||||
|
@ -47,7 +47,7 @@ spring:
|
|||||||
# redis配置
|
# redis配置
|
||||||
redis:
|
redis:
|
||||||
# Redis数据库索引(默认为0)
|
# Redis数据库索引(默认为0)
|
||||||
database: 3
|
database: 0
|
||||||
# Redis服务器地址
|
# Redis服务器地址
|
||||||
host: 127.0.0.1
|
host: 127.0.0.1
|
||||||
# Redis服务器连接端口
|
# Redis服务器连接端口
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
spring:
|
spring:
|
||||||
profiles:
|
profiles:
|
||||||
active: devp
|
active: devp
|
||||||
|
|
||||||
|
admin:
|
||||||
|
url: http://127.0.0.1:48080
|
||||||
|
key: backstage-contact
|
||||||
|
password: linghe2024
|
||||||
|
Loading…
Reference in New Issue
Block a user