fix:1.运管Token失效问题2.优化信息查询
This commit is contained in:
parent
6ca6a90804
commit
432cdbea0b
|
@ -14,4 +14,11 @@ public class NameValue implements Serializable {
|
||||||
private String name;
|
private String name;
|
||||||
|
|
||||||
private Boolean value;
|
private Boolean value;
|
||||||
|
|
||||||
|
private Integer usage; // 单位 MB
|
||||||
|
|
||||||
|
public NameValue(String name, Boolean value) {
|
||||||
|
this.name = name;
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
package org.jeecg.modules.exceptionhandler;
|
package org.jeecg.modules.exceptionhandler;
|
||||||
|
|
||||||
|
import feign.FeignException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.modules.controller.SystemMonitorController;
|
import org.jeecg.modules.controller.SystemMonitorController;
|
||||||
|
import org.jeecg.modules.feignclient.ManageUtil;
|
||||||
import org.springframework.http.HttpStatus;
|
import org.springframework.http.HttpStatus;
|
||||||
import org.springframework.http.ResponseEntity;
|
import org.springframework.http.ResponseEntity;
|
||||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||||
|
@ -12,11 +14,18 @@ import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||||
@Slf4j
|
@Slf4j
|
||||||
public class MonitorExceptionHandler {
|
public class MonitorExceptionHandler {
|
||||||
|
|
||||||
|
@ExceptionHandler(FeignException.Unauthorized.class)
|
||||||
|
public ResponseEntity<Result<?>> handleFeignExceptionUnauthorized(FeignException.Unauthorized e) {
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("运管服务Token失效,Token已刷新");
|
||||||
|
return ResponseEntity.status(HttpStatus.OK)
|
||||||
|
.body(Result.error("Management system token is invalid and refreshed"));
|
||||||
|
}
|
||||||
|
|
||||||
@ExceptionHandler(Exception.class)
|
@ExceptionHandler(Exception.class)
|
||||||
public ResponseEntity<Result<?>> handleException(Exception e) {
|
public ResponseEntity<Result<?>> handleException(Exception e) {
|
||||||
log.error("运管服务调用异常: {}", e.getMessage());
|
log.error("运管服务调用异常: {}", e.getMessage());
|
||||||
return ResponseEntity.status(HttpStatus.OK)
|
return ResponseEntity.status(HttpStatus.OK)
|
||||||
.body(Result.error("Management system is abnormal, data cannot be displayed"));
|
.body(Result.error("Management system is abnormal, data cannot be displayed"));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,14 @@ public class ManageUtil {
|
||||||
LoginVo loginVo = new LoginVo(username, password);
|
LoginVo loginVo = new LoginVo(username, password);
|
||||||
Result<LoginResult> loginRes = monitorAlarm.login(loginVo);
|
Result<LoginResult> loginRes = monitorAlarm.login(loginVo);
|
||||||
String token = loginRes.getResult().getToken();
|
String token = loginRes.getResult().getToken();
|
||||||
redisUtil.set(RedisConstant.MANAGE_TOKEN, token, JwtUtil.EXPIRE_TIME * 2 / 1000 - 10);
|
redisUtil.set(RedisConstant.MANAGE_TOKEN, token, JwtUtil.EXPIRE_TIME / 1000 - 10);
|
||||||
return token;
|
return token;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void refreshToken(){
|
||||||
|
LoginVo loginVo = new LoginVo(username, password);
|
||||||
|
Result<LoginResult> loginRes = monitorAlarm.login(loginVo);
|
||||||
|
String token = loginRes.getResult().getToken();
|
||||||
|
redisUtil.set(RedisConstant.MANAGE_TOKEN, token, JwtUtil.EXPIRE_TIME / 1000 - 10);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,11 +14,11 @@ public class MailBox {
|
||||||
public static Integer unreadMsg(QiyeOpenPlatSDK platSDK, RParam rParam){
|
public static Integer unreadMsg(QiyeOpenPlatSDK platSDK, RParam rParam){
|
||||||
Q q = Q.init(rParam);
|
Q q = Q.init(rParam);
|
||||||
if (ObjectUtil.isNull(platSDK))
|
if (ObjectUtil.isNull(platSDK))
|
||||||
return -1;
|
return 0;
|
||||||
R<Map<String, Integer>> result = platSDK.commonInvoke(q, MailBoxAPI.UNREADMSG);
|
R<Map<String, Integer>> result = platSDK.commonInvoke(q, MailBoxAPI.UNREADMSG);
|
||||||
Map<String, Integer> data = result.getData();
|
Map<String, Integer> data = result.getData();
|
||||||
if (ObjectUtil.isNull(data))
|
if (ObjectUtil.isNull(data))
|
||||||
return -1;
|
return 0;
|
||||||
return data.getOrDefault("count", -1);
|
return data.getOrDefault("count", 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,7 @@ import cn.hutool.core.util.ObjectUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
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 feign.FeignException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.MonitorConstant;
|
import org.jeecg.common.constant.MonitorConstant;
|
||||||
|
@ -113,7 +114,11 @@ public class AlarmItemServiceImpl extends ServiceImpl<AlarmItemMapper, AlarmItem
|
||||||
alarmItems.add(alarmItem);
|
alarmItems.add(alarmItem);
|
||||||
}
|
}
|
||||||
return saveOrUpdateBatch(alarmItems);
|
return saveOrUpdateBatch(alarmItems);
|
||||||
}catch (Exception e){
|
}catch (FeignException.Unauthorized e){
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("向运管系统同步Server监控项信息异常: Token失效,已刷新Token");
|
||||||
|
return false;
|
||||||
|
} catch (Exception e){
|
||||||
log.error("向运管系统同步Server监控项信息异常: {}", e.getMessage());
|
log.error("向运管系统同步Server监控项信息异常: {}", e.getMessage());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,10 @@ import com.netease.qiye.qiyeopenplatform.sdk.QiyeOpenPlatSDK;
|
||||||
import org.jeecg.common.api.vo.Result;
|
import org.jeecg.common.api.vo.Result;
|
||||||
import org.jeecg.common.constant.DateConstant;
|
import org.jeecg.common.constant.DateConstant;
|
||||||
import org.jeecg.common.constant.Prompt;
|
import org.jeecg.common.constant.Prompt;
|
||||||
|
import org.jeecg.common.constant.RedisConstant;
|
||||||
import org.jeecg.common.constant.SymbolConstant;
|
import org.jeecg.common.constant.SymbolConstant;
|
||||||
|
import org.jeecg.common.util.RedisUtil;
|
||||||
|
import org.jeecg.modules.base.dto.NameValue;
|
||||||
import org.jeecg.modules.base.entity.postgre.SysEmail;
|
import org.jeecg.modules.base.entity.postgre.SysEmail;
|
||||||
import org.jeecg.modules.base.entity.postgre.SysEmailLog;
|
import org.jeecg.modules.base.entity.postgre.SysEmailLog;
|
||||||
import org.jeecg.modules.mapper.SysEmailLogMapper;
|
import org.jeecg.modules.mapper.SysEmailLogMapper;
|
||||||
|
@ -39,6 +42,9 @@ import static org.jeecg.modules.base.enums.Qiye.IS;
|
||||||
@Service("sysEmailLogService")
|
@Service("sysEmailLogService")
|
||||||
public class SysEmailLogServiceImpl extends ServiceImpl<SysEmailLogMapper, SysEmailLog> implements ISysEmailLogService {
|
public class SysEmailLogServiceImpl extends ServiceImpl<SysEmailLogMapper, SysEmailLog> implements ISysEmailLogService {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private RedisUtil redisUtil;
|
||||||
|
|
||||||
@Autowired
|
@Autowired
|
||||||
private SysEmailMapper sysEmailMapper;
|
private SysEmailMapper sysEmailMapper;
|
||||||
|
|
||||||
|
@ -81,6 +87,11 @@ public class SysEmailLogServiceImpl extends ServiceImpl<SysEmailLogMapper, SysEm
|
||||||
Integer isQiye = sysEmail.getIsQiye();
|
Integer isQiye = sysEmail.getIsQiye();
|
||||||
String emailUsername = sysEmail.getUsername();
|
String emailUsername = sysEmail.getUsername();
|
||||||
Map<String, Object> map = MapUtil.newHashMap();
|
Map<String, Object> map = MapUtil.newHashMap();
|
||||||
|
map.put("usage", "0.00GB");
|
||||||
|
NameValue nameValue = (NameValue)redisUtil.hget(RedisConstant.EMAIL_STATUS, emailId);
|
||||||
|
if (ObjectUtil.isNotNull(nameValue))
|
||||||
|
map.put("usage", m2G(nameValue.getUsage())); // 邮箱空间使用量 单位G
|
||||||
|
map.put("unreadMsg", 0);
|
||||||
if (ObjectUtil.isNull(sysEmail) || StrUtil.isBlank(emailUsername))
|
if (ObjectUtil.isNull(sysEmail) || StrUtil.isBlank(emailUsername))
|
||||||
return map;
|
return map;
|
||||||
String[] info = StrUtil.split(emailUsername, SymbolConstant.AT);
|
String[] info = StrUtil.split(emailUsername, SymbolConstant.AT);
|
||||||
|
@ -96,10 +107,7 @@ public class SysEmailLogServiceImpl extends ServiceImpl<SysEmailLogMapper, SysEm
|
||||||
QiyeOpenPlatSDK platSDK = InstanceSDK.getInstance();
|
QiyeOpenPlatSDK platSDK = InstanceSDK.getInstance();
|
||||||
if (ObjectUtil.isNull(platSDK))
|
if (ObjectUtil.isNull(platSDK))
|
||||||
return map;
|
return map;
|
||||||
AccountInfo mailAccountInfo = Account.getMailAccountInfo(platSDK, rParam);
|
|
||||||
Integer usedQuota = mailAccountInfo.getUsedQuota();
|
|
||||||
Integer unreadMsg = MailBox.unreadMsg(platSDK, rParam);
|
Integer unreadMsg = MailBox.unreadMsg(platSDK, rParam);
|
||||||
map.put("usage", m2G(usedQuota)); // 邮箱空间使用量 单位G
|
|
||||||
map.put("unreadMsg", unreadMsg); // 未读邮件数量
|
map.put("unreadMsg", unreadMsg); // 未读邮件数量
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,6 +39,7 @@ import java.util.*;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static org.jeecg.modules.base.enums.Enabled.ENABLED;
|
import static org.jeecg.modules.base.enums.Enabled.ENABLED;
|
||||||
|
import static org.jeecg.modules.base.enums.Qiye.IS;
|
||||||
|
|
||||||
@Service("sysEmailService")
|
@Service("sysEmailService")
|
||||||
public class SysEmailServiceImpl extends ServiceImpl<SysEmailMapper, SysEmail> implements ISysEmailService {
|
public class SysEmailServiceImpl extends ServiceImpl<SysEmailMapper, SysEmail> implements ISysEmailService {
|
||||||
|
@ -81,37 +82,19 @@ public class SysEmailServiceImpl extends ServiceImpl<SysEmailMapper, SysEmail> i
|
||||||
// 邮箱状态Map key:id value:状态(true|false)
|
// 邮箱状态Map key:id value:状态(true|false)
|
||||||
String statusKey = RedisConstant.EMAIL_STATUS;
|
String statusKey = RedisConstant.EMAIL_STATUS;
|
||||||
Map<Object, Object> statusMap = redisUtil.hmget(statusKey);
|
Map<Object, Object> statusMap = redisUtil.hmget(statusKey);
|
||||||
// 查询是否有企业邮箱
|
|
||||||
List<Integer> hasQieye = emailDtos.stream().map(EmailDto::getIsQiye)
|
|
||||||
.filter(ObjectUtil::isNotNull).filter(isQiye -> Qiye.IS.getValue() == isQiye)
|
|
||||||
.collect(Collectors.toList());
|
|
||||||
QiyeOpenPlatSDK platSDK = null;
|
|
||||||
// 如果emailDtos中存在企业邮箱 则提前登录为查询邮箱信息做准备
|
|
||||||
if (CollUtil.isNotEmpty(hasQieye)) platSDK = InstanceSDK.getInstance();
|
|
||||||
// 遍历emailDtos 完善每一个邮箱的详细配置信息
|
// 遍历emailDtos 完善每一个邮箱的详细配置信息
|
||||||
for (EmailDto emailDto : emailDtos) {
|
for (EmailDto emailDto : emailDtos) {
|
||||||
String id = emailDto.getId();
|
|
||||||
Integer isQiye = emailDto.getIsQiye();
|
|
||||||
String capacity = "--";
|
|
||||||
if (ObjectUtil.isNotNull(isQiye) && Qiye.IS.getValue() == isQiye){
|
|
||||||
String username = emailDto.getUsername();
|
|
||||||
String[] info = StrUtil.split(username, SymbolConstant.AT);
|
|
||||||
if (ArrayUtil.length(info) == 2 && ObjectUtil.isNotNull(platSDK)){
|
|
||||||
String accountName = info[0];
|
|
||||||
String domain = info[1];
|
|
||||||
RParam param = new RParam(accountName, domain);
|
|
||||||
AccountInfo accountInfo = Account.getMailAccountInfo(platSDK, param);
|
|
||||||
Integer usedQuota = accountInfo.getUsedQuota();
|
|
||||||
if (ObjectUtil.isNotNull(usedQuota))
|
|
||||||
capacity = usedQuota + " MB";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
NameValue nameValue = (NameValue) statusMap.get(id);
|
|
||||||
boolean online = false;
|
boolean online = false;
|
||||||
|
String capacity = "--";
|
||||||
|
String id = emailDto.getId();
|
||||||
|
NameValue nameValue = (NameValue) statusMap.get(id);
|
||||||
if (ObjectUtil.isNotNull(nameValue)){
|
if (ObjectUtil.isNotNull(nameValue)){
|
||||||
Boolean value = nameValue.getValue();
|
Boolean value = nameValue.getValue();
|
||||||
|
Integer usage = nameValue.getUsage();
|
||||||
if (ObjectUtil.isNotNull(value))
|
if (ObjectUtil.isNotNull(value))
|
||||||
online = value;
|
online = value;
|
||||||
|
if (ObjectUtil.isNotNull(usage))
|
||||||
|
capacity = usage + "MB";
|
||||||
}
|
}
|
||||||
emailDto.setOnline(online).setStoerCapacity(capacity).setStoerRed(true)
|
emailDto.setOnline(online).setStoerCapacity(capacity).setStoerRed(true)
|
||||||
.setToday(todayMap.getOrDefault(id, 0))
|
.setToday(todayMap.getOrDefault(id, 0))
|
||||||
|
@ -238,12 +221,33 @@ public class SysEmailServiceImpl extends ServiceImpl<SysEmailMapper, SysEmail> i
|
||||||
public void status2Redis() {
|
public void status2Redis() {
|
||||||
// 获取所有配置的邮箱服务器
|
// 获取所有配置的邮箱服务器
|
||||||
List<SysEmail> emails = list();
|
List<SysEmail> emails = list();
|
||||||
|
// 查询是否有企业邮箱
|
||||||
|
List<Integer> hasQieye = emails.stream().map(SysEmail::getIsQiye)
|
||||||
|
.filter(ObjectUtil::isNotNull).filter(isQiye -> Qiye.IS.getValue() == isQiye)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
QiyeOpenPlatSDK platSDK = null;
|
||||||
|
// 如果emails中存在企业邮箱 则提前登录为查询邮箱信息做准备
|
||||||
|
if (CollUtil.isNotEmpty(hasQieye)) platSDK = InstanceSDK.getInstance();
|
||||||
Map<String, Object> statusMap = new HashMap<>();
|
Map<String, Object> statusMap = new HashMap<>();
|
||||||
for (SysEmail email : emails) {
|
for (SysEmail email : emails) {
|
||||||
String id = email.getId();
|
String id = email.getId();
|
||||||
String name = email.getName();
|
String name = email.getName();
|
||||||
|
Integer isQiye = email.getIsQiye();
|
||||||
boolean isConn = EmailUtil.isConnection(email);
|
boolean isConn = EmailUtil.isConnection(email);
|
||||||
statusMap.put(id, new NameValue(name, isConn));
|
NameValue nameValue = new NameValue(name, isConn);
|
||||||
|
if (ObjectUtil.isNotNull(isQiye) && isQiye == IS.getValue()){
|
||||||
|
String username = email.getUsername();
|
||||||
|
String[] info = StrUtil.split(username, SymbolConstant.AT);
|
||||||
|
if (ArrayUtil.length(info) == 2 && ObjectUtil.isNotNull(platSDK)){
|
||||||
|
String accountName = info[0];
|
||||||
|
String domain = info[1];
|
||||||
|
RParam param = new RParam(accountName, domain);
|
||||||
|
AccountInfo accountInfo = Account.getMailAccountInfo(platSDK, param);
|
||||||
|
Integer usedQuota = accountInfo.getUsedQuota();
|
||||||
|
nameValue.setUsage(usedQuota);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
statusMap.put(id, nameValue);
|
||||||
}
|
}
|
||||||
// 将邮箱服务器连接状态更新到reids
|
// 将邮箱服务器连接状态更新到reids
|
||||||
String statusKey = RedisConstant.EMAIL_STATUS;
|
String statusKey = RedisConstant.EMAIL_STATUS;
|
||||||
|
|
|
@ -10,6 +10,7 @@ import cn.hutool.core.util.StrUtil;
|
||||||
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
|
||||||
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
|
||||||
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
|
||||||
|
import feign.FeignException;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jeecg.common.api.QueryRequest;
|
import org.jeecg.common.api.QueryRequest;
|
||||||
|
@ -78,7 +79,10 @@ public class SysServerServiceImpl extends ServiceImpl<SysServerMapper, SysServer
|
||||||
String token = ManageUtil.getToken();
|
String token = ManageUtil.getToken();
|
||||||
hosts = monitorAlarm.listOnApp(ServerStatus.ON.getValue(),
|
hosts = monitorAlarm.listOnApp(ServerStatus.ON.getValue(),
|
||||||
MonitorConstant.SERVER_APP, token).getResult().getRecords();
|
MonitorConstant.SERVER_APP, token).getResult().getRecords();
|
||||||
}catch (Exception e){
|
}catch (FeignException.Unauthorized e){
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("向运管系统查询Hosts信息异常: Token失效,已刷新Token");
|
||||||
|
} catch (Exception e){
|
||||||
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
// 将List<Host>转换为Map<hostId,Host>
|
// 将List<Host>转换为Map<hostId,Host>
|
||||||
|
@ -250,7 +254,10 @@ public class SysServerServiceImpl extends ServiceImpl<SysServerMapper, SysServer
|
||||||
try {
|
try {
|
||||||
String token = ManageUtil.getToken();
|
String token = ManageUtil.getToken();
|
||||||
host = monitorAlarm.summary(hostId, MonitorConstant.PAGE_SUMMARY, token).getResult();
|
host = monitorAlarm.summary(hostId, MonitorConstant.PAGE_SUMMARY, token).getResult();
|
||||||
}catch (Exception e){
|
}catch (FeignException.Unauthorized e){
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("向运管系统查询Hosts信息异常: Token失效,已刷新Token");
|
||||||
|
} catch (Exception e){
|
||||||
log.error("向运管系统查询Host信息异常: {}", e.getMessage());
|
log.error("向运管系统查询Host信息异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
/* BasicInfo */
|
/* BasicInfo */
|
||||||
|
@ -338,7 +345,10 @@ public class SysServerServiceImpl extends ServiceImpl<SysServerMapper, SysServer
|
||||||
values.put(serverId, new NameString(name, ServerStatus.UNKNOWN.getValue()));
|
values.put(serverId, new NameString(name, ServerStatus.UNKNOWN.getValue()));
|
||||||
}
|
}
|
||||||
redisUtil.hmset(key, values);
|
redisUtil.hmset(key, values);
|
||||||
}catch (Exception e){
|
}catch (FeignException.Unauthorized e){
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("向运管系统查询Hosts信息异常: Token失效,已刷新Token");
|
||||||
|
} catch (Exception e){
|
||||||
defaultStatus(sysServers);
|
defaultStatus(sysServers);
|
||||||
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
@ -386,6 +396,9 @@ public class SysServerServiceImpl extends ServiceImpl<SysServerMapper, SysServer
|
||||||
server.setHostId(host.getHostId());
|
server.setHostId(host.getHostId());
|
||||||
status = host.getStatus();
|
status = host.getStatus();
|
||||||
}
|
}
|
||||||
|
}catch (FeignException.Unauthorized e){
|
||||||
|
ManageUtil.refreshToken();
|
||||||
|
log.warn("向运管系统查询Hosts信息异常: Token失效,已刷新Token");
|
||||||
}catch (Exception e){
|
}catch (Exception e){
|
||||||
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
log.error("向运管系统查询Hosts信息异常: {}", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user