🐞 fix(gvg): 添加情报页面
This commit is contained in:
@@ -1,5 +1,6 @@
|
|||||||
import { Application, ChannelService, HandlerService, } from 'pinus';
|
import { Application, ChannelService, HandlerService, } from 'pinus';
|
||||||
import { setHiddenData } from '../../../services/dataService';
|
import { setHiddenData } from '../../../services/dataService';
|
||||||
|
import { setGVGServerGroup } from '../../../services/gvg/gvgService';
|
||||||
import { errlogger } from '../../../util/logger';
|
import { errlogger } from '../../../util/logger';
|
||||||
|
|
||||||
export default function (app: Application) {
|
export default function (app: Application) {
|
||||||
@@ -36,4 +37,12 @@ export class GMRemote {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setGVGServerGroup() {
|
||||||
|
try {
|
||||||
|
await setGVGServerGroup();
|
||||||
|
} catch(e) {
|
||||||
|
errlogger.error(`remote ${__filename} \n ${e.stack}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -2,7 +2,7 @@ import { Application, BackendSession, ChannelService, HandlerService, pinus } fr
|
|||||||
import { GVG_ITEM, DATA_NAME, GVG_ACTIVE_TYPE, GVG_PERIOD, GVG_SERVER_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, LEAGUE_MANAGE_TYPE, STATUS, GVG_REC_TYPE, TASK_TYPE, GVG_TECH_TYPE, PUSH_ROUTE } from "../../../consts";
|
import { GVG_ITEM, DATA_NAME, GVG_ACTIVE_TYPE, GVG_PERIOD, GVG_SERVER_TYPE, ITEM_CHANGE_REASON, LEAGUE_JOB, LEAGUE_MANAGE_TYPE, STATUS, GVG_REC_TYPE, TASK_TYPE, GVG_TECH_TYPE, PUSH_ROUTE } from "../../../consts";
|
||||||
import { GVGLeagueModel } from "../../../db/GVGLeague";
|
import { GVGLeagueModel } from "../../../db/GVGLeague";
|
||||||
import { GVGLeaguePrepareModel } from "../../../db/GVGLeaguePrepare";
|
import { GVGLeaguePrepareModel } from "../../../db/GVGLeaguePrepare";
|
||||||
import { GVGMainData, LeagueContributeInfo, LeagueMemberContributeInfo, LeagueMemberListInfo } from "../../../domain/gvgField/returnData";
|
import { GuardCityInfoPage, GVGMainData, LeagueContributeInfo, LeagueMemberContributeInfo, LeagueRankInInfoPage } from "../../../domain/gvgField/returnData";
|
||||||
import { getRandEelm, resResult } from "../../../pubUtils/util";
|
import { getRandEelm, resResult } from "../../../pubUtils/util";
|
||||||
import { calLeagueCe, getGroupIdOfServer, getGroupKey, getGVGConfig, getGVGPeriodData, getGVGServerType, getServerTypeByTime } from "../../../services/gvg/gvgService";
|
import { calLeagueCe, getGroupIdOfServer, getGroupKey, getGVGConfig, getGVGPeriodData, getGVGServerType, getServerTypeByTime } from "../../../services/gvg/gvgService";
|
||||||
import { autoCreateLeague, checkCanChooseJob, checkCanPrepare, checkLeagueAuth, getMyAuth } from "../../../services/gvg/gvgTeamService";
|
import { autoCreateLeague, checkCanChooseJob, checkCanPrepare, checkLeagueAuth, getMyAuth } from "../../../services/gvg/gvgTeamService";
|
||||||
@@ -25,6 +25,8 @@ import { getFightTimeByPeriod, getMyVestiges, getVestiges } from "../../../servi
|
|||||||
import { getSeconds } from "../../../pubUtils/timeUtil";
|
import { getSeconds } from "../../../pubUtils/timeUtil";
|
||||||
import { GVGVestigeRankModel } from "../../../db/GVGVestigeRank";
|
import { GVGVestigeRankModel } from "../../../db/GVGVestigeRank";
|
||||||
import { addTechActivateMessage, addTechUnlockMessage } from "../../../services/gvg/gvgRecService";
|
import { addTechActivateMessage, addTechUnlockMessage } from "../../../services/gvg/gvgRecService";
|
||||||
|
import { GuildModel } from "../../../db/Guild";
|
||||||
|
import { GVGCityModel } from "../../../db/GVGCity";
|
||||||
|
|
||||||
export default function (app: Application) {
|
export default function (app: Application) {
|
||||||
new HandlerService(app, {});
|
new HandlerService(app, {});
|
||||||
@@ -461,6 +463,78 @@ export class GVGHandler {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 情报页面:联军排名
|
||||||
|
async getLeagueRankInfo(msg: {}, session: BackendSession) {
|
||||||
|
|
||||||
|
const roleId = session.get('roleId');
|
||||||
|
const serverId = session.get('serverId');
|
||||||
|
const guildCode = session.get('guildCode');
|
||||||
|
const { configId } = getGVGConfig();
|
||||||
|
const groupKey = await getGroupKey(serverId);
|
||||||
|
|
||||||
|
let myLeague = await GVGLeagueModel.findLeagueByGuild(guildCode);
|
||||||
|
if(!myLeague) return resResult(STATUS.GVG_LEAGUE_NOT_EXIST);
|
||||||
|
|
||||||
|
const prepares = await GVGLeaguePrepareModel.getLvRank(configId);
|
||||||
|
const leagues = await GVGLeagueModel.findByCodes(prepares.map(cur => cur.leagueCode));
|
||||||
|
const guilds = await GuildModel.findByCodesWithoutPopulate(leagues.reduce((pre, cur) => [...pre, ...cur.guildCodes], []));
|
||||||
|
const cities = await GVGCityModel.findGuardCity(configId, groupKey);
|
||||||
|
|
||||||
|
let ranks: LeagueRankInInfoPage[] = [], myRank: LeagueRankInInfoPage = undefined;
|
||||||
|
prepares.forEach((prepare, index) => {
|
||||||
|
let league = leagues.find(cur => cur.leagueCode == prepare.leagueCode);
|
||||||
|
if(!league) return;
|
||||||
|
let leagueGuilds = guilds.filter(cur => cur.leagueCode == league.leagueCode);
|
||||||
|
let leagueCe = leagueGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);
|
||||||
|
let guardCities = cities.filter(cur => cur.guardLeague == league.leagueCode).map(cur => cur.cityId);
|
||||||
|
let data = new LeagueRankInInfoPage(index + 1, league, prepare, leagueCe, guardCities);
|
||||||
|
if(myLeague.leagueCode == league.leagueCode) myRank = data;
|
||||||
|
ranks.push(data);
|
||||||
|
});
|
||||||
|
|
||||||
|
if(!myRank) {
|
||||||
|
let myGuilds = await GuildModel.findByCodes(myLeague.guildCodes);
|
||||||
|
let leagueCe = myGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);
|
||||||
|
let guardCities = cities.filter(cur => cur.guardLeague == myLeague.leagueCode).map(cur => cur.cityId);
|
||||||
|
myRank = new LeagueRankInInfoPage(0, myLeague, null, leagueCe, guardCities);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resResult(STATUS.SUCCESS, {
|
||||||
|
ranks, myRank
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 情报页面:城池占领
|
||||||
|
async getGuardCityInfo(msg: {}, session: BackendSession) {
|
||||||
|
|
||||||
|
const serverId = session.get('serverId');
|
||||||
|
|
||||||
|
const { configId } = getGVGConfig();
|
||||||
|
const groupKey = await getGroupKey(serverId);
|
||||||
|
|
||||||
|
const cities = await GVGCityModel.findGuardCity(configId, groupKey);
|
||||||
|
const leagueCodes = cities.map(cur => cur.guardLeague);
|
||||||
|
const leagues = await GVGLeagueModel.findByCodes(leagueCodes);
|
||||||
|
const prepares = await GVGLeaguePrepareModel.findByLeagueCodes(configId, leagueCodes);
|
||||||
|
const guilds = await GuildModel.findByCodesWithoutPopulate(leagues.reduce((pre, cur) => [...pre, ...cur.guildCodes], []));
|
||||||
|
|
||||||
|
const result: GuardCityInfoPage[] = [];
|
||||||
|
for(let { cityId, guardLeagueCode } of result) {
|
||||||
|
let league = leagues.find(cur => cur.leagueCode == guardLeagueCode);
|
||||||
|
if(!league) continue;
|
||||||
|
let prepare = prepares.find(cur => cur.leagueCode == guardLeagueCode);
|
||||||
|
let leagueGuilds = guilds.filter(cur => cur.leagueCode == league.leagueCode);
|
||||||
|
let leagueCe = leagueGuilds.reduce((pre, cur) => pre + cur.guildCe, 0);
|
||||||
|
|
||||||
|
let data = new GuardCityInfoPage(cityId);
|
||||||
|
data.setGuardLeague(league, prepare, leagueCe);
|
||||||
|
}
|
||||||
|
|
||||||
|
return resResult(STATUS.SUCCESS, {
|
||||||
|
cities: result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// 获取道具
|
// 获取道具
|
||||||
async debugAddLeagueItem(msg: { id: number, count: number }, session: BackendSession) {
|
async debugAddLeagueItem(msg: { id: number, count: number }, session: BackendSession) {
|
||||||
const roleId = session.get('roleId');
|
const roleId = session.get('roleId');
|
||||||
@@ -490,10 +564,4 @@ export class GVGHandler {
|
|||||||
const result = await handleGVGCost(roleId, myLeague.leagueCode, sid, leagueItems, items, ITEM_CHANGE_REASON.DEBUG);
|
const result = await handleGVGCost(roleId, myLeague.leagueCode, sid, leagueItems, items, ITEM_CHANGE_REASON.DEBUG);
|
||||||
return resResult(STATUS.SUCCESS, { result });
|
return resResult(STATUS.SUCCESS, { result });
|
||||||
}
|
}
|
||||||
|
|
||||||
async getServerType(msg: { time: string }, session: BackendSession) {
|
|
||||||
let t = new Date(msg.time);
|
|
||||||
let serverType = getServerTypeByTime(getSeconds(t));
|
|
||||||
return resResult(STATUS.SUCCESS, { serverType });
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@@ -19,6 +19,7 @@ import { GUILD_ACTIVITY_TYPE, LADDER_STATUS } from '../../../consts';
|
|||||||
import { setApiIsClose } from '../../../services/chatService';
|
import { setApiIsClose } from '../../../services/chatService';
|
||||||
import { setHiddenData } from '../../../services/dataService';
|
import { setHiddenData } from '../../../services/dataService';
|
||||||
import { setKvToMemory } from '../../../services/pushService';
|
import { setKvToMemory } from '../../../services/pushService';
|
||||||
|
import { setGVGServerGroup } from '../../../services/gvg/gvgService';
|
||||||
|
|
||||||
export default function (app: Application) {
|
export default function (app: Application) {
|
||||||
return new SystimerRemote(app);
|
return new SystimerRemote(app);
|
||||||
@@ -274,4 +275,12 @@ export class SystimerRemote {
|
|||||||
errlogger.error(`remote ${__filename} \n ${e.stack}`);
|
errlogger.error(`remote ${__filename} \n ${e.stack}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async setGVGServerGroup() {
|
||||||
|
try {
|
||||||
|
await setGVGServerGroup();
|
||||||
|
} catch(e) {
|
||||||
|
errlogger.error(`remote ${__filename} \n ${e.stack}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,6 +35,8 @@ export async function createNewGVGConfig() {
|
|||||||
await pinus.app.rpc.guild.guildRemote.setGVGServerGroup.broadcast();
|
await pinus.app.rpc.guild.guildRemote.setGVGServerGroup.broadcast();
|
||||||
await pinus.app.rpc.chat.chatRemote.setGVGServerGroup.broadcast();
|
await pinus.app.rpc.chat.chatRemote.setGVGServerGroup.broadcast();
|
||||||
await pinus.app.rpc.connector.connectorRemote.setGVGServerGroup.broadcast();
|
await pinus.app.rpc.connector.connectorRemote.setGVGServerGroup.broadcast();
|
||||||
|
await pinus.app.rpc.gm.gmRemote.setGVGServerGroup.broadcast();
|
||||||
|
await pinus.app.rpc.systimer.systimerRemote.setGVGServerGroup.broadcast();
|
||||||
await pinus.app.rpc.guild?.guildRemote?.clearBattleMemory.broadcast();
|
await pinus.app.rpc.guild?.guildRemote?.clearBattleMemory.broadcast();
|
||||||
} catch(e) {
|
} catch(e) {
|
||||||
console.log('remote未初始完');
|
console.log('remote未初始完');
|
||||||
@@ -183,8 +185,15 @@ export async function initLeaguePrepare() {
|
|||||||
const config = await GVGConfigModel.findConfig();
|
const config = await GVGConfigModel.findConfig();
|
||||||
if(!config) return;
|
if(!config) return;
|
||||||
const leagues = await GVGLeagueModel.findAllLeague();
|
const leagues = await GVGLeagueModel.findAllLeague();
|
||||||
for(let { leagueCode, memberCnt } of leagues) {
|
let groupKeyByServerId = new Map<number, string>();
|
||||||
await GVGLeaguePrepareModel.initData(config.configId, leagueCode, memberCnt);
|
for(let { leagueCode, memberCnt, serverId } of leagues) {
|
||||||
|
let groupKey = groupKeyByServerId.get(serverId);
|
||||||
|
if(!groupKey) {
|
||||||
|
groupKey = await getGroupKey(serverId);
|
||||||
|
groupKeyByServerId.set(serverId, groupKey);
|
||||||
|
}
|
||||||
|
|
||||||
|
await GVGLeaguePrepareModel.initData(config.configId, groupKey, leagueCode, memberCnt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -34,7 +34,8 @@ export async function autoCreateLeague(guildCode: string) {
|
|||||||
let { configId, period } = getGVGPeriodData();
|
let { configId, period } = getGVGPeriodData();
|
||||||
if(period == GVG_PERIOD.PREPARE) {
|
if(period == GVG_PERIOD.PREPARE) {
|
||||||
let league = await createLeague(guild, {});
|
let league = await createLeague(guild, {});
|
||||||
await GVGLeaguePrepareModel.initData(configId, league.leagueCode, guild.memberCnt);
|
let groupKey = await getGroupKey(guild.serverId);
|
||||||
|
await GVGLeaguePrepareModel.initData(configId, groupKey, league.leagueCode, guild.memberCnt);
|
||||||
return league;
|
return league;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -137,9 +137,9 @@ export default class GVGLeague extends BaseModel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static async findAllLeague() {
|
public static async findAllLeague() {
|
||||||
const leagues: { leagueCode: string, memberCnt: number }[] = await GVGLeagueModel.aggregate([
|
const leagues: { leagueCode: string, memberCnt: number, serverId: number }[] = await GVGLeagueModel.aggregate([
|
||||||
{ $match: { status: 1 } },
|
{ $match: { status: 1 } },
|
||||||
{ $project: { leagueCode: 1, memberCnt: 1 } }
|
{ $project: { leagueCode: 1, memberCnt: 1, serverId: 1 } }
|
||||||
]);
|
]);
|
||||||
return leagues;
|
return leagues;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -44,11 +44,15 @@ class GuildActive {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@index({ leagueCode: 1, configId: 1 })
|
@index({ leagueCode: 1, configId: 1 })
|
||||||
|
@index({ configId: 1, lv: -1 })
|
||||||
export default class GVGLeaguePrepare extends BaseModel {
|
export default class GVGLeaguePrepare extends BaseModel {
|
||||||
|
|
||||||
@prop({ required: true })
|
@prop({ required: true })
|
||||||
configId: number; // 赛期配置id
|
configId: number; // 赛期配置id
|
||||||
|
|
||||||
|
@prop({ required: true })
|
||||||
|
groupKey: string; // 战区
|
||||||
|
|
||||||
@prop({ required: true })
|
@prop({ required: true })
|
||||||
leagueCode: string; // 联军
|
leagueCode: string; // 联军
|
||||||
|
|
||||||
@@ -82,12 +86,12 @@ export default class GVGLeaguePrepare extends BaseModel {
|
|||||||
@prop({ required: true, default: [], type: GuildActive, _id: false })
|
@prop({ required: true, default: [], type: GuildActive, _id: false })
|
||||||
guildActive: GuildActive[]; // 军团活跃
|
guildActive: GuildActive[]; // 军团活跃
|
||||||
|
|
||||||
public static async initData(configId: number, leagueCode: string, maxMemberCnt: number) {
|
public static async initData(configId: number, groupKey: string, leagueCode: string, maxMemberCnt: number) {
|
||||||
const doc = new GVGLeaguePrepareModel();
|
const doc = new GVGLeaguePrepareModel();
|
||||||
const update = Object.assign(doc.toJSON(), { maxMemberCnt });
|
const update = Object.assign(doc.toJSON(), { maxMemberCnt });
|
||||||
delete update._id;
|
delete update._id;
|
||||||
|
|
||||||
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $setOnInsert: update }, { upsert: true, new: true })
|
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode, groupKey }, { $setOnInsert: update }, { upsert: true, new: true })
|
||||||
.select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 }).lean();
|
.select({ _id: 0, __v: 0, createdAt: 0, updatedAt: 0 }).lean();
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@@ -97,6 +101,12 @@ export default class GVGLeaguePrepare extends BaseModel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static async findByLeagueCodes(configId: number, leagueCodes: string[]) {
|
||||||
|
const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.findOne({ configId, leagueCode: { $in: leagueCodes } }).lean();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
public static async chooseJob(configId: number, leagueCode: string, job: LEAGUE_JOB) {
|
public static async chooseJob(configId: number, leagueCode: string, job: LEAGUE_JOB) {
|
||||||
if(job == LEAGUE_JOB.FIGHTER) {
|
if(job == LEAGUE_JOB.FIGHTER) {
|
||||||
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $inc: { fighterCnt: 1 } }, { new: true }).lean();
|
const result: GVGLeaguePrepareType = await GVGLeaguePrepareModel.findOneAndUpdate({ configId, leagueCode }, { $inc: { fighterCnt: 1 } }, { new: true }).lean();
|
||||||
@@ -146,6 +156,11 @@ export default class GVGLeaguePrepare extends BaseModel {
|
|||||||
const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.aggregate([{ $match: {configId} }]);
|
const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.aggregate([{ $match: {configId} }]);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async getLvRank(configId: number) {
|
||||||
|
const result: GVGLeaguePrepareType[] = await GVGLeaguePrepareModel.find({ configId }).sort({ lv: -1 }).lean();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export const GVGLeaguePrepareModel = getModelForClass(GVGLeaguePrepare);
|
export const GVGLeaguePrepareModel = getModelForClass(GVGLeaguePrepare);
|
||||||
|
|||||||
@@ -346,6 +346,10 @@ export default class Guild extends BaseModel {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static async findByCodesWithoutPopulate(codes: string[]) {
|
||||||
|
const result: GuildType[] = await GuildModel.find({ status: GUILD_STATUS.RUNNING, code: { $in: codes } }).select('+serverId').lean();
|
||||||
|
return result;
|
||||||
|
}
|
||||||
public static async quitFromLeague(guildCode: string, leagueCode: string, select = null) {
|
public static async quitFromLeague(guildCode: string, leagueCode: string, select = null) {
|
||||||
const result: GuildType = await GuildModel.findOneAndUpdate({ code: guildCode, leagueCode }, { $set: { leagueCode: '' } }, { new: true }).select(select).lean();
|
const result: GuildType = await GuildModel.findOneAndUpdate({ code: guildCode, leagueCode }, { $set: { leagueCode: '' } }, { new: true }).select(select).lean();
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -825,3 +825,54 @@ export class MyTeamInfo {
|
|||||||
this.curTeamBreak = team.curTeamBreak;
|
this.curTeamBreak = team.curTeamBreak;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 情报
|
||||||
|
// 联军排名
|
||||||
|
export class LeagueRankInInfoPage {
|
||||||
|
rank: number;
|
||||||
|
leagueCode: string = '';
|
||||||
|
leagueName: string = '';
|
||||||
|
lv: number = 1;
|
||||||
|
leaderName: string = '';
|
||||||
|
leagueCe: number = 0;
|
||||||
|
cities: number[] = [];
|
||||||
|
|
||||||
|
constructor(rank: number, league: GVGLeagueType, prepare: GVGLeaguePrepareType, ce: number, cities: number[]) {
|
||||||
|
this.rank = rank;
|
||||||
|
if(league) {
|
||||||
|
this.leagueCode = league.leagueCode;
|
||||||
|
this.leagueName = league.name;
|
||||||
|
this.leaderName = (<RoleType>league.leader)?.roleName;
|
||||||
|
}
|
||||||
|
if(prepare) {
|
||||||
|
this.lv = prepare.lv;
|
||||||
|
}
|
||||||
|
this.leagueCe = ce;
|
||||||
|
this.cities = cities;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class GuardCityInfoPage {
|
||||||
|
cityId: number;
|
||||||
|
guardLeagueCode: string = '';
|
||||||
|
guardLeagueName: string = '';
|
||||||
|
lv: number = 0;
|
||||||
|
leaderName: string = '';
|
||||||
|
leagueCe: number = 0;
|
||||||
|
|
||||||
|
constructor(cityId: number) {
|
||||||
|
this.cityId = cityId;
|
||||||
|
}
|
||||||
|
|
||||||
|
setGuardLeague(league: GVGLeagueType, prepare: GVGLeaguePrepareType, ce: number) {
|
||||||
|
if(league) {
|
||||||
|
this.guardLeagueCode = league.leagueCode;
|
||||||
|
this.guardLeagueName = league.name;
|
||||||
|
this.leaderName = (<RoleType>league.leader)?.roleName;
|
||||||
|
}
|
||||||
|
if(prepare) {
|
||||||
|
this.lv = prepare.lv;
|
||||||
|
}
|
||||||
|
this.leagueCe = ce;
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user