mirror of
https://github.com/NapNeko/NapCatQQ.git
synced 2025-07-19 12:03:37 +00:00
(partially) fix: 'throw' of exception caught locally
This commit is contained in:
@@ -60,20 +60,17 @@ export class QQBasicInfoWrapper {
|
|||||||
|
|
||||||
getAppidV2(): { appid: string; qua: string } {
|
getAppidV2(): { appid: string; qua: string } {
|
||||||
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
const appidTbale = AppidTable as unknown as QQAppidTableType;
|
||||||
try {
|
const fullVersion = this.getFullQQVesion();
|
||||||
const fullVersion = this.getFullQQVesion();
|
if (fullVersion) {
|
||||||
if (!fullVersion) throw new Error('QQ版本获取失败');
|
|
||||||
const data = appidTbale[fullVersion];
|
const data = appidTbale[fullVersion];
|
||||||
if (data) {
|
if (data) {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
} catch (e) {
|
|
||||||
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
|
||||||
}
|
}
|
||||||
// 以下是兜底措施
|
|
||||||
this.context.logger.log(
|
// else
|
||||||
`[QQ版本兼容性检测] ${this.getFullQQVesion()} 版本兼容性不佳,可能会导致一些功能无法正常使用`,
|
this.context.logger.log(`[QQ版本兼容性检测] 获取Appid异常 请检测NapCat/QQNT是否正常`);
|
||||||
);
|
this.context.logger.log(`[QQ版本兼容性检测] ${fullVersion} 版本兼容性不佳,可能会导致一些功能无法正常使用`,);
|
||||||
return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() };
|
return { appid: systemPlatform === 'linux' ? '537240795' : '537240709', qua: this.getQUAInternal() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -184,11 +184,8 @@ export class NTQQWebApi {
|
|||||||
const HonorInfo: any = { group_id: groupCode };
|
const HonorInfo: any = { group_id: groupCode };
|
||||||
|
|
||||||
if (getType === WebHonorType.TALKATIVE || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.TALKATIVE || getType === WebHonorType.ALL) {
|
||||||
try {
|
const RetInternal = await getDataInternal(groupCode, 1);
|
||||||
const RetInternal = await getDataInternal(groupCode, 1);
|
if (RetInternal) {
|
||||||
if (!RetInternal) {
|
|
||||||
throw new Error('获取龙王信息失败');
|
|
||||||
}
|
|
||||||
HonorInfo.current_talkative = {
|
HonorInfo.current_talkative = {
|
||||||
user_id: RetInternal[0]?.uin,
|
user_id: RetInternal[0]?.uin,
|
||||||
avatar: RetInternal[0]?.avatar,
|
avatar: RetInternal[0]?.avatar,
|
||||||
@@ -206,16 +203,13 @@ export class NTQQWebApi {
|
|||||||
nickname: talkative_ele?.name,
|
nickname: talkative_ele?.name,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} else {
|
||||||
this.context.logger.logDebug(e);
|
this.context.logger.logError('获取龙王信息失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
||||||
try {
|
const RetInternal = await getDataInternal(groupCode, 2);
|
||||||
const RetInternal = await getDataInternal(groupCode, 2);
|
if (RetInternal) {
|
||||||
if (!RetInternal) {
|
|
||||||
throw new Error('获取群聊之火失败');
|
|
||||||
}
|
|
||||||
HonorInfo.performer_list = [];
|
HonorInfo.performer_list = [];
|
||||||
for (const performer_ele of RetInternal) {
|
for (const performer_ele of RetInternal) {
|
||||||
HonorInfo.performer_list.push({
|
HonorInfo.performer_list.push({
|
||||||
@@ -225,16 +219,13 @@ export class NTQQWebApi {
|
|||||||
description: performer_ele?.desc,
|
description: performer_ele?.desc,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} else {
|
||||||
this.context.logger.logDebug(e);
|
this.context.logger.logError('获取群聊之火失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.PERFORMER || getType === WebHonorType.ALL) {
|
||||||
try {
|
const RetInternal = await getDataInternal(groupCode, 3);
|
||||||
const RetInternal = await getDataInternal(groupCode, 3);
|
if (RetInternal) {
|
||||||
if (!RetInternal) {
|
|
||||||
throw new Error('获取群聊炽焰失败');
|
|
||||||
}
|
|
||||||
HonorInfo.legend_list = [];
|
HonorInfo.legend_list = [];
|
||||||
for (const legend_ele of RetInternal) {
|
for (const legend_ele of RetInternal) {
|
||||||
HonorInfo.legend_list.push({
|
HonorInfo.legend_list.push({
|
||||||
@@ -244,16 +235,13 @@ export class NTQQWebApi {
|
|||||||
desc: legend_ele?.description,
|
desc: legend_ele?.description,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} else {
|
||||||
this.context.logger.logDebug('获取群聊炽焰失败', e);
|
this.context.logger.logError('获取群聊炽焰失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||||
try {
|
const RetInternal = await getDataInternal(groupCode, 6);
|
||||||
const RetInternal = await getDataInternal(groupCode, 6);
|
if (RetInternal) {
|
||||||
if (!RetInternal) {
|
|
||||||
throw new Error('获取快乐源泉失败');
|
|
||||||
}
|
|
||||||
HonorInfo.emotion_list = [];
|
HonorInfo.emotion_list = [];
|
||||||
for (const emotion_ele of RetInternal) {
|
for (const emotion_ele of RetInternal) {
|
||||||
HonorInfo.emotion_list.push({
|
HonorInfo.emotion_list.push({
|
||||||
@@ -263,11 +251,11 @@ export class NTQQWebApi {
|
|||||||
desc: emotion_ele.description,
|
desc: emotion_ele.description,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} else {
|
||||||
this.context.logger.logDebug('获取快乐源泉失败', e);
|
this.context.logger.logError('获取快乐源泉失败');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
//冒尖小春笋好像已经被tx扬了
|
// 冒尖小春笋好像已经被tx扬了 R.I.P.
|
||||||
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
if (getType === WebHonorType.EMOTION || getType === WebHonorType.ALL) {
|
||||||
HonorInfo.strong_newbie_list = [];
|
HonorInfo.strong_newbie_list = [];
|
||||||
}
|
}
|
||||||
|
@@ -34,61 +34,55 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
const NTQQMsgApi = this.core.apis.MsgApi;
|
const NTQQMsgApi = this.core.apis.MsgApi;
|
||||||
const NTQQGroupApi = this.core.apis.GroupApi;
|
const NTQQGroupApi = this.core.apis.GroupApi;
|
||||||
const NTQQFileApi = this.core.apis.FileApi;
|
const NTQQFileApi = this.core.apis.FileApi;
|
||||||
let UuidData: {
|
|
||||||
high: string;
|
|
||||||
low: string;
|
|
||||||
} | undefined;
|
|
||||||
try {
|
try {
|
||||||
UuidData = UUIDConverter.decode(payload.file);
|
const uuidData = UUIDConverter.decode(payload.file);
|
||||||
if (UuidData) {
|
const peerUin = uuidData.high;
|
||||||
const peerUin = UuidData.high;
|
const msgId = uuidData.low;
|
||||||
const msgId = UuidData.low;
|
const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin);
|
||||||
const isGroup: boolean = !!(await NTQQGroupApi.getGroups(false)).find(e => e.groupCode == peerUin);
|
let peer: Peer | undefined;
|
||||||
let peer: Peer | undefined;
|
//识别Peer
|
||||||
//识别Peer
|
if (isGroup) {
|
||||||
if (isGroup) {
|
peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: peerUin };
|
||||||
peer = { chatType: ChatType.KCHATTYPEGROUP, peerUid: peerUin };
|
|
||||||
}
|
|
||||||
const PeerUid = await NTQQUserApi.getUidByUinV2(peerUin);
|
|
||||||
if (PeerUid) {
|
|
||||||
const isBuddy = await NTQQFriendApi.isBuddy(PeerUid);
|
|
||||||
if (isBuddy) {
|
|
||||||
peer = { chatType: ChatType.KCHATTYPEC2C, peerUid: PeerUid };
|
|
||||||
} else {
|
|
||||||
peer = { chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: PeerUid };
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!peer) {
|
|
||||||
throw new Error('chattype not support');
|
|
||||||
}
|
|
||||||
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]);
|
|
||||||
if (msgList.msgList.length == 0) {
|
|
||||||
throw new Error('msg not found');
|
|
||||||
}
|
|
||||||
const msg = msgList.msgList[0];
|
|
||||||
const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT);
|
|
||||||
if (!findEle) {
|
|
||||||
throw new Error('element not found');
|
|
||||||
}
|
|
||||||
const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', '');
|
|
||||||
const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0';
|
|
||||||
const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || '';
|
|
||||||
const res: GetFileResponse = {
|
|
||||||
file: downloadPath,
|
|
||||||
url: downloadPath,
|
|
||||||
file_size: fileSize,
|
|
||||||
file_name: fileName,
|
|
||||||
};
|
|
||||||
if (true/*enableLocalFile2Url*/ && downloadPath) {
|
|
||||||
try {
|
|
||||||
res.base64 = await fs.readFile(downloadPath, 'base64');
|
|
||||||
} catch (e) {
|
|
||||||
throw new Error('文件下载失败. ' + e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
//不手动删除?文件持久化了
|
|
||||||
return res;
|
|
||||||
}
|
}
|
||||||
|
const PeerUid = await NTQQUserApi.getUidByUinV2(peerUin);
|
||||||
|
if (PeerUid) {
|
||||||
|
const isBuddy = await NTQQFriendApi.isBuddy(PeerUid);
|
||||||
|
if (isBuddy) {
|
||||||
|
peer = { chatType: ChatType.KCHATTYPEC2C, peerUid: PeerUid };
|
||||||
|
} else {
|
||||||
|
peer = { chatType: ChatType.KCHATTYPETEMPC2CFROMGROUP, peerUid: PeerUid };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!peer) {
|
||||||
|
throw new Error('chattype not support');
|
||||||
|
}
|
||||||
|
const msgList = await NTQQMsgApi.getMsgsByMsgId(peer, [msgId]);
|
||||||
|
if (msgList.msgList.length == 0) {
|
||||||
|
throw new Error('msg not found');
|
||||||
|
}
|
||||||
|
const msg = msgList.msgList[0];
|
||||||
|
const findEle = msg.elements.find(e => e.elementType == ElementType.VIDEO || e.elementType == ElementType.FILE || e.elementType == ElementType.PTT);
|
||||||
|
if (!findEle) {
|
||||||
|
throw new Error('element not found');
|
||||||
|
}
|
||||||
|
const downloadPath = await NTQQFileApi.downloadMedia(msgId, msg.chatType, msg.peerUid, findEle.elementId, '', '');
|
||||||
|
const fileSize = findEle?.videoElement?.fileSize || findEle?.fileElement?.fileSize || findEle?.pttElement?.fileSize || '0';
|
||||||
|
const fileName = findEle?.videoElement?.fileName || findEle?.fileElement?.fileName || findEle?.pttElement?.fileName || '';
|
||||||
|
const res: GetFileResponse = {
|
||||||
|
file: downloadPath,
|
||||||
|
url: downloadPath,
|
||||||
|
file_size: fileSize,
|
||||||
|
file_name: fileName,
|
||||||
|
};
|
||||||
|
if (/* enableLocalFile2Url && */ downloadPath) {
|
||||||
|
try {
|
||||||
|
res.base64 = await fs.readFile(downloadPath, 'base64');
|
||||||
|
} catch (e) {
|
||||||
|
throw new Error('文件下载失败. ' + e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//不手动删除?文件持久化了
|
||||||
|
return res;
|
||||||
} catch {
|
} catch {
|
||||||
this.core.context.logger.logDebug('GetFileBase Mode - 1 Error');
|
this.core.context.logger.logDebug('GetFileBase Mode - 1 Error');
|
||||||
}
|
}
|
||||||
@@ -119,7 +113,7 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
file_size: NTSearchNameResult[0].fileSize.toString(),
|
file_size: NTSearchNameResult[0].fileSize.toString(),
|
||||||
file_name: NTSearchNameResult[0].fileName,
|
file_name: NTSearchNameResult[0].fileName,
|
||||||
};
|
};
|
||||||
if (true/*enableLocalFile2Url*/ && downloadPath) {
|
if (/* enableLocalFile2Url && */ downloadPath) {
|
||||||
try {
|
try {
|
||||||
res.base64 = await fs.readFile(downloadPath, 'base64');
|
res.base64 = await fs.readFile(downloadPath, 'base64');
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -130,66 +124,6 @@ export class GetFileBase extends BaseAction<GetFilePayload, GetFileResponse> {
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
throw new Error('file not found');
|
throw new Error('file not found');
|
||||||
// let cache = await dbUtil.getFileCacheByName(payload.file);
|
|
||||||
// if (!cache) {
|
|
||||||
// cache = await dbUtil.getFileCacheByUuid(payload.file);
|
|
||||||
// }
|
|
||||||
// if (!cache) {
|
|
||||||
// throw new Error('file not found');
|
|
||||||
// }
|
|
||||||
// const { enableLocalFile2Url } = ob11Config;
|
|
||||||
// try {
|
|
||||||
// await fs.access(cache.path, fs.constants.F_OK);
|
|
||||||
// } catch (e) {
|
|
||||||
// logDebug('local file not found, start download...');
|
|
||||||
// // if (cache.url) {
|
|
||||||
// // const downloadResult = await uri2local(cache.url);
|
|
||||||
// // if (downloadResult.success) {
|
|
||||||
// // cache.path = downloadResult.path;
|
|
||||||
// // dbUtil.updateFileCache(cache).then();
|
|
||||||
// // } else {
|
|
||||||
// // throw new Error('file download failed. ' + downloadResult.errMsg);
|
|
||||||
// // }
|
|
||||||
// // } else {
|
|
||||||
// // // 没有url的可能是私聊文件或者群文件,需要自己下载
|
|
||||||
// // log('需要调用 NTQQ 下载文件api');
|
|
||||||
// let peer = MessageUnique.getPeerByMsgId(cache.msgId);
|
|
||||||
// let msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId);
|
|
||||||
// // log('文件 msg', msg);
|
|
||||||
// if (msg) {
|
|
||||||
// // 构建下载函数
|
|
||||||
// const downloadPath = await NTQQFileApi.downloadMedia(msg.msgId, msg.chatType, msg.peerUid,
|
|
||||||
// cache.elementId, '', '');
|
|
||||||
// // await sleep(1000);
|
|
||||||
|
|
||||||
// // log('download result', downloadPath);
|
|
||||||
// let peer = MessageUnique.getPeerByMsgId(cache.msgId);
|
|
||||||
// msg = await NTQQMsgApi.getMsgsByMsgId(peer?.Peer!,cache.msgId);
|
|
||||||
// // log('下载完成后的msg', msg);
|
|
||||||
// cache.path = downloadPath!;
|
|
||||||
// dbUtil.updateFileCache(cache).then();
|
|
||||||
// // log('下载完成后的msg', msg);
|
|
||||||
// // }
|
|
||||||
// }
|
|
||||||
|
|
||||||
// }
|
|
||||||
// // log('file found', cache);
|
|
||||||
// const res: GetFileResponse = {
|
|
||||||
// file: cache.path,
|
|
||||||
// url: cache.url,
|
|
||||||
// file_size: cache.size.toString(),
|
|
||||||
// file_name: cache.name
|
|
||||||
// };
|
|
||||||
// if (enableLocalFile2Url) {
|
|
||||||
// if (!cache.url) {
|
|
||||||
// try {
|
|
||||||
// res.base64 = await fs.readFile(cache.path, 'base64');
|
|
||||||
// } catch (e) {
|
|
||||||
// throw new Error('文件下载失败. ' + e);
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//return res;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -20,16 +20,12 @@ export default class SendLike extends BaseAction<Payload, null> {
|
|||||||
async _handle(payload: Payload): Promise<null> {
|
async _handle(payload: Payload): Promise<null> {
|
||||||
const NTQQUserApi = this.core.apis.UserApi;
|
const NTQQUserApi = this.core.apis.UserApi;
|
||||||
//logDebug('点赞参数', payload);
|
//logDebug('点赞参数', payload);
|
||||||
try {
|
const qq = payload.user_id.toString();
|
||||||
const qq = payload.user_id.toString();
|
const uid: string = await NTQQUserApi.getUidByUinV2(qq) || '';
|
||||||
const uid: string = await NTQQUserApi.getUidByUinV2(qq) || '';
|
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1);
|
||||||
const result = await NTQQUserApi.like(uid, parseInt(payload.times?.toString()) || 1);
|
//logDebug('点赞结果', result);
|
||||||
//logDebug('点赞结果', result);
|
if (result.result !== 0) {
|
||||||
if (result.result !== 0) {
|
throw `点赞失败 ${result.errMsg}`;
|
||||||
throw Error(result.errMsg);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
throw `点赞失败 ${e}`;
|
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
@@ -89,8 +89,9 @@ export class OneBotGroupApi {
|
|||||||
parseInt(memberUin),
|
parseInt(memberUin),
|
||||||
parseInt(operatorUin),
|
parseInt(operatorUin),
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
return undefined;
|
||||||
}
|
}
|
||||||
return undefined;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
async parseGroupKickEvent(GroupCode: string, grayTipElement: GrayTipElement) {
|
||||||
@@ -118,35 +119,33 @@ export class OneBotGroupApi {
|
|||||||
attributeNamePrefix: '',
|
attributeNamePrefix: '',
|
||||||
}).parse(grayTipElement.xmlElement.content);
|
}).parse(grayTipElement.xmlElement.content);
|
||||||
this.core.context.logger.logDebug('收到表情回应我的消息', emojiLikeData);
|
this.core.context.logger.logDebug('收到表情回应我的消息', emojiLikeData);
|
||||||
try {
|
const senderUin = emojiLikeData.gtip.qq.jp;
|
||||||
const senderUin = emojiLikeData.gtip.qq.jp;
|
const msgSeq = emojiLikeData.gtip.url.msgseq;
|
||||||
const msgSeq = emojiLikeData.gtip.url.msgseq;
|
const emojiId = emojiLikeData.gtip.face.id;
|
||||||
const emojiId = emojiLikeData.gtip.face.id;
|
const peer = {
|
||||||
const peer = {
|
chatType: ChatType.KCHATTYPEGROUP,
|
||||||
chatType: ChatType.KCHATTYPEGROUP,
|
guildId: '',
|
||||||
guildId: '',
|
peerUid: GroupCode,
|
||||||
peerUid: GroupCode,
|
};
|
||||||
};
|
const replyMsgList = (await NTQQMsgApi.getMsgExBySeq(peer, msgSeq)).msgList;
|
||||||
const replyMsgList = (await NTQQMsgApi.getMsgExBySeq(peer, msgSeq)).msgList;
|
if (replyMsgList.length < 1) {
|
||||||
if (replyMsgList.length < 1) {
|
return;
|
||||||
return;
|
|
||||||
}
|
|
||||||
const replyMsg = replyMsgList.filter(e => e.msgSeq == msgSeq).sort((a, b) => parseInt(a.msgTime) - parseInt(b.msgTime))[0];
|
|
||||||
//console.log("表情回应消息长度检测", msgSeq, replyMsg.elements);
|
|
||||||
if (!replyMsg) throw new Error('找不到回应消息');
|
|
||||||
return new OB11GroupMsgEmojiLikeEvent(
|
|
||||||
this.core,
|
|
||||||
parseInt(GroupCode),
|
|
||||||
parseInt(senderUin),
|
|
||||||
MessageUnique.getShortIdByMsgId(replyMsg.msgId)!,
|
|
||||||
[{
|
|
||||||
emoji_id: emojiId,
|
|
||||||
count: 1,
|
|
||||||
}],
|
|
||||||
);
|
|
||||||
} catch (e: any) {
|
|
||||||
this.core.context.logger.logError('解析表情回应消息失败', e.stack);
|
|
||||||
}
|
}
|
||||||
return undefined;
|
const replyMsg = replyMsgList.filter(e => e.msgSeq == msgSeq).sort((a, b) => parseInt(a.msgTime) - parseInt(b.msgTime))[0];
|
||||||
|
//console.log("表情回应消息长度检测", msgSeq, replyMsg.elements);
|
||||||
|
if (!replyMsg) {
|
||||||
|
this.core.context.logger.logError('解析表情回应消息失败: 未找到回应消息');
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
return new OB11GroupMsgEmojiLikeEvent(
|
||||||
|
this.core,
|
||||||
|
parseInt(GroupCode),
|
||||||
|
parseInt(senderUin),
|
||||||
|
MessageUnique.getShortIdByMsgId(replyMsg.msgId)!,
|
||||||
|
[{
|
||||||
|
emoji_id: emojiId,
|
||||||
|
count: 1,
|
||||||
|
}],
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Reference in New Issue
Block a user