Jofthomas's picture
Jofthomas HF staff
Upload 4781 files
5c2ed06 verified
{
"version": 3,
"sources": ["../../../server/chat-plugins/helptickets.ts"],
"sourcesContent": ["import { FS, Utils, Net, ProcessManager } from '../../lib';\nimport { getCommonBattles } from '../chat-commands/info';\nimport { checkRipgrepAvailability } from '../config-loader';\nimport type { Punishment } from '../punishments';\nimport type { PartialModlogEntry, ModlogID } from '../modlog';\nimport { runPunishments } from './helptickets-auto';\n\nconst TICKET_FILE = 'config/tickets.json';\nconst SETTINGS_FILE = 'config/chat-plugins/ticket-settings.json';\nconst TICKET_CACHE_TIME = 24 * 60 * 60 * 1000; // 24 hours\nconst TICKET_BAN_DURATION = 48 * 60 * 60 * 1000; // 48 hours\nexport const BATTLES_REGEX = /\\bbattle-(?:[a-z0-9]+)-(?:[0-9]+)(?:-[a-z0-9]{31}pw)?/g;\nexport const REPLAY_REGEX = new RegExp(\n\t`${Utils.escapeRegex(Config.routes.replays)}/(?:[a-z0-9]-)?(?:[a-z0-9]+)-(?:[0-9]+)(?:-[a-z0-9]{31}pw)?`, \"g\"\n);\nconst REPORT_NAMECOLORS: { [k: string]: string } = {\n\tp1: 'DodgerBlue',\n\tp2: 'Crimson',\n\tp3: '#FBa92C',\n\tp4: '#228B22',\n\tother: '#00000',\n};\n\nPunishments.addPunishmentType({\n\ttype: 'TICKETBAN',\n\tdesc: 'banned from creating help tickets',\n});\n\ninterface TicketSettings {\n\t// {[ticketType]: {[button title]: response}}\n\tresponses: { [ticketType: string]: { [title: string]: string } };\n}\n\nexport interface TicketState {\n\tcreator: string;\n\tuserid: ID;\n\topen: boolean;\n\tactive: boolean;\n\ttype: string;\n\tcreated: number;\n\tclaimed: string | null;\n\tip: string;\n\tneedsDelayWarning?: boolean;\n\toffline?: boolean;\n\t// text ticket properties\n\t/** [main text, context] */\n\ttext?: [string, string];\n\tresolved?: ResolvedTicketInfo;\n\tmeta?: string;\n\tnotes?: { [userid: string]: string };\n\t/** Extra info that they might need for displays or whatnot.\n\t * Use `TextTicketInfo#getState` to set it at creation (store properties of the user object, etc)\n\t */\n\tstate?: AnyObject & { claimTime?: number };\n\t/** Recommendations from the Artemis monitor, if it is set to only recommend. */\n\trecommended?: string[];\n}\n\ninterface ResolvedTicketInfo {\n\ttime: number;\n\tresult: string;\n\tby: string;\n\tseen: boolean;\n\tstaffReason: string;\n\t/** <small> note under the resolved */\n\tnote?: string;\n}\n\nexport interface TextTicketInfo {\n\tchecker?: (\n\t\tinput: string, context: string, pageId: string, user: User, reportTarget?: string\n\t) => boolean | string[] | Promise<boolean | string[]>;\n\ttitle: string;\n\tdisclaimer?: string;\n\t/**\n\t * Set this to prompt for more specific context beyond\n\t * \"Do you have any other information you want to provide? (this is optional)\"\n\t */\n\tcontextMessage?: string;\n\t/** Should this be displayed with all the other tickets of the type on a singular page? */\n\tlistOnly?: boolean;\n\tgetReviewDisplay: (\n\t\tticket: TicketState & { text: [string, string] }, staff: User, conn: Connection, state?: AnyObject\n\t) => Promise<string | void> | string | void;\n\tonSubmit?: (ticket: TicketState, text: [string, string], submitter: User, conn: Connection) => void | Promise<void>;\n\tgetState?: (ticket: TicketState, user: User) => AnyObject;\n}\n\ninterface BattleInfo {\n\tlog: string[];\n\turl: string;\n\ttitle: string;\n\tplayers: { p1: ID, p2: ID, p3?: ID, p4?: ID };\n\tpokemon: Record<string, { species: string, name?: string }[]>;\n}\n\ntype TicketResult = 'approved' | 'valid' | 'assisted' | 'denied' | 'invalid' | 'unassisted' | 'ticketban' | 'deleted';\n\nconst defaults: TicketSettings = { responses: {} };\n\nexport const tickets: { [k: string]: TicketState } = {};\nexport const settings: TicketSettings = (() => {\n\ttry {\n\t\t// this ensures that if new settings are added to the defaults, they are added\n\t\t// to the JSON as well\n\t\treturn { ...defaults, ...JSON.parse(FS(SETTINGS_FILE).readSync()) };\n\t} catch {\n\t\treturn { ...defaults };\n\t}\n})();\n\ntry {\n\tconst ticketData = JSON.parse(FS(TICKET_FILE).readSync());\n\tfor (const t in ticketData) {\n\t\tconst ticket = ticketData[t];\n\t\tif (ticket.banned) {\n\t\t\tif (ticket.expires && ticket.expires <= Date.now()) continue;\n\t\t\tvoid Punishments.punish(ticket.userid, {\n\t\t\t\ttype: 'TICKETBAN',\n\t\t\t\tid: ticket.userid,\n\t\t\t\texpireTime: ticket.expires,\n\t\t\t\treason: ticket.reason,\n\t\t\t}, false);\n\t\t\tdelete ticketData[t]; // delete the old format\n\t\t} else {\n\t\t\tif (ticket.created + TICKET_CACHE_TIME <= Date.now()) {\n\t\t\t\t// Tickets that have been open for 24+ hours will be automatically closed.\n\t\t\t\tconst ticketRoom = Rooms.get(`help-${ticket.userid}`) as ChatRoom | null;\n\t\t\t\tif (ticketRoom) {\n\t\t\t\t\tconst ticketGame = ticketRoom.game as HelpTicket;\n\t\t\t\t\tticketGame.writeStats(false);\n\t\t\t\t\tticketRoom.expire();\n\t\t\t\t} else if (ticket.text && ticket.open) {\n\t\t\t\t\tticket.open = false;\n\t\t\t\t\tconst startTime = ticket.state?.claimTime || ticket.created;\n\t\t\t\t\twriteStats(`${ticket.type}\\t${Date.now() - startTime}\\t0\\t0\\tdead\\tvalid\\t`);\n\t\t\t\t}\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\t// Close open tickets after a restart\n\t\t\tif (ticket.open && !Chat.oldPlugins.helptickets) ticket.open = false;\n\t\t\ttickets[t] = ticket;\n\t\t}\n\t}\n} catch (e: any) {\n\tif (e.code !== 'ENOENT') throw e;\n}\n\nexport function writeTickets() {\n\tFS(TICKET_FILE).writeUpdate(\n\t\t() => JSON.stringify(tickets), { throttle: 5000 }\n\t);\n}\n\nexport function writeSettings() {\n\tFS(SETTINGS_FILE).writeUpdate(() => JSON.stringify(settings));\n}\n\nasync function convertRoomPunishments() {\n\tfor (const [id, punishment] of Punishments.getPunishments('staff')) {\n\t\tif (punishment.punishType !== 'TICKETBAN') continue;\n\t\tPunishments.roomUnpunish('staff', id, 'TICKETBAN');\n\t\tawait HelpTicket.ban(id as ID, punishment.reason);\n\t}\n}\n\nexport function writeStats(line: string) {\n\t// ticketType\\ttotalTime\\ttimeToFirstClaim\\tinactiveTime\\tresolution\\tresult\\tstaff,userids,seperated,with,commas\n\tconst date = new Date();\n\tconst month = Chat.toTimestamp(date).split(' ')[0].split('-', 2).join('-');\n\ttry {\n\t\tMonitor.logPath(`tickets/${month}.tsv`).appendSync(line + '\\n');\n\t} catch (e: any) {\n\t\tif (e.code !== 'ENOENT') throw e;\n\t}\n}\n\nexport class HelpTicket extends Rooms.SimpleRoomGame {\n\toverride readonly gameid = \"helpticket\" as ID;\n\toverride readonly allowRenames = true;\n\toverride room: ChatRoom;\n\tticket: TicketState;\n\tclaimQueue: string[];\n\tinvolvedStaff = new Set<ID>();\n\tcreateTime: number;\n\tactivationTime: number;\n\temptyRoom = false;\n\tfirstClaimTime = 0;\n\tunclaimedTime = 0;\n\tlastUnclaimedStart: number;\n\tcloseTime = 0;\n\tresolution: 'unknown' | 'dead' | 'unresolved' | 'resolved' = 'unknown';\n\tresult: TicketResult | null = null;\n\n\tconstructor(room: ChatRoom, ticket: TicketState) {\n\t\tsuper(room);\n\t\tthis.room = room;\n\t\tthis.room.settings.language = Users.get(ticket.creator)?.language || 'english' as ID;\n\t\tthis.title = `Help Ticket - ${ticket.type}`;\n\t\tthis.ticket = ticket;\n\t\tthis.claimQueue = [];\n\n\t\t/* Stats */\n\t\tthis.createTime = Date.now();\n\t\tthis.activationTime = (ticket.active ? this.createTime : 0);\n\t\tthis.lastUnclaimedStart = (ticket.active ? this.createTime : 0);\n\t}\n\n\tonJoin(user: User, connection: Connection) {\n\t\tif (!this.ticket.open) return false;\n\t\tif (!user.isStaff || user.id === this.ticket.userid) {\n\t\t\tif (this.emptyRoom) this.emptyRoom = false;\n\t\t\tthis.addPlayer(user);\n\t\t\tif (this.ticket.offline) {\n\t\t\t\tdelete this.ticket.offline;\n\t\t\t\twriteTickets();\n\t\t\t\tnotifyStaff();\n\t\t\t}\n\t\t\treturn false;\n\t\t}\n\t\tif (!this.ticket.claimed) {\n\t\t\tthis.ticket.claimed = user.name;\n\t\t\tif (!this.firstClaimTime) {\n\t\t\t\tthis.firstClaimTime = Date.now();\n\t\t\t\t// I'd use the player list for this, but it dosen't track DCs so were checking the userlist\n\t\t\t\t// Non-staff users in the room currently (+ the ticket creator even if they are staff)\n\t\t\t\tconst users = Object.entries(this.room.users).filter(\n\t\t\t\t\tu => !((u[1].isStaff && u[1].id !== this.ticket.userid) || !u[1].named)\n\t\t\t\t);\n\t\t\t\tif (!users.length) this.emptyRoom = true;\n\t\t\t}\n\t\t\tif (this.ticket.active) {\n\t\t\t\tthis.unclaimedTime += Date.now() - this.lastUnclaimedStart;\n\t\t\t\tthis.lastUnclaimedStart = 0; // Set back to 0 so we know that it was active when closed\n\t\t\t}\n\t\t\ttickets[this.ticket.userid] = this.ticket;\n\t\t\twriteTickets();\n\t\t\tthis.room.modlog({ action: 'TICKETCLAIM', isGlobal: false, loggedBy: user.id });\n\t\t\tthis.addText(`${user.name} claimed this ticket.`, user);\n\t\t\tnotifyStaff();\n\t\t} else {\n\t\t\tthis.claimQueue.push(user.name);\n\t\t}\n\t}\n\n\tonLeave(user: User, oldUserid: ID) {\n\t\tconst player = this.playerTable[oldUserid || user.id];\n\t\tif (player) {\n\t\t\tthis.removePlayer(player);\n\t\t\tthis.ticket.offline = true;\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t\treturn;\n\t\t}\n\t\tif (!this.ticket.open) return;\n\t\tif (toID(this.ticket.claimed) === user.id) {\n\t\t\tif (this.claimQueue.length) {\n\t\t\t\tthis.ticket.claimed = this.claimQueue.shift() || null;\n\t\t\t\tthis.room.modlog({ action: 'TICKETCLAIM', isGlobal: false, loggedBy: toID(this.ticket.claimed) });\n\t\t\t\tthis.addText(`This ticket is now claimed by ${this.ticket.claimed}.`, user);\n\t\t\t} else {\n\t\t\t\tconst oldClaimed = this.ticket.claimed;\n\t\t\t\tthis.ticket.claimed = null;\n\t\t\t\tthis.lastUnclaimedStart = Date.now();\n\t\t\t\tthis.room.modlog({ action: 'TICKETUNCLAIM', isGlobal: false, loggedBy: toID(oldClaimed) });\n\t\t\t\tthis.addText(`This ticket is no longer claimed.`, user);\n\t\t\t\tnotifyStaff();\n\t\t\t}\n\t\t\ttickets[this.ticket.userid] = this.ticket;\n\t\t\twriteTickets();\n\t\t} else {\n\t\t\tconst index = this.claimQueue.map(toID).indexOf(user.id);\n\t\t\tif (index > -1) this.claimQueue.splice(index, 1);\n\t\t}\n\t}\n\n\tonLogMessage(message: string, user: User) {\n\t\tif (!this.ticket.open) return;\n\t\tif (user.isStaff && this.ticket.userid !== user.id) this.involvedStaff.add(user.id);\n\t\tif (this.ticket.active) return;\n\t\tconst blockedMessages = [\n\t\t\t'hello', 'hullo', 'hey',\n\t\t\t'hesrude', 'shesrude', 'hesinappropriate', 'shesinappropriate', 'heswore', 'sheswore',\n\t\t\t'help', 'yes',\n\t\t];\n\t\tif (\n\t\t\t(!user.isStaff || this.ticket.userid === user.id) && (message.length < 3 || blockedMessages.includes(toID(message)))\n\t\t) {\n\t\t\tthis.room.add(`|c|~Staff|${this.room.tr`Hello! The global staff team would be happy to help you, but you need to explain what's going on first.`}`);\n\t\t\tthis.room.add(`|c|~Staff|${this.room.tr`Please post the information I requested above so a global staff member can come to help.`}`);\n\t\t\tthis.room.update();\n\t\t\treturn false;\n\t\t}\n\t\tif ((!user.isStaff || this.ticket.userid === user.id) && !this.ticket.active) {\n\t\t\tthis.ticket.active = true;\n\t\t\tthis.activationTime = Date.now();\n\t\t\tif (!this.ticket.claimed) this.lastUnclaimedStart = Date.now();\n\t\t\tnotifyStaff();\n\t\t\tthis.room.add(`|c|~Staff|${this.room.tr`Thank you for the information, global staff will be here shortly. Please stay in the room.`}`).update();\n\t\t\tswitch (this.ticket.type) {\n\t\t\tcase 'PM Harassment':\n\t\t\t\tthis.room.add(\n\t\t\t\t\t`|c|~Staff|Global staff might take more than a few minutes to handle your report. ` +\n\t\t\t\t\t`If you are being disturbed by another user, you can type \\`\\`/ignore [username]\\`\\` in any chat to ignore their messages immediately`\n\t\t\t\t).update();\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tthis.ticket.needsDelayWarning = true;\n\t\t}\n\t}\n\n\tforfeit(user: User) {\n\t\tif (!(user.id in this.playerTable)) return;\n\t\tthis.removePlayer(this.playerTable[user.id]);\n\t\tif (!this.ticket.open) return;\n\t\tthis.room.modlog({ action: 'TICKETABANDON', isGlobal: false, loggedBy: user.id });\n\t\tthis.addText(`${user.name} is no longer interested in this ticket.`, user);\n\t\tif (this.playerCount - 1 > 0) return; // There are still users in the ticket room, dont close the ticket\n\t\tthis.close(!!(this.firstClaimTime), user);\n\t\treturn true;\n\t}\n\n\taddText(text: string, user?: User) {\n\t\tif (user) {\n\t\t\tthis.room.addByUser(user, text);\n\t\t} else {\n\t\t\tthis.room.add(text);\n\t\t}\n\t\tthis.room.update();\n\t}\n\n\tgetButton() {\n\t\tconst color = this.ticket.claimed ? `` : this.ticket.offline ? `alt-notifying` : `notifying`;\n\t\tconst creator = (\n\t\t\tthis.ticket.claimed ? Utils.html`${this.ticket.creator}` : Utils.html`<strong>${this.ticket.creator}</strong>`\n\t\t);\n\t\tconst user = Users.get(this.ticket.creator);\n\t\tlet details = '';\n\t\tif (user?.namelocked && !this.ticket.state?.namelocked) {\n\t\t\tif (!this.ticket.state) this.ticket.state = {};\n\t\t\tthis.ticket.state.namelocked = user.namelocked;\n\t\t}\n\t\tif (this.ticket.state?.namelocked) {\n\t\t\tdetails += ` [${this.ticket.state?.namelocked}]`;\n\t\t}\n\t\tif (user?.locked) {\n\t\t\tconst punishment = Punishments.userids.getByType(user.locked, 'LOCK');\n\t\t\tif (punishment?.rest?.length) {\n\t\t\t\t// only #artemis uses this rn\n\t\t\t\tdetails += ` [${punishment.rest.join(', ')}]`;\n\t\t\t}\n\t\t}\n\t\treturn (\n\t\t\t`<a class=\"button ${color}\" href=\"/help-${this.ticket.userid}\"` +\n\t\t\t` ${this.getPreview()}>Help ${creator}${details}: ${this.ticket.type}</a> `\n\t\t);\n\t}\n\n\tgetPreview() {\n\t\tif (!this.ticket.active) return `title=\"The ticket creator has not spoken yet.\"`;\n\t\tconst hoverText = [];\n\t\tconst noteBuf = Object.entries(this.ticket.notes || {})\n\t\t\t.map(([userid, note]) => Utils.html`${note} (by ${userid})`)\n\t\t\t.join('&#10;');\n\t\tconst notes = this.ticket.notes ? `&#10;Staff notes:&#10;${noteBuf}` : '';\n\t\tfor (let i = this.room.log.log.length - 1; i >= 0; i--) {\n\t\t\t// Don't show anything after the first linebreak for multiline messages\n\t\t\tconst entry = this.room.log.log[i].split('\\n')[0].split('|');\n\t\t\tentry.shift(); // Remove empty string\n\t\t\tif (!/c:?/.test(entry[0])) continue;\n\t\t\tif (entry[0] === 'c:') entry.shift(); // c: includes a timestamp and needs an extra shift\n\t\t\tentry.shift();\n\t\t\tconst user = entry.shift();\n\t\t\tlet message = entry.join('|');\n\t\t\tmessage = message.startsWith('/log ') ? message.slice(5) : `${user}: ${message}`;\n\t\t\thoverText.push(Utils.html`${message}`);\n\t\t\tif (hoverText.length >= 3) break;\n\t\t}\n\t\tif (!hoverText.length) return `title=\"The ticket creator has not spoken yet.${notes}\"`;\n\t\treturn `title=\"${hoverText.reverse().join(`&#10;`)}${notes}\"`;\n\t}\n\n\tclose(result: boolean | 'ticketban' | 'deleted', staff?: User) {\n\t\tthis.ticket.open = false;\n\t\ttickets[this.ticket.userid] = this.ticket;\n\t\twriteTickets();\n\t\tthis.room.modlog({ action: 'TICKETCLOSE', isGlobal: false, loggedBy: staff?.id || 'unknown' as ID });\n\t\tthis.addText(staff ? `${staff.name} closed this ticket.` : `This ticket was closed.`, staff);\n\t\tnotifyStaff();\n\t\tthis.room.pokeExpireTimer();\n\t\tfor (const ticketGameUser of Object.values(this.playerTable)) {\n\t\t\tthis.removePlayer(ticketGameUser);\n\t\t\tconst user = Users.get(ticketGameUser.id);\n\t\t\tif (user) user.updateSearch();\n\t\t}\n\t\tif (!this.involvedStaff.size) {\n\t\t\tif (staff?.isStaff && staff.id !== this.ticket.userid) {\n\t\t\t\tthis.involvedStaff.add(staff.id);\n\t\t\t} else {\n\t\t\t\tthis.involvedStaff.add(toID(this.ticket.claimed));\n\t\t\t}\n\t\t}\n\t\tthis.writeStats(result);\n\t}\n\n\twriteStats(result: boolean | 'ticketban' | 'deleted') {\n\t\t// Only run when a ticket is closed/banned/deleted\n\t\tthis.closeTime = Date.now();\n\t\tif (this.lastUnclaimedStart) this.unclaimedTime += this.closeTime - this.lastUnclaimedStart;\n\t\tif (!this.ticket.active) {\n\t\t\tthis.resolution = \"dead\";\n\t\t} else if (!this.firstClaimTime || this.emptyRoom) {\n\t\t\tthis.resolution = \"unresolved\";\n\t\t} else {\n\t\t\tthis.resolution = \"resolved\";\n\t\t}\n\t\tif (typeof result === 'boolean') {\n\t\t\tswitch (this.ticket.type) {\n\t\t\tcase 'Appeal':\n\t\t\tcase 'IP-Appeal':\n\t\t\t\tthis.result = (result ? 'approved' : 'denied');\n\t\t\t\tbreak;\n\t\t\tcase 'PM Harassment':\n\t\t\tcase 'Battle Harassment':\n\t\t\tcase 'Inappropriate Username':\n\t\t\tcase 'Inappropriate Pokemon Nicknames':\n\t\t\t\tthis.result = (result ? 'valid' : 'invalid');\n\t\t\t\tbreak;\n\t\t\tcase 'Public Room Assistance Request':\n\t\t\tcase 'Other':\n\t\t\tdefault:\n\t\t\t\tthis.result = (result ? 'assisted' : 'unassisted');\n\t\t\t\tbreak;\n\t\t\t}\n\t\t} else {\n\t\t\tthis.result = result;\n\t\t}\n\t\tlet firstClaimWait = 0;\n\t\tlet involvedStaff = '';\n\t\tif (this.activationTime) {\n\t\t\tfirstClaimWait = (this.firstClaimTime ? this.firstClaimTime : this.closeTime) - this.activationTime;\n\t\t\tinvolvedStaff = Array.from(this.involvedStaff.entries()).map(s => s[0]).join(',');\n\t\t}\n\t\t// Write to TSV\n\t\t// ticketType\\ttotalTime\\ttimeToFirstClaim\\tinactiveTime\\tresolution\\tresult\\tstaff,userids,seperated,with,commas\n\t\tconst line = `${this.ticket.type}\\t${(this.closeTime - this.createTime)}\\t${firstClaimWait}\\t${this.unclaimedTime}\\t${this.resolution}\\t${this.result}\\t${involvedStaff}`;\n\t\twriteStats(line);\n\t}\n\n\tdeleteTicket(staff: User) {\n\t\tthis.close('deleted', staff);\n\t\tthis.room.modlog({ action: 'TICKETDELETE', isGlobal: false, loggedBy: staff.id });\n\t\tthis.addText(`${staff.name} deleted this ticket.`, staff);\n\t\tdelete tickets[this.ticket.userid];\n\t\twriteTickets();\n\t\tnotifyStaff();\n\t\tthis.room.destroy();\n\t}\n\n\t// Modified version of RoomGame.destory\n\tdestroy() {\n\t\tif (tickets[this.ticket.userid] && this.ticket.open) {\n\t\t\t// Ticket was not deleted - deleted tickets already have this done to them - and was not closed.\n\t\t\t// Write stats and change flags as appropriate prior to deletion.\n\t\t\tthis.ticket.open = false;\n\t\t\ttickets[this.ticket.userid] = this.ticket;\n\t\t\tnotifyStaff();\n\t\t\twriteTickets();\n\t\t\tthis.writeStats(false);\n\t\t}\n\n\t\tthis.room.game = null;\n\t\t(this.room as any) = null;\n\t\tthis.setEnded();\n\t\tfor (const player of this.players) player.destroy();\n\t\t(this.players as any) = null;\n\t\t(this.playerTable as any) = null;\n\t}\n\tonChatMessage(message: string, user: User) {\n\t\tHelpTicket.uploadReplaysFrom(message, user, user.connections[0]);\n\t}\n\t// workaround to modlog for no room\n\tstatic async modlog(entry: PartialModlogEntry) {\n\t\tawait Rooms.Modlog.write('help-texttickets' as ModlogID, entry);\n\t}\n\tstatic list(sorter?: (ticket: TicketState) => Utils.Comparable) {\n\t\tif (!sorter) {\n\t\t\tsorter = ticket => [\n\t\t\t\t!ticket.offline,\n\t\t\t\tticket.open,\n\t\t\t\tticket.open ? [ticket.active, !ticket.claimed, ticket.created] : 0,\n\t\t\t];\n\t\t}\n\t\treturn Utils.sortBy(Object.values(tickets), sorter);\n\t}\n\tstatic logTextResult(ticket: TicketState & { text: [string, string], resolved: ResolvedTicketInfo }) {\n\t\tconst entry = {\n\t\t\ttext: ticket.text,\n\t\t\tresolved: ticket.resolved,\n\t\t\tmeta: ticket.meta,\n\t\t\tcreated: ticket.created,\n\t\t\tuserid: ticket.userid,\n\t\t\ttype: ticket.type,\n\t\t\tclaimed: ticket.claimed,\n\t\t\tstate: ticket.state || {},\n\t\t\trecommended: ticket.recommended,\n\t\t};\n\t\tconst date = Chat.toTimestamp(new Date()).split(' ')[0];\n\t\tvoid Monitor.logPath(`tickets/${date.slice(0, -3)}.jsonl`).append(JSON.stringify(entry) + '\\n');\n\t}\n\n\t/**\n\t * @param search [search key, search value] (ie ['userid', 'mia']\n\t * returns tickets where the userid property === mia)\n\t * If the [value] is omitted (index 1), searches just for tickets with the given property.\n\t */\n\tstatic async getTextLogs(search: [string, string] | [string], date?: string) {\n\t\tif (Config.disableripgrep) {\n\t\t\tthrow new Chat.ErrorMessage(\"Helpticket logs are currently disabled.\");\n\t\t}\n\t\tconst results = [];\n\t\tif (await checkRipgrepAvailability()) {\n\t\t\tconst searchString = search.length > 1 ?\n\t\t\t\t// regex escaped to handle things like searching for arrays or objects\n\t\t\t\t// (JSON.stringify accounts for \" strings are wrapped in and stuff. generally ensures that searching is easier.)\n\t\t\t\tUtils.escapeRegex(JSON.stringify(search[1]).slice(0, -1)) :\n\t\t\t\t\"\";\n\t\t\tconst args = [\n\t\t\t\t`-e`, search.length > 1 ? `${search[0]}\":${searchString}` : `${search[0]}\":`,\n\t\t\t\t'--no-filename',\n\t\t\t];\n\t\t\tlet lines;\n\t\t\ttry {\n\t\t\t\tlines = await ProcessManager.exec([\n\t\t\t\t\t`rg`, Monitor.logPath(`tickets/${date ? `${date}.jsonl` : ''}`).path, ...args,\n\t\t\t\t]);\n\t\t\t} catch (e: any) {\n\t\t\t\tif (e.message.includes('No such file or directory')) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(`No ticket logs for that month.`);\n\t\t\t\t}\n\t\t\t\tif (e.code !== 1 && !e.message.includes('stdout maxBuffer')) {\n\t\t\t\t\tthrow e; // 2 means an error in ripgrep\n\t\t\t\t}\n\t\t\t\tif (e.stdout) {\n\t\t\t\t\tlines = e;\n\t\t\t\t} else {\n\t\t\t\t\tlines = { stdout: \"\" };\n\t\t\t\t}\n\t\t\t}\n\t\t\tfor (const line of lines.stdout.split('\\n')) {\n\t\t\t\tif (line.trim()) results.push(JSON.parse(line));\n\t\t\t}\n\t\t} else {\n\t\t\tif (!date) throw new Chat.ErrorMessage(`Specify a month.`);\n\t\t\tconst path = Monitor.logPath(`tickets/${date}.jsonl`);\n\t\t\tif (!path.existsSync()) {\n\t\t\t\tthrow new Chat.ErrorMessage(`There are no logs for the month \"${date}\".`);\n\t\t\t}\n\t\t\tconst stream = path.createReadStream();\n\t\t\tfor await (const line of stream.byLine()) {\n\t\t\t\tif (line.trim()) {\n\t\t\t\t\tconst data = JSON.parse(line);\n\t\t\t\t\tconst searched = data[search[0]];\n\t\t\t\t\tlet matched = !!searched;\n\t\t\t\t\tif (search[1]) matched = searched === search[1];\n\t\t\t\t\tif (matched) results.push(data);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\t\treturn results;\n\t}\n\tstatic uploadReplaysFrom(text: string, user: User, conn: Connection) {\n\t\tconst rooms = getBattleLinks(text);\n\t\tfor (const roomid of rooms) {\n\t\t\tconst room = Rooms.get(roomid) as GameRoom | undefined;\n\t\t\tvoid room?.uploadReplay?.(user, conn, \"forpunishment\");\n\t\t}\n\t}\n\tstatic colorName(id: ID, info: BattleInfo) {\n\t\tfor (const k in info.players) {\n\t\t\tconst player = info.players[k as SideID];\n\t\t\tif (player === id) {\n\t\t\t\treturn REPORT_NAMECOLORS[k];\n\t\t\t}\n\t\t}\n\t\treturn REPORT_NAMECOLORS.other;\n\t}\n\tstatic formatBattleLog(logs: string[], info: BattleInfo, reported?: ID) {\n\t\tconst log = logs.filter(l => l.startsWith('|c|'));\n\t\tlet buf = ``;\n\t\tfor (const line of log) {\n\t\t\tconst [,, username, message] = Utils.splitFirst(line, '|', 3);\n\t\t\tconst userid = toID(username);\n\t\t\tbuf += `<div class=\"chat chatmessage${reported === userid ? ' highlighted' : \"\"}\">`;\n\t\t\tbuf += `<span class=\"username\"><strong style=\"color: ${this.colorName(userid, info)}\">`;\n\t\t\tbuf += Utils.html`${username}:</strong></span> ${message}</div>`;\n\t\t}\n\t\tif (buf) buf = `<div class=\"infobox\"><strong><a href=\"${info.url}\">${info.title}</a></strong><hr />${buf}</div>`;\n\t\treturn buf;\n\t}\n\tstatic async visualizeBattleLogs(rooms: string[], reported?: ID) {\n\t\tconst logs = [];\n\t\tfor (const room of rooms) {\n\t\t\tconst log = await getBattleLog(room);\n\t\t\tif (log) logs.push(log);\n\t\t}\n\t\tconst existingRooms = logs.filter(Boolean);\n\t\tif (existingRooms.length) {\n\t\t\tconst chatBuffer = existingRooms\n\t\t\t\t.map(room => this.formatBattleLog(room.log, room, reported))\n\t\t\t\t.filter(Boolean)\n\t\t\t\t.join('');\n\t\t\tif (chatBuffer) {\n\t\t\t\treturn (\n\t\t\t\t\t`<div class=\"infobox\"><details class=\"readmore\"><summary><strong>Battle chat logs:</strong><br /></summary>` +\n\t\t\t\t\t`${chatBuffer}</details></div>`\n\t\t\t\t);\n\t\t\t}\n\t\t}\n\t}\n\tstatic displayPunishmentList(\n\t\treportUserid: ID,\n\t\tproofString: string,\n\t\tticket: TicketState,\n\t\ttitle?: string,\n\t\tinner?: string,\n\t) {\n\t\tif (ticket.resolved) return '';\n\t\tlet buf = `<details class=\"readmore\"><summary>${title || 'Punish reported user:'}</summary><div class=\"infobox\">`;\n\t\tif (inner) buf += inner;\n\t\tconst punishments = ['Warn', 'Lock', 'Weeklock', 'Namelock', 'Weeknamelock'];\n\t\tfor (const name of punishments) {\n\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,/${toID(name)} ${reportUserid},{reason} spoiler: ${proofString}\">`;\n\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">${name}</button><br />`;\n\t\t\tbuf += `Optional reason: <input name=\"reason\" />`;\n\t\t\tbuf += `</form><br />`;\n\t\t}\n\t\tbuf += `</div></details><br />`;\n\t\treturn buf;\n\t}\n\tstatic getTextButton(ticket: TicketState & { text: [string, string] }) {\n\t\tlet buf = '';\n\t\tconst titleBuf = [\n\t\t\t...ticket.text[0].split('\\n').map(Utils.escapeHTML),\n\t\t\t...ticket.text[1].split('<br />').map(Utils.stripHTML),\n\t\t].slice(0, 3);\n\t\tconst noteBuf = Object.entries(ticket.notes || {})\n\t\t\t.map(([userid, note]) => Utils.html`${note} (by ${userid})`)\n\t\t\t.join('&#10;');\n\t\tconst notes = ticket.notes ? `&#10;Staff notes:&#10;${noteBuf}` : '';\n\t\tconst title = `title=\"${titleBuf.join('&#10;')}${notes}\"`;\n\t\tconst user = Users.get(ticket.userid);\n\t\tlet namelockDisplay = '';\n\t\tif (user?.namelocked && !ticket.state?.namelocked) {\n\t\t\tif (!ticket.state) ticket.state = {};\n\t\t\tticket.state.namelocked = user.namelocked;\n\t\t}\n\t\tif (ticket.state?.namelocked) {\n\t\t\tnamelockDisplay = ` <small>[${ticket.state.namelocked}]</small>`;\n\t\t}\n\t\tbuf += `<a class=\"button${ticket.claimed ? `` : ` notifying`}\" ${title} href=\"/view-help-text-${ticket.userid}\">`;\n\t\tbuf += ticket.claimed ?\n\t\t\t`${ticket.userid}${namelockDisplay}:` :\n\t\t\t`<strong>${ticket.userid}</strong>${namelockDisplay}:`;\n\t\tbuf += ` ${ticket.type}</a>`;\n\t\treturn buf;\n\t}\n\tstatic async ban(user: User | ID, reason = '') {\n\t\tconst userid = toID(user);\n\t\tconst userObj = Users.get(user);\n\t\tif (userObj) user = userObj;\n\t\tlet duration = Date.now() + TICKET_BAN_DURATION;\n\t\tconst punishments = Punishments.userids.get(userid) || [];\n\t\t// we're not gonna grab by IP because we don't wanna risk nuking schools\n\t\tfor (const punishment of punishments) {\n\t\t\t// find the punishment with the highest expire time, take that time instead\n\t\t\tif (punishment.expireTime > duration) {\n\t\t\t\tduration = punishment.expireTime;\n\t\t\t}\n\t\t}\n\t\treturn Punishments.punish(user, {\n\t\t\ttype: 'TICKETBAN',\n\t\t\tid: userid,\n\t\t\texpireTime: duration,\n\t\t\treason,\n\t\t}, false);\n\t}\n\tstatic unban(user: ID | User) {\n\t\tuser = toID(user);\n\t\treturn Punishments.unpunish(user, 'TICKETBAN');\n\t}\n\tstatic getBanMessage(userid: ID, punishment: Punishment) {\n\t\tif (userid !== punishment.id) {\n\t\t\tconst { id: punished, reason } = punishment;\n\t\t\treturn (\n\t\t\t\t`You are banned from creating help tickets` +\n\t\t\t\t`${punished !== userid ? `, because you have the same IP as ${userid}` : ''}. ${reason ? `Reason: ${reason}` : ''}`\n\t\t\t);\n\t\t}\n\t\treturn `You are banned from creating help tickets.`;\n\t}\n\tstatic notifyResolved(user: User, ticket: TicketState, userid = user.id) {\n\t\tconst { result, time, by, seen, note } = ticket.resolved!;\n\t\tif (seen) return;\n\t\tconst timeString = (Date.now() - time) > 1000 ? `, ${Chat.toDurationString(Date.now() - time)} ago.` : '.';\n\t\tuser.send(`|pm|~Staff|${user.getIdentity()}|Hello! Your report was resolved by ${by}${timeString}`);\n\t\tif (result?.trim()) {\n\t\t\tuser.send(`|pm|~Staff|${user.getIdentity()}|The result was \"${result}\"`);\n\t\t}\n\t\tif (note?.trim()) {\n\t\t\tuser.send(`|pm|~Staff|${user.getIdentity()}|/raw <small>${note}</small>`);\n\t\t}\n\t\ttickets[userid].resolved!.seen = true;\n\t\twriteTickets();\n\t}\n\tstatic getTypeId(name: string) {\n\t\treturn Object.entries(ticketTitles).find(entry => entry[1] === name)?.[0] || toID(name);\n\t}\n}\n\nconst NOTIFY_ALL_TIMEOUT = 5 * 60 * 1000;\nconst NOTIFY_ASSIST_TIMEOUT = 60 * 1000;\nconst unclaimedTicketTimer: { [k: string]: NodeJS.Timeout | null } = { upperstaff: null, staff: null };\nconst timerEnds: { [k: string]: number } = { upperstaff: 0, staff: 0 };\nfunction pokeUnclaimedTicketTimer(hasUnclaimed: boolean, hasAssistRequest: boolean) {\n\tconst room = Rooms.get('staff');\n\tif (!room) return;\n\tif (hasUnclaimed && !unclaimedTicketTimer[room.roomid]) {\n\t\tunclaimedTicketTimer[room.roomid] = setTimeout(\n\t\t\t() =>\n\t\t\t\tnotifyUnclaimedTicket(hasAssistRequest), hasAssistRequest ? NOTIFY_ASSIST_TIMEOUT : NOTIFY_ALL_TIMEOUT\n\t\t);\n\t\ttimerEnds[room.roomid] = Date.now() + (hasAssistRequest ? NOTIFY_ASSIST_TIMEOUT : NOTIFY_ALL_TIMEOUT);\n\t} else if (\n\t\thasAssistRequest &&\n\t\t(timerEnds[room.roomid] - NOTIFY_ASSIST_TIMEOUT) > NOTIFY_ASSIST_TIMEOUT &&\n\t\tunclaimedTicketTimer[room.roomid]\n\t) {\n\t\t// Shorten timer\n\t\tclearTimeout(unclaimedTicketTimer[room.roomid]!);\n\t\tunclaimedTicketTimer[room.roomid] = setTimeout(() => notifyUnclaimedTicket(hasAssistRequest), NOTIFY_ASSIST_TIMEOUT);\n\t\ttimerEnds[room.roomid] = Date.now() + NOTIFY_ASSIST_TIMEOUT;\n\t} else if (!hasUnclaimed && unclaimedTicketTimer[room.roomid]) {\n\t\tclearTimeout(unclaimedTicketTimer[room.roomid]!);\n\t\tunclaimedTicketTimer[room.roomid] = null;\n\t\ttimerEnds[room.roomid] = 0;\n\t}\n}\nfunction notifyUnclaimedTicket(hasAssistRequest: boolean) {\n\tconst room = Rooms.get('staff');\n\tif (!room) return;\n\tclearTimeout(unclaimedTicketTimer[room.roomid]!);\n\tunclaimedTicketTimer[room.roomid] = null;\n\ttimerEnds[room.roomid] = 0;\n\tfor (const ticket of Object.values(tickets)) {\n\t\tif (!ticket.open) continue;\n\t\tif (!ticket.active) continue;\n\t\tconst ticketRoom = Rooms.get(`help-${ticket.userid}`) as ChatRoom;\n\n\t\tif (ticket.needsDelayWarning && !ticket.claimed && delayWarnings[ticket.type]) {\n\t\t\tticketRoom.add(\n\t\t\t\t`|c|~Staff|${ticketRoom.tr(delayWarningPreamble)}${ticketRoom.tr(delayWarnings[ticket.type])}`\n\t\t\t).update();\n\t\t\tticket.needsDelayWarning = false;\n\t\t}\n\t}\n\tfor (const i in room.users) {\n\t\tconst user: User = room.users[i];\n\t\tif (user.can('mute', null, room) && !user.settings.ignoreTickets) {\n\t\t\tuser.sendTo(\n\t\t\t\troom,\n\t\t\t\t`|tempnotify|helptickets|Unclaimed help tickets!|${hasAssistRequest ? 'Public Room Staff need help' : 'There are unclaimed Help tickets'}`\n\t\t\t);\n\t\t}\n\t}\n}\n\nexport function notifyStaff() {\n\tconst room = Rooms.get('staff');\n\tif (!room) return;\n\tlet buf = ``;\n\tconst sortedTickets = HelpTicket.list();\n\tconst listOnlyTypes = Object.keys(textTickets).filter(type => textTickets[type].listOnly);\n\tlet count = 0;\n\tlet hiddenTicketUnclaimedCount = 0;\n\tlet hiddenTicketCount = 0;\n\tlet hasUnclaimed = false;\n\tlet fourthTicketIndex = 0;\n\tlet hasAssistRequest = false;\n\tfor (const ticket of sortedTickets) {\n\t\tif (!ticket.open || listOnlyTypes.includes(HelpTicket.getTypeId(ticket.type))) continue;\n\t\tif (!ticket.active) continue;\n\t\tif (count >= 3) {\n\t\t\thiddenTicketCount++;\n\t\t\tif (!ticket.claimed) hiddenTicketUnclaimedCount++;\n\t\t\tif (hiddenTicketCount === 1) {\n\t\t\t\tfourthTicketIndex = buf.length;\n\t\t\t} else {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t}\n\t\t// should always exist if it's a normal ticket\n\t\tconst ticketRoom = Rooms.get(`help-${ticket.userid}`);\n\t\tconst ticketGame = ticketRoom?.getGame(HelpTicket);\n\t\tif (!ticket.claimed) {\n\t\t\thasUnclaimed = true;\n\t\t\tif (ticket.type === 'Public Room Assistance Request') hasAssistRequest = true;\n\t\t}\n\t\tif (ticket.text) {\n\t\t\tbuf += HelpTicket.getTextButton(ticket as TicketState & { text: [string, string] });\n\t\t} else if (ticketGame) {\n\t\t\tbuf += ticketGame.getButton();\n\t\t}\n\t\tcount++;\n\t}\n\tif (hiddenTicketCount > 1) {\n\t\tconst notifying = hiddenTicketUnclaimedCount > 0 ? ` notifying` : ``;\n\t\tif (hiddenTicketUnclaimedCount > 0) hasUnclaimed = true;\n\t\tbuf = buf.slice(0, fourthTicketIndex) +\n\t\t\t`<button class=\"button${notifying}\" name=\"send\" value=\"/ht list\">and ${hiddenTicketCount} more Help ticket${Chat.plural(hiddenTicketCount)} (${hiddenTicketUnclaimedCount} unclaimed)</button>`;\n\t}\n\tfor (const type of listOnlyTypes) {\n\t\tconst matches = sortedTickets.filter(\n\t\t\tticket => HelpTicket.getTypeId(ticket.type) === type && ticket.open && !ticket.resolved\n\t\t);\n\t\tif (matches.length) {\n\t\t\thasUnclaimed = true;\n\t\t\tcount += matches.length;\n\t\t\tbuf += `<button class=\"button notifying\" name=\"send\" value=\"/j view-help-list-${type}\">${ticketTitles[type]} (${matches.length} open)</button> `;\n\t\t}\n\t}\n\tbuf = `|${hasUnclaimed ? 'uhtml' : 'uhtmlchange'}|latest-tickets|<div class=\"infobox\" style=\"padding: 6px 4px\">${buf}${count === 0 ? `There were open Help tickets, but they've all been closed now.` : ``}</div>`;\n\troom.send(buf);\n\n\tif (hasUnclaimed) {\n\t\tbuf = `|tempnotify|helptickets|Unclaimed help tickets!|${hasAssistRequest ? 'Public Room Staff need help' : 'There are unclaimed Help tickets'}`;\n\t} else {\n\t\tbuf = `|tempnotifyoff|helptickets`;\n\t}\n\n\tif (hasUnclaimed) {\n\t\t// only notify for people highlighting\n\t\tbuf = `${buf}|${hasAssistRequest ? 'Public Room Staff need help' : 'There are unclaimed Help tickets'}`;\n\t}\n\tfor (const user of Object.values(room.users)) {\n\t\tif (user.can('lock') && !user.settings.ignoreTickets) user.sendTo(room, buf);\n\t\tfor (const connection of user.connections) {\n\t\t\tif (connection.openPages?.has('help-tickets')) {\n\t\t\t\tvoid Chat.resolvePage('view-help-tickets', user, connection);\n\t\t\t}\n\t\t}\n\t}\n\tpokeUnclaimedTicketTimer(hasUnclaimed, hasAssistRequest);\n}\n\nfunction checkIp(ip: string) {\n\tfor (const t in tickets) {\n\t\tif (tickets[t].ip === ip && tickets[t].open && !Punishments.isSharedIp(ip)) {\n\t\t\treturn tickets[t];\n\t\t}\n\t}\n\treturn false;\n}\n\nexport function getBattleLinks(text: string) {\n\tconst rooms = new Set<string>();\n\tconst battles = text.match(BATTLES_REGEX);\n\tconst replays = text.match(REPLAY_REGEX);\n\tif (battles) {\n\t\tfor (const battle of battles) rooms.add(battle);\n\t}\n\tif (replays) {\n\t\tfor (const r of replays) {\n\t\t\trooms.add(`battle-${r.split('/').pop()!}`);\n\t\t}\n\t}\n\treturn [...rooms];\n}\n\nfunction getReportedUser(ticket: TicketState) {\n\tif (!ticket.meta?.startsWith('user-')) return null;\n\tconst id = toID(ticket.meta.slice(5));\n\t// ignoreit if they report themselves for w/e reason\n\treturn (!id || id === ticket.userid) ? null : id;\n}\n\nexport async function listOpponentsFrom(\n\tticket: TicketState & { text: [string, string] }\n) {\n\tconst opps = new Utils.Multiset<string>();\n\tconst links = getBattleLinks(ticket.text[0]).concat(getBattleLinks(ticket.text[1]));\n\tfor (const link of links) {\n\t\tconst opp = await getOpponent(link, ticket.userid);\n\t\tif (opp && opp !== ticket.userid) opps.add(opp);\n\t}\n\treturn Utils.sortBy([...opps], ([, count]) => -count).map(opp => toID(opp[0]));\n}\n\nexport async function getOpponent(link: string, submitter: ID): Promise<string | null> {\n\tconst room = Rooms.get(link) as GameRoom | undefined;\n\t// we can't determine this for FFA - valid guesses can be made for 2 player, but not 4p. not at all.\n\tif (room?.battle) {\n\t\tif (room.battle.playerCap > 2) return null;\n\t\tfor (const k in room.battle.playerTable) {\n\t\t\tif (k === submitter) continue;\n\t\t\treturn k;\n\t\t}\n\t}\n\tif (!room) {\n\t\tconst battleData = await getBattleLog(link);\n\t\tif (battleData) {\n\t\t\treturn battleData.players.p1 === submitter ? battleData.players.p2 : battleData.players.p1;\n\t\t}\n\t}\n\treturn null;\n}\n\nexport async function getBattleLog(battle: string, noReplay = false): Promise<BattleInfo | null> {\n\tconst battleRoom = Rooms.get(battle);\n\tconst seenPokemon = new Set<string>();\n\tlet data: { log: string, players: string[] } | null = null;\n\t// try battle room first\n\tif (battleRoom && battleRoom.type !== 'chat' && battleRoom.battle) {\n\t\tdata = {\n\t\t\tlog: battleRoom.log.log.join('\\n'),\n\t\t\tplayers: battleRoom.battle.players.map(x => x.id),\n\t\t};\n\t} else { // fall back to replay\n\t\tif (noReplay) return null;\n\t\tbattle = battle.replace(`battle-`, ''); // don't wanna strip passwords\n\n\t\tif (Rooms.Replays.db) { // direct conn exists, use it\n\t\t\tif (battle.endsWith('pw')) {\n\t\t\t\tbattle = battle.slice(0, battle.lastIndexOf(\"-\", battle.length - 2));\n\t\t\t}\n\t\t\tdata = await Rooms.Replays.get(battle);\n\t\t} else {\n\t\t\t// call out to API\n\t\t\ttry {\n\t\t\t\tconst raw = await Net(`https://${Config.routes.replays}/${battle}.json`).get();\n\t\t\t\tdata = JSON.parse(raw);\n\t\t\t} catch {}\n\t\t}\n\t}\n\n\t// parse\n\tif (data?.log?.length) {\n\t\tconst log = data.log.split('\\n');\n\t\tconst players: BattleInfo['players'] = {} as any;\n\t\tfor (const [i, id] of data.players.entries()) {\n\t\t\tplayers[`p${i + 1}` as SideID] = toID(id);\n\t\t}\n\t\tconst chat = [];\n\t\tconst mons: BattleInfo['pokemon'] = {};\n\t\tfor (const line of log) {\n\t\t\tif (line.startsWith('|c|')) {\n\t\t\t\tchat.push(line);\n\t\t\t} else if (line.startsWith('|switch|')) {\n\t\t\t\tconst [, , playerWithNick, speciesWithGender] = line.split('|');\n\t\t\t\tconst species = speciesWithGender.split(',')[0].trim(); // should always exist\n\t\t\t\tlet [slot, name] = playerWithNick.split(':');\n\t\t\t\tslot = slot.slice(0, -1); // p2a -> p2\n\t\t\t\t// safe to not check here bc this should always exist in the players table.\n\t\t\t\t// if it doesn't, there's a problem\n\t\t\t\tconst id = players[slot as SideID] as string;\n\t\t\t\tif (!mons[id]) mons[id] = [];\n\t\t\t\tname = name?.trim() || \"\";\n\t\t\t\tconst setId = `${name || \"\"}-${species}`;\n\t\t\t\tif (seenPokemon.has(setId)) continue;\n\t\t\t\tseenPokemon.add(setId);\n\t\t\t\tmons[id].push({\n\t\t\t\t\tspecies, // don't want to see a name if it's the same as the species\n\t\t\t\t\tname: name === species ? undefined : name,\n\t\t\t\t});\n\t\t\t}\n\t\t}\n\t\treturn {\n\t\t\tlog: chat,\n\t\t\ttitle: `${players.p1} vs ${players.p2}`,\n\t\t\turl: `https://${Config.routes.replays}/${battle}`,\n\t\t\tplayers,\n\t\t\tpokemon: mons,\n\t\t};\n\t}\n\treturn null;\n}\n\n// Prevent a desynchronization issue when hotpatching\nfor (const room of Rooms.rooms.values()) {\n\tif (!room.settings.isHelp || !room.game) continue;\n\tconst game = room.getGame(HelpTicket)!;\n\tif (game.ticket && tickets[game.ticket.userid]) game.ticket = tickets[game.ticket.userid];\n}\n\n// convert old-style Staff-room ticketbans to regular ones\nvoid convertRoomPunishments();\n\nconst delayWarningPreamble = `Hi! All global staff members are busy right now and we apologize for the delay. `;\nconst delayWarnings: { [k: string]: string } = {\n\t'PM Harassment': `Please make sure you have given us the permission to check the PMs between you and the user you reported. You can also provide any relevant context; for example, a replay of a battle with the person you're reporting.`,\n\t'Battle Harassment': `Please save the replay of the battle and provide a link to it in this chat, so we can see the harassment even if the battle expires. You can save the replay by clicking on the \"Upload and share replay\" button once the battle has ended.`,\n\t'Inappropriate Username': `Make sure you have provided the correct username, and if its meaning or why it is offensive is not obvious, please explain why it should not be allowed.`,\n\t'Inappropriate Pokemon Nicknames': `Please save the replay of the battle and provide a link to it in this chat, so we can see the nicknames even if the battle expires. You can save the replay by clicking on the \"Upload and share replay\" button once the battle has ended.`,\n\t'Appeal': `Please clearly explain why you should be unlocked and we will review it as soon as possible.`,\n\t'IP-Appeal': `Please give us all relevant information on how you are connecting to Pok\u00E9mon Showdown (if it is through mobile data, at home, a school or work network, etc), and we will review your case as soon as possible.`,\n\t'Public Room Assistance Request': `Please tell us which room you need assistance with and a global staff member will join your room as soon as possible.`,\n\tother: `If your issue pertains to battle mechanics or is a question about Pok\u00E9mon Showdown, you can ask in the <<help>> chatroom.`,\n};\nconst ticketTitles: { [k: string]: string } = {\n\tpmharassment: `PM Harassment`,\n\tbattleharassment: `Battle Harassment`,\n\tinapname: `Inappropriate Username`,\n\tinappokemon: `Inappropriate Pokemon Nicknames`,\n\tappeal: `Appeal`,\n\tipappeal: `IP-Appeal`,\n\troomhelp: `Public Room Assistance Request`,\n\tother: `Other`,\n};\nconst ticketPages: { [k: string]: string } = {\n\treport: `I want to report someone`,\n\tpmharassment: `Someone is harassing me in PMs`,\n\tbattleharassment: `Someone is harassing me in a battle`,\n\tinapname: `Someone is using an offensive username`,\n\tinappokemon: `Someone is using offensive Pokemon nicknames`,\n\tcheating: `Someone is hacking or cheating in my battle`,\n\n\tappeal: `I want to appeal a punishment`,\n\tpermalock: `I want to appeal my permalock`,\n\tlock: `I want to appeal my lock`,\n\tip: `I'm locked because I have the same IP as someone I don't recognize.`,\n\thomeip: `I'm locked because someone in my home was punished.`,\n\tdevice: `I'm locked because someone misused my device or account.`,\n\tmobileip: `I am using mobile data.`,\n\tpublic: `I am at a public place (school, library, workplace, etc) or was locked in one.`,\n\ttimeleft: `I want to know how long is left on my lock.`,\n\treason: `I want to know why I was locked.`,\n\tstartedit: `The other user started it.`,\n\tsemilock: `I can't talk in chat because of my ISP`,\n\thostfilter: `I'm locked because of a proxy or VPN`,\n\thasautoconfirmed: `Yes, I have an autoconfirmed account`,\n\tlacksautoconfirmed: `No, I don't have an autoconfirmed account`,\n\tappealother: `I want to appeal a mute/roomban/blacklist`,\n\n\tmisc: `Something else`,\n\tpassword: `I lost my password`,\n\troomhelp: `I need global staff to help watch a public room`,\n\tother: `Other`,\n\n\tconfirmpmharassment: `Report harassment in a private message (PM)`,\n\tconfirmbattleharassment: `Report harassment in a battle`,\n\tconfirminapname: `Report an inappropriate username`,\n\tconfirminappokemon: `Report inappropriate Pokemon nicknames`,\n\tconfirmappeal: `Appeal your lock`,\n\tconfirmipappeal: `Appeal IP lock`,\n\tconfirmroomhelp: `Call a Global Staff member to help`,\n\tconfirmother: `Call a Global Staff member`,\n};\nconst cheatingScenarios = [\n\t[\n\t\t`My opponent's Pokemon used moves it couldn't learn`,\n\t\t`It was probably a disguised Zoroark (<psicon pokemon=\"zoroark\" />), which has the ability <a href=\"//${Config.routes.dex}/abilities/illusion\">Illusion</a>. This happens often in Random Battles!`,\n\t],\n\t[\n\t\t`My opponent got very lucky (critical hits, freezes, flinches, etc.)`,\n\t\t`Sometimes, <a href=\"//${Config.routes.root}/pages/rng\">that's just how RNG works</a>!`,\n\t],\n\t[\n\t\t`My opponent used six of the same Pokemon or too many Legendaries`,\n\t\t`Certain tiers, like Anything Goes, do not have Species Clause, which normally restricts a player to only one of each Pokemon. In addition, many tiers allow lots of legendaries, and you are allowed to use them!`,\n\t],\n\t[\n\t\t`My Pokemon used a move I didn't choose`,\n\t\t`You accidentally selected the wrong move and didn't notice. It happens more often than you might think!`,\n\t],\n\t[\n\t\t`My Pokemon moved last when it shouldn't have`,\n\t\t`You probably accidentally chose a move with negative priority, like Trick Room, Dragon Tail, or Roar.`,\n\t],\n\t[\n\t\t`My Pokemon's Ability didn't work`,\n\t\t`Perhaps Weezing's <a href=\"//${Config.routes.dex}/abilities/neutralizinggas\">Neutralizing Gas</a> was active (<psicon pokemon=\"weezinggalar\" />), or another effect, like <a href=\"https://dex.pokemonshowdown.com/abilities/moldbreaker\">Mold Breaker</a>, was suppressing the Ability.`,\n\t],\n\t[\n\t\t`My Pokemon's move failed when I attacked the opponent in a Double Battle)`,\n\t\t`You attacked your own partner Pokemon, which failed because no Pokemon was there.`,\n\t],\n];\n\nexport const textTickets: { [k: string]: TextTicketInfo } = {\n\tpmharassment: {\n\t\ttitle: \"Who's harassing you in PMs?\",\n\t\tchecker(input) {\n\t\t\tif (!Users.get(input)) {\n\t\t\t\treturn ['That user was not found.'];\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\tasync getReviewDisplay(ticket, staff, conn) {\n\t\t\tlet buf = '';\n\t\t\tconst reportUserid = toID(ticket.text[0]);\n\t\t\tconst sharedBattles = getCommonBattles(ticket.userid, null, reportUserid, null, conn);\n\t\t\tlet replays = getBattleLinks(ticket.text[1]).concat(getBattleLinks(ticket.text[1]));\n\t\t\treplays = replays.filter((url, index) => replays.indexOf(url) === index).concat(sharedBattles);\n\t\t\tconst replayString = replays.map(u => `https://${Config.routes.client}/${u}`).join(', ');\n\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\tticket.userid,\n\t\t\t\t`spoiler:PMs with ${reportUserid} (as ${ticket.userid})${replayString ? `, ${replayString}` : ''}`,\n\t\t\t\tticket,\n\t\t\t\t`Punish <strong>${ticket.userid}</strong> (reporter)`,\n\t\t\t\t`<h2 style=\"color:red\">You are about to punish the reporter. Are you sure you want to do this?</h2>`,\n\t\t\t);\n\t\t\tbuf += `<strong>Reported user:</strong> <span class=\"username\">${reportUserid}</span> </strong>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${reportUserid}'\">Global Modlog</button><br />`;\n\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\treportUserid,\n\t\t\t\t`spoiler:PMs with ${ticket.userid}${replayString ? `, ${replayString}` : ''}`,\n\t\t\t\tticket,\n\t\t\t\t`Punish <strong>${reportUserid}</strong> (reported user)`\n\t\t\t);\n\n\t\t\tif (replays.length) {\n\t\t\t\tconst battleLogHTML = await HelpTicket.visualizeBattleLogs(replays, reportUserid);\n\t\t\t\tif (battleLogHTML) {\n\t\t\t\t\tbuf += `<br />`;\n\t\t\t\t\tbuf += battleLogHTML;\n\t\t\t\t\tbuf += `<br />`;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn buf;\n\t\t},\n\t\tonSubmit(ticket, text, submitter, conn) {\n\t\t\tconst targetId = toID(text[0]);\n\t\t\t// this does the saving for us so we don't have to do anything else\n\t\t\tgetCommonBattles(targetId, Users.get(targetId), submitter.id, submitter, conn);\n\t\t},\n\t},\n\tinapname: {\n\t\ttitle: \"What's the inappropriate username?\",\n\t\tcontextMessage: \"If the username is offensive in a non-English language, or if it's not obvious, please be sure to explain below.\",\n\t\tchecker(input) {\n\t\t\tif (!Users.get(input)) {\n\t\t\t\treturn [\n\t\t\t\t\t\"Please specify a valid username - that name was not found.\",\n\t\t\t\t\t\"Maybe you spelled it wrong?\",\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\tgetReviewDisplay(ticket, staff, conn, state) {\n\t\t\tlet buf = ``;\n\t\t\tif (!ticket.open) return buf;\n\t\t\tconst cmds: [string, string][] = [\n\t\t\t\t['Forcerename', '/forcerename'],\n\t\t\t\t['Namelock', '/namelock'],\n\t\t\t\t['Weeknamelock', '/weeknamelock'],\n\t\t\t];\n\t\t\tconst tar = toID(ticket.text[0]); // should always be the reported userid\n\t\t\tconst name = Utils.escapeHTML(Users.getExact(tar)?.name || tar);\n\t\t\tbuf += `<br /><strong>Reported user:</strong> <a href=\"https://${Config.routes.root}/users/${name}\">${name}</a> `;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${tar}'\">Global Modlog</button><br />`;\n\t\t\tbuf += `<details ${state?.list ? 'open' : ''} class=\"readmore\">`;\n\t\t\tbuf += `<summary>Punish <strong>${name}</strong> (reported user)</summary>`;\n\t\t\tbuf += `<div class=\"infobox\">`;\n\t\t\tfor (const [cmdName, cmd] of cmds) {\n\t\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,${cmd} ${tar},{reason}\">`;\n\t\t\t\tbuf += `<button class=\"button notifying\" type=\"submit\">${cmdName}</button><br />`;\n\t\t\t\tbuf += `Reason (optional:) <input name=\"reason\" /></form><br />`;\n\t\t\t}\n\t\t\tbuf += `</div></details>`;\n\t\t\treturn buf;\n\t\t},\n\t\tonSubmit(ticket, text) {\n\t\t\tif (!ticket.meta?.startsWith('user-')) {\n\t\t\t\t// we validate that `text` is the id of existing user, so this is safe.\n\t\t\t\tticket.meta = `user-${toID(text)}`;\n\t\t\t}\n\t\t},\n\t},\n\tbattleharassment: {\n\t\ttitle: \"Please provide a link to the battle (taken from the \\\"Upload and share\\\" button or copied from the browser URL)\",\n\t\tasync checker(input, context) {\n\t\t\tconst replays = getBattleLinks(input).concat(getBattleLinks(context));\n\t\t\tif (!replays.length) {\n\t\t\t\treturn ['Please provide at least one valid battle or replay URL.'];\n\t\t\t}\n\t\t\tlet atLeastOne = false;\n\t\t\tfor (const replay of replays) {\n\t\t\t\tconst log = await getBattleLog(replay);\n\t\t\t\tif (log) {\n\t\t\t\t\tatLeastOne = true;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!atLeastOne) {\n\t\t\t\treturn [\n\t\t\t\t\t'None of the battle links provided are valid.',\n\t\t\t\t\t'They may have expired, or you may have misspelled the URL.',\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\tonSubmit(ticket, text, submitter, conn) {\n\t\t\tfor (const part of text) {\n\t\t\t\tHelpTicket.uploadReplaysFrom(part, submitter, conn);\n\t\t\t}\n\t\t},\n\t\tasync getReviewDisplay(ticket, staff, connection) {\n\t\t\tlet buf = ``;\n\t\t\tconst [text, context] = ticket.text;\n\t\t\tlet rooms = getBattleLinks(text);\n\n\t\t\tif (context) {\n\t\t\t\trooms.push(...getBattleLinks(context));\n\t\t\t}\n\t\t\tif (ticket.meta?.startsWith('room-')) {\n\t\t\t\trooms.push(...getBattleLinks(ticket.meta.slice(5)));\n\t\t\t}\n\t\t\trooms = rooms.filter((url, index) => rooms.indexOf(url) === index);\n\t\t\tconst proof = rooms.map(u => `https://${Config.routes.client}/${u}`).join(', ');\n\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\tticket.userid,\n\t\t\t\tproof,\n\t\t\t\tticket,\n\t\t\t\t`Punish <strong>${ticket.userid}</strong> (reporter)`,\n\t\t\t\t`<h2 style=\"color:red\">You are about to punish the reporter. Are you sure you want to do this?</h2>`\n\t\t\t);\n\t\t\tconst opp = getReportedUser(ticket) || (await listOpponentsFrom(ticket))[0];\n\t\t\tif (opp) {\n\t\t\t\tbuf += `<br /><strong>Reported user:</strong> <span class=\"username\">${opp}</span> `;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${opp}'\">Global Modlog</button><br />`;\n\t\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\t\topp,\n\t\t\t\t\tproof,\n\t\t\t\t\tticket,\n\t\t\t\t\t`Punish <strong>${opp}</strong> (reported user)`\n\t\t\t\t);\n\t\t\t}\n\t\t\tbuf += `<strong>Battle links:</strong> ${rooms.map(url => Chat.formatText(`<<${url}>>`)).join(', ')}<br />`;\n\t\t\tbuf += `<br />`;\n\t\t\tconst battleLogHTML = await HelpTicket.visualizeBattleLogs(rooms, opp);\n\t\t\tif (battleLogHTML) buf += battleLogHTML;\n\t\t\treturn buf;\n\t\t},\n\t},\n\troomhelp: {\n\t\ttitle: \"Enter the name of the room\",\n\t\tgetReviewDisplay(ticket, staff) {\n\t\t\tlet buf = ``;\n\t\t\tconst room = Rooms.search(ticket.text[0])!;\n\t\t\tif (!staff.inRooms.has(room.roomid)) {\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,/join ${room.roomid}\">Join room</button>`;\n\t\t\t\tbuf += `<br />`;\n\t\t\t} else {\n\t\t\t\tbuf += `<p>You're already in that room.</p>`;\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\tchecker(input) {\n\t\t\tconst room = Rooms.search(input);\n\t\t\tif (!room) {\n\t\t\t\treturn [\n\t\t\t\t\t`That room was not found.`,\n\t\t\t\t\t`Enter either the room name or a room alias.`,\n\t\t\t\t];\n\t\t\t}\n\t\t\tif (room.settings.isPrivate) {\n\t\t\t\treturn ['You may only request help for public rooms.'];\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t},\n\tinappokemon: {\n\t\ttitle: \"Please provide replays of the battle with inappropriate Pokemon nicknames\",\n\t\tdisclaimer: \"If the nickname is offensive in a non-english language, or if it's not obvious, please be sure to explain.\",\n\t\tchecker(input) {\n\t\t\tif (BATTLES_REGEX.test(input) || REPLAY_REGEX.test(input)) return true;\n\t\t\treturn ['Please provide at least one valid battle or replay URL.'];\n\t\t},\n\t\tasync getReviewDisplay(ticket, staff, conn) {\n\t\t\tlet buf = ``;\n\t\t\tconst [text, context] = ticket.text;\n\t\t\tlet links = getBattleLinks(text);\n\t\t\tif (context) links.push(...getBattleLinks(context));\n\t\t\tconst proof = links.join(', ');\n\t\t\tconst opp = getReportedUser(ticket) || (await listOpponentsFrom(ticket))[0];\n\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\tticket.userid,\n\t\t\t\tproof,\n\t\t\t\tticket,\n\t\t\t\t`Punish <strong>${ticket.userid}</strong> (reporter)`,\n\t\t\t\t`<h2 style=\"color:red\">You are about to punish the reporter. Are you sure you want to do this?</h2>`\n\t\t\t);\n\t\t\tif (opp) {\n\t\t\t\tbuf += `<strong>Reported user:</strong> <span class=\"username\">${opp}</span> </strong>`;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${opp}'\">Global Modlog</button><br />`;\n\t\t\t\tbuf += HelpTicket.displayPunishmentList(\n\t\t\t\t\topp,\n\t\t\t\t\tproof,\n\t\t\t\t\tticket,\n\t\t\t\t\t`Punish <strong>${opp}</strong> (reported)`,\n\t\t\t\t);\n\t\t\t}\n\t\t\tbuf += `<p><strong>Battle links given:</strong><p>`;\n\t\t\tlinks = links.filter((url, i) => links.indexOf(url) === i);\n\t\t\tbuf += links.map(uri => Chat.formatText(`<<${uri}>>`)).join(', ');\n\t\t\tbuf += `<div class=\"infobox\"><strong>Names in given battles:</strong><hr />`;\n\t\t\tfor (const link of links) {\n\t\t\t\tconst names = [];\n\t\t\t\tconst roomData = await getBattleLog(link);\n\t\t\t\tif (!roomData) continue;\n\t\t\t\tfor (const id of Object.values(roomData.players)) {\n\t\t\t\t\tconst user = Users.get(id)?.name || id;\n\t\t\t\t\tconst team = roomData.pokemon[id];\n\t\t\t\t\tif (team) {\n\t\t\t\t\t\tconst teamNames = team.map(p => (\n\t\t\t\t\t\t\tp.name !== p.species ? Utils.html`${p.name} (${p.species})` : p.species\n\t\t\t\t\t\t));\n\t\t\t\t\t\tnames.push(`<strong>${user}:</strong> ${teamNames.join(', ')}`);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (names.length) {\n\t\t\t\t\tbuf += `<a href=\"/${getBattleLinks(link)[0]}\">${roomData.title}</a><br />`;\n\t\t\t\t\tbuf += names.join('<br />');\n\t\t\t\t\tbuf += `<hr />`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += `</div>`;\n\t\t\treturn buf;\n\t\t},\n\t\tonSubmit(ticket, text, submitter, conn) {\n\t\t\tfor (const part of text) {\n\t\t\t\tHelpTicket.uploadReplaysFrom(part, submitter, conn);\n\t\t\t}\n\t\t},\n\t},\n\tipappeal: {\n\t\ttitle: \"Where are you currently connecting from? Please give its name, city, and country.\",\n\t\tasync getReviewDisplay(ticket, staff, conn, state) {\n\t\t\tconst tarUser = Users.get(ticket.userid);\n\t\t\tlet info = state?.ips;\n\t\t\tconst stringIps = info?.some((f: any) => typeof f === 'string');\n\t\t\tif (!info || stringIps) {\n\t\t\t\tconst ips = stringIps ? [...info] : tarUser?.ips;\n\t\t\t\tinfo = [];\n\t\t\t\tif (ips?.length) {\n\t\t\t\t\tfor (const ip of ips) {\n\t\t\t\t\t\tinfo.push({ ...await IPTools.lookup(ip), ip });\n\t\t\t\t\t}\n\t\t\t\t\tif (!ticket.state) {\n\t\t\t\t\t\tticket.state = info;\n\t\t\t\t\t\twriteTickets();\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet buf = `<strong>IPs:</strong><br />`;\n\t\t\tfor (const data of info) {\n\t\t\t\tconst ip = data.ip;\n\t\t\t\tbuf += `<details class=\"readmore\"><summary>`;\n\t\t\t\tbuf += `<strong><a href=\"https://whatismyipaddress.com/ip/${ip}\">${ip}</a></strong></summary>`;\n\t\t\t\tconst ipPunishments = Punishments.ips.get(ip);\n\t\t\t\tif (ipPunishments) {\n\t\t\t\t\tconst str = ipPunishments.map(p => (\n\t\t\t\t\t\t`${Punishments.punishmentTypes.get(p.type)?.desc || p.type} as ` +\n\t\t\t\t\t\t`<a href=\"https://${Config.routes.root}/users/${p.id}\">${p.id}</a>` +\n\t\t\t\t\t\t`${p.reason ? ` (${p.reason})` : ''}`\n\t\t\t\t\t));\n\t\t\t\t\tif (str) buf += `Punishments: ${str.join(' | ')}<br />`;\n\t\t\t\t}\n\t\t\t\tbuf += `Host: ${data.shortHost} [${data.hostType}]<br />`;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,ip=${ip}\">Modlog</button><br />`;\n\t\t\t\tif (ipPunishments) {\n\t\t\t\t\tconst unlockCmd = staff.can('globalban') ?\n\t\t\t\t\t\t`/unlockip ${ip}` :\n\t\t\t\t\t\t`Can someone \\`\\`/unlockip ${ip}\\`\\` (${data.hostType} host)`;\n\t\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/msgroom staff,${unlockCmd}\">Unlock IP</button><br />`;\n\t\t\t\t\tconst marksharedCmd = staff.can('globalban') ?\n\t\t\t\t\t\t`/markshared ${ip}, {owner}` :\n\t\t\t\t\t\t`Can someone \\`\\`/markshared ${ip}, {owner}\\`\\``;\n\t\t\t\t\tbuf += `<form data-submitsend=\"/msgroom staff,${marksharedCmd}\">`;\n\t\t\t\t\tbuf += `<input name=\"owner\" placeholder=\"School/Organization Name, City, Country\" size=\"40\" required />`;\n\t\t\t\t\tbuf += `<button class=\"button\" type=\"submit\">Mark as shared IP</button>`;\n\t\t\t\t\tbuf += `</form>`;\n\t\t\t\t}\n\t\t\t\tbuf += `</details>`;\n\t\t\t}\n\n\t\t\treturn buf;\n\t\t},\n\t\tgetState(ticket, user) {\n\t\t\treturn { ips: user.ips };\n\t\t},\n\t\tchecker(text, context, pageId, user) {\n\t\t\tif (!toID(text)) {\n\t\t\t\treturn ['Please tell us where you are connecting from.'];\n\t\t\t}\n\t\t\tif (!(user.locked || user.namelocked || user.semilocked)) {\n\t\t\t\treturn ['You are not punished.'];\n\t\t\t}\n\t\t\tif (!user.registered) {\n\t\t\t\treturn [\n\t\t\t\t\t\"Because this account isn't registered (with a password), we cannot verify your identity.\",\n\t\t\t\t\t\"Please come back with a different account you've registered in the past.\",\n\t\t\t\t];\n\t\t\t}\n\t\t\tconst punishments = Punishments.search(user.id);\n\t\t\tconst userids = [user.id, ...user.previousIDs];\n\n\t\t\tif (punishments.length) {\n\t\t\t\tfor (const [, , punishment] of punishments) {\n\t\t\t\t\tif (userids.includes(punishment.id as ID)) {\n\t\t\t\t\t\treturn ['Your current punishment was explicitly given to you. Please open an Appeal ticket instead.'];\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (user.ips.some(i => Punishments.isBlacklistedSharedIp(i))) {\n\t\t\t\treturn [\n\t\t\t\t\t\"Your network has too many users who consistently misbehave on it. As such, we cannot unlock you, to ensure they don't abuse it.\",\n\t\t\t\t\t\"Apologies for the inconvenience. It should expire in a few days.\",\n\t\t\t\t];\n\t\t\t}\n\t\t\treturn true;\n\t\t},\n\t\tasync onSubmit(ticket, text, user) {\n\t\t\tconst ips = [];\n\t\t\tfor (const ip of user.ips) {\n\t\t\t\tips.push({ ...await IPTools.lookup(ip), ip });\n\t\t\t}\n\t\t\tticket.state = ips;\n\t\t\twriteTickets();\n\t\t},\n\t},\n};\n\nexport const pages: Chat.PageTable = {\n\thelp: {\n\t\trequest(query, user, connection) {\n\t\t\tif (!user.named) {\n\t\t\t\tconst buf = `>view-help-request${query.length ? '-' + query.join('-') : ''}\\n` +\n\t\t\t\t\t`|init|html\\n` +\n\t\t\t\t\t`|title|Request Help\\n` +\n\t\t\t\t\t`|pagehtml|<div class=\"pad\"><h2>${this.tr`Request help from global staff`}</h2><p>${this.tr`Please <button name=\"login\" class=\"button\">Log In</button> to request help.`}</p></div>`;\n\t\t\t\tconnection.send(buf);\n\t\t\t\treturn Rooms.RETRY_AFTER_LOGIN;\n\t\t\t}\n\t\t\tthis.title = this.tr`Request Help`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>${this.tr`Request help from global staff`}</h2>`;\n\n\t\t\tconst ticketBan = Punishments.isTicketBanned(user);\n\t\t\tif (ticketBan) {\n\t\t\t\treturn connection.popup(HelpTicket.getBanMessage(user.id, ticketBan));\n\t\t\t}\n\t\t\tlet ticket = tickets[user.id];\n\t\t\tconst ipTicket = checkIp(user.latestIp);\n\t\t\tif (ticket?.open || ipTicket) {\n\t\t\t\tif (!ticket && ipTicket) ticket = ipTicket;\n\t\t\t\tconst helpRoom = Rooms.get(`help-${ticket.userid}`);\n\t\t\t\tif (!helpRoom && !ticket.text) {\n\t\t\t\t\t// Should never happen\n\t\t\t\t\ttickets[ticket.userid].open = false;\n\t\t\t\t\twriteTickets();\n\t\t\t\t} else {\n\t\t\t\t\tif (helpRoom) {\n\t\t\t\t\t\tif (!helpRoom.auth.has(user.id)) helpRoom.auth.set(user.id, '+');\n\t\t\t\t\t\tuser.joinRoom(`help-${ticket.userid}` as RoomID);\n\t\t\t\t\t}\n\t\t\t\t\tconnection.popup(this.tr`You already have a Help ticket.`);\n\t\t\t\t\treturn this.close();\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst isStaff = user.can('lock');\n\t\t\t// room / user being reported\n\t\t\tlet meta = '';\n\t\t\tconst targetTypeIndex = Math.max(query.indexOf('user'), query.indexOf('room'));\n\t\t\tif (targetTypeIndex >= 0) meta = '-' + query.splice(targetTypeIndex).join('-');\n\t\t\tif (!query.length) query = [''];\n\t\t\tfor (const [i, page] of query.entries()) {\n\t\t\t\tconst isLast = (i === query.length - 1);\n\t\t\t\tconst isFirst = i === 1;\n\t\t\t\tif (page && page in ticketPages && !page.startsWith('confirm')) {\n\t\t\t\t\tlet prevPageLink = query.slice(0, i).join('-');\n\t\t\t\t\tif (prevPageLink) prevPageLink = `-${prevPageLink}`;\n\t\t\t\t\tbuf += `<p><a href=\"/view-help-request${prevPageLink}${!isFirst ? meta : ''}\" target=\"replace\"><button class=\"button\">${this.tr`Back`}</button></a> <button class=\"button disabled\" disabled>${this.tr(ticketPages[page])}</button></p>`;\n\t\t\t\t}\n\t\t\t\tswitch (page) {\n\t\t\t\tcase '':\n\t\t\t\t\tbuf += `<p><b>${this.tr`What's going on?`}</b></p>`;\n\t\t\t\t\tif (isStaff) {\n\t\t\t\t\t\tbuf += `<p class=\"message-error\">${this.tr`Global staff cannot make Help requests. This form is only for reference.`}</p>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbuf += `<p class=\"message-error\">${this.tr`Abuse of Help requests can result in punishments.`}</p>`;\n\t\t\t\t\t}\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>report</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>appeal</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>misc</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'report':\n\t\t\t\t\tbuf += `<p><b>${this.tr`What do you want to report someone for?`}</b></p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>pmharassment</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>battleharassment</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>inapname</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>inappokemon</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>cheating</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'pmharassment':\n\t\t\t\t\tbuf += `<p>${this.tr`If someone is harassing you in private messages (PMs), click the button below and a global staff member will take a look. If you are being harassed in a chatroom, please ask a room staff member to handle it.`}`;\n\t\t\t\t\tif (!this.pageid.includes('confirm')) {\n\t\t\t\t\t\tbuf += ` If it's a minor issue, consider using <code>/ignore [username]</code> instead.`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirmpmharassment</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'battleharassment':\n\t\t\t\t\tbuf += `<p>${this.tr`If someone is harassing you in a battle, click the button below and a global staff member will take a look. If you are being harassed in a chatroom, please ask a room staff member to handle it.`}`;\n\t\t\t\t\tif (!this.pageid.includes('confirm')) {\n\t\t\t\t\t\tbuf += ` If it's a minor issue, consider using <code>/ignore [username]</code> instead.`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`Please save a replay of the battle if it has ended, or provide a link to the battle if it is still ongoing.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirmbattleharassment</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'inapname':\n\t\t\t\t\tbuf += `<p>${this.tr`If a user has an inappropriate name, click the button below and a global staff member will take a look.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirminapname</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'inappokemon':\n\t\t\t\t\tbuf += `<p>${this.tr`If a user has inappropriate Pokemon nicknames, click the button below and a global staff member will take a look.`}</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`Please save a replay of the battle if it has ended, or provide a link to the battle if it is still ongoing.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirminappokemon</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'cheating':\n\t\t\t\t\tbuf += `<p>Your opponent cannot control how lucky or unlucky you are, what moves you choose, or the mechanics of the battle. You may just be misunderstanding what happened in your battle!</p>`;\n\t\t\t\t\tbuf += `<h4>Some common situations</h4><ul>`;\n\t\t\t\t\tfor (const [scenario, explanation] of cheatingScenarios) {\n\t\t\t\t\t\tbuf += `<li><details class=\"readmore\"><summary>${scenario}</summary><br />${explanation}<br /><br /></details></li>`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `</ul><p>There are many more situations like this where the opponent was not cheating or hacking. If you're confused about what happened, upload your battle replay and share it with the Help room. They can help you understand what happened!</p>`;\n\t\t\t\t\tbuf += `<p style=\"text-align: center\"><button class=\"button\" name=\"send\" value=\"/j help\"><strong>Join the Help Room</strong></button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'appeal':\n\t\t\t\t\t// buf += `<p><b>${this.tr`What would you like to appeal?`}</b></p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tif (user.locked || isStaff) {\n\t\t\t\t\t\tconst hostfiltered = user.locked === '#hostfilter' || (user.latestHostType === 'proxy' && user.locked !== user.id);\n\t\t\t\t\t\tif (!hostfiltered) {\n\t\t\t\t\t\t\tbuf += `<p><strong>I want to appeal my lock.</strong></p>`;\n\t\t\t\t\t\t\tconst namelocked = user.named && user.id.startsWith('guest');\n\t\t\t\t\t\t\tif (user.locked === user.id || namelocked || isStaff) {\n\t\t\t\t\t\t\t\tif (user.permalocked || isStaff) {\n\t\t\t\t\t\t\t\t\tbuf += `<p><Button>permalock</Button></p>`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\tif (!user.permalocked || isStaff) {\n\t\t\t\t\t\t\t\t\tbuf += `<p><Button>lock</Button></p>`;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tfor (const type of ['timeleft', 'reason', 'startedit']) {\n\t\t\t\t\t\t\t\tbuf += `<p><Button>${type}</Button></p>`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuf += `<p><strong>I'm locked under a name or IP I don't recognize.</strong></p>`;\n\t\t\t\t\t\tif (hostfiltered) {\n\t\t\t\t\t\t\tbuf += `<p><Button>hostfilter</Button></p>`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (!hostfiltered || isStaff) {\n\t\t\t\t\t\t\tfor (const type of ['public', 'homeip', 'mobileip', 'device']) {\n\t\t\t\t\t\t\t\tbuf += `<p><Button>${type}</Button></p>`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\tif ((user.locked !== '#hostfilter' && user.latestHostType !== 'proxy' && user.locked !== user.id) || isStaff) {\n\t\t\t\t\t\t\t\tbuf += `<p><Button>ip</Button></p>`;\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `<p><strong>I am punished but do not fall under any of the above.</strong></p>`;\n\t\t\t\t\tif (user.semilocked || isStaff) {\n\t\t\t\t\t\tbuf += `<p><Button>semilock</Button></p>`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `<p><Button>appealother</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>other</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'permalock':\n\t\t\t\t\tbuf += `<p>${this.tr`Permalocks are usually for repeated incidents of poor behavior over an extended period of time, and rarely for a single severe infraction. Please keep this in mind when appealing a permalock.`}</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`Please visit the <a href=\"https://www.smogon.com/forums/threads/discipline-appeal-rules.3583479/\">Discipline Appeals</a> page to appeal your permalock.`}</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'lock':\n\t\t\t\t\tbuf += `<p>${this.tr`If you want to appeal your lock or namelock, click the button below and a global staff member will be with you shortly.`}</p>`;\n\t\t\t\t\tbuf += `<p>You will have to explain in detail why your punishment is unjustified and why we would want to unlock you. Insufficient explanations such as \"lol this is bs unlock me\" will not be considered.</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirmappeal</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'ip':\n\t\t\t\t\tbuf += `<p>${this.tr`If you are locked or namelocked under a name you don't recognize, click the button below to call a global staff member so we can check.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirmipappeal</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'homeip':\n\t\t\t\t\tbuf += `<p>If you are using your home's wifi network, it means that the person you are being mistaken for did as well (maybe a family member?).</p>`;\n\t\t\t\t\tbuf += `<p>In any case, we have no ability to make the difference - for all we know, you are the same user. Please wait out the lock.</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'device':\n\t\t\t\t\tbuf += `<p>Sorry, but you are considered responsible for whoever has access to your computer.</p>`;\n\t\t\t\t\tbuf += `<p>We have no way to make the difference between two people using the exact same computer. Please wait out the lock.</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'mobileip':\n\t\t\t\t\tbuf += `<p>If you are not the user who was punished, the lock should expire on its own within a few hours.</p>`;\n\t\t\t\t\tbuf += `<p>If you are in a hurry to communicate with another user, you can click on the following button to open a ticket.</p>`;\n\t\t\t\t\tbuf += `<p>A staff member will look at your case as soon as possible.</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<button name=\"send\" value=\"/ht submit IP-Appeal|||I am on a mobile IP.|\">Submit ticket</button>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'public':\n\t\t\t\t\tif (user.ips.some(ip => Punishments.sharedIpBlacklist.has(ip))) {\n\t\t\t\t\t\tbuf += \"<p>The public place you are in has had frequent misbehavior. As such, we can not unlock it, to prevent the bad users on it from abusing this. We apologize for the inconvenience.</p>\";\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbuf += `<p>If you have been locked at school or in a library, please write down its name, city and country in the form below so we can verify your claim. This information is strictly confidential, and global staff will only use it to deal with your appeal.</p>`;\n\t\t\t\t\t\tbuf += `<p>If you have been locked using the wifi of another type of facility, please write down which kind it is in the form.</p>`;\n\t\t\t\t\t\tbuf += `<p><Button>confirmipappeal</Button></p>`;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'timeleft':\n\t\t\t\t\tconst expiry = Punishments.checkLockExpiration(user.id);\n\t\t\t\t\tif (typeof expiry !== 'string') {\n\t\t\t\t\t\tbuf += `<p>You aren't locked.</p>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbuf += `Your lock ${expiry.trim().replace('(', '').replace(')', '') || \"expires soon\"}.`;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'reason':\n\t\t\t\t\tconst punishments = Punishments.search(user.id)\n\t\t\t\t\t\t.map(p => p[2])\n\t\t\t\t\t\t.filter(t => ['LOCK', 'NAMELOCK'].includes(t.type));\n\t\t\t\t\tif (!punishments.some(p => p.reason)) {\n\t\t\t\t\t\tbuf += `<p>No reasons were found on your lock.</p>`;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tfor (const [idx, punishment] of punishments.entries()) {\n\t\t\t\t\t\tif (punishments.indexOf(punishment) !== idx) {\n\t\t\t\t\t\t\tcontinue;\n\t\t\t\t\t\t} else if (punishment.reason) {\n\t\t\t\t\t\t\tbuf += Utils.html`<p>Your ${punishment.type} was for: ${punishment.reason}.</p>`;\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'startedit':\n\t\t\t\t\tbuf += `<p>If you have been locked, it is because your behavior on its own has broken PS rules - whether someone else \"started\" it does not excuse it.</p>`;\n\t\t\t\t\tbuf += `<p>If someone broke the rules during the interaction with led to your lock, they should have been punished as well when we addressed the report concerning you.</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'hostfilter':\n\t\t\t\t\tbuf += `<p>${this.tr`We automatically lock proxies and VPNs to prevent evasion of punishments and other attacks on our server. To get unlocked, you need to disable your proxy or VPN.`}</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`If you must use a proxy / VPN to access Pokemon Showdown (e.g. your school blocks the site normally), you will only be able to battle, not chat. When you go home, you will be unlocked and able to freely chat again.`}</p>`;\n\t\t\t\t\tbuf += `<p>For more detailed information, view the <a href=\"//${Config.routes.root}/pages/proxyhelp\">proxy help guide</a>.</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`If you are certain that you are not currently using a proxy / VPN, please continue and open a ticket. Please explain in detail how you are connecting to Pokemon Showdown.`}</p>`;\n\t\t\t\t\tbuf += `<p><Button>confirmipappeal</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'semilock':\n\t\t\t\t\tbuf += `<p>${this.tr`Do you have an autoconfirmed account? An account is autoconfirmed when it has won at least one rated battle and has been registered for one week or longer.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>hasautoconfirmed</Button> <Button>lacksautoconfirmed</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'hasautoconfirmed':\n\t\t\t\t\tbuf += `<p>${this.tr`Login to your autoconfirmed account by using the <code>/nick</code> command in any chatroom, and the semilock will automatically be removed. Afterwards, you can use the <code>/nick</code> command to switch back to your current username without being semilocked again.`}</p>`;\n\t\t\t\t\tbuf += `<p>${this.tr`If the semilock does not go away, you can try asking a global staff member for help.`}</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'lacksautoconfirmed':\n\t\t\t\t\tbuf += `<p>${this.tr`If you don't have an autoconfirmed account, you will need to contact a global staff member to appeal your semilock.`}</p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'appealother':\n\t\t\t\t\tbuf += `<p>${this.tr`Please PM the staff member who punished you. If you don't know who punished you, ask another room staff member; they will redirect you to the correct user. If you are banned or blacklisted from the room, use <code>/roomauth [name of room]</code> to get a list of room staff members. Bold names are online.`}</p>`;\n\t\t\t\t\tbuf += `<p><strong>${this.tr`Do not PM staff if you are locked (signified by the symbol <code>\u203D</code> in front of your username). Locks are a different type of punishment; to appeal a lock, make a help ticket by clicking the Back button and then selecting the most relevant option.`}</strong></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'misc':\n\t\t\t\t\tbuf += `<p><b>${this.tr`Maybe one of these options will be helpful?`}</b></p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>password</Button></p>`;\n\t\t\t\t\tif (user.trusted || isStaff) buf += `<p><Button>roomhelp</Button></p>`;\n\t\t\t\t\tbuf += `<p><Button>other</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'password':\n\t\t\t\t\tbuf += `<p>If you need your Pok\u00E9mon Showdown password reset, you can fill out a <a href=\"https://www.smogon.com/forums/password-reset-form/\">Password Reset Form</a>.</p>`;\n\t\t\t\t\tbuf += `<p>You will need to make a Smogon account to be able to fill out a form.`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'roomhelp':\n\t\t\t\t\tbuf += `<p>${this.tr`If you are a room driver or up in a public room, and you need help watching the chat, one or more global staff members would be happy to assist you!`}</p>`;\n\t\t\t\t\tbuf += `<p><Button>confirmroomhelp</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'other':\n\t\t\t\t\tbuf += `<p>${this.tr`If your issue is not handled above, click the button below to talk to a global staff member. Please be ready to explain the situation.`}</p>`;\n\t\t\t\t\tif (!isLast) break;\n\t\t\t\t\tbuf += `<p><Button>confirmother</Button></p>`;\n\t\t\t\t\tbreak;\n\t\t\t\tdefault:\n\t\t\t\t\tif (!page.startsWith('confirm') || !ticketTitles[page.slice(7)]) {\n\t\t\t\t\t\tbuf += `<p>${this.tr`Malformed help request.`}</p>`;\n\t\t\t\t\t\tbuf += `<a href=\"/view-help-request\" target=\"replace\"><button class=\"button\">${this.tr`Back`}</button></a>`;\n\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t\tconst type = this.tr(ticketTitles[page.slice(7)]);\n\t\t\t\t\tconst submitMeta = Utils.splitFirst(meta, '-', 2).join('|'); // change the delimiter as some ticket titles include -\n\t\t\t\t\tconst textTicket = textTickets[page.slice(7)];\n\t\t\t\t\tif (textTicket) {\n\t\t\t\t\t\tbuf += `<p><b>${this.tr(textTicket.title)}</b></p>`;\n\t\t\t\t\t\tif (textTicket.disclaimer) {\n\t\t\t\t\t\t\tbuf += `<p>${this.tr(textTicket.disclaimer)}</p>`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuf += `<form data-submitsend=\"/helpticket submit ${ticketTitles[page.slice(7)]} ${submitMeta} | {text} | {context}\">`;\n\t\t\t\t\t\tbuf += `<textarea style=\"width: 100%\" name=\"text\"></textarea><br />`;\n\t\t\t\t\t\tbuf += `<strong>${\"Do you have any other information you want to provide? (this is optional)\"}</strong>`;\n\t\t\t\t\t\tif (textTicket.contextMessage) {\n\t\t\t\t\t\t\tbuf += `<br />${textTicket.contextMessage}`;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tbuf += `<br />`;\n\t\t\t\t\t\tbuf += `<textarea style=\"width: 100%\" name=\"context\"></textarea><br />`;\n\t\t\t\t\t\tbuf += `<br /><button class=\"button notifying\" type=\"submit\">Submit ticket</button></form>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\tbuf += `<p><b>${this.tr`Are you sure you want to submit a ticket for ${type}?`}</b></p>`;\n\t\t\t\t\t\tbuf += `<p><button class=\"button notifying\" name=\"send\" value=\"/helpticket submit ${ticketTitles[page.slice(7)]} ${submitMeta}\">${this.tr`Yes, contact global staff`}</button> <a href=\"/view-help-request-${query.slice(0, i).join('-')}${meta}\" target=\"replace\">`;\n\t\t\t\t\t\tbuf += `<button class=\"button\">${this.tr`No, cancel`}</button></a></p>`;\n\t\t\t\t\t}\n\t\t\t\t\tif (textTicket || page.includes('confirmpmharassment')) {\n\t\t\t\t\t\tbuf += `<p>`;\n\t\t\t\t\t\tbuf += `Global staff might take more than a few minutes to handle your report. `;\n\t\t\t\t\t\tbuf += `If you are being disturbed by another user, we advise you to type <code>/ignore [username]</code> in a chatroom to ignore their messages.`;\n\t\t\t\t\t}\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += '</div>';\n\t\t\tconst curPageLink = query.length ? '-' + query.join('-') : '';\n\t\t\tbuf = buf.replace(\n\t\t\t\t/<Button>([a-z]+)<\\/Button>/g,\n\t\t\t\t(match, id) => (\n\t\t\t\t\t`<a class=\"button\" href=\"/view-help-request${curPageLink}-${id}${meta}\" target=\"replace\">${this.tr(ticketPages[id])}</a>`\n\t\t\t\t)\n\t\t\t);\n\t\t\treturn buf;\n\t\t},\n\t\tasync list(query, user, connection) {\n\t\t\tif (!user.named) return Rooms.RETRY_AFTER_LOGIN;\n\t\t\tthis.checkCan('lock');\n\t\t\tconst type = toID(query.shift());\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tthis.title = '[Help Tickets]';\n\t\t\tif (!type) {\n\t\t\t\tbuf += `<h2>Help Tickets</h2><hr />`;\n\t\t\t\tconst keys = Object.keys(textTickets).filter(id => textTickets[id].listOnly);\n\t\t\t\tif (!keys.length) {\n\t\t\t\t\tbuf += `<p class=\"message-error\">Currently, no ticket types support mass-view in a list.</p>`;\n\t\t\t\t\tbuf += `<p>Use <code>/ht text [username]</code> to view an individual user's ticket instead.</p>`;\n\t\t\t\t\treturn buf;\n\t\t\t\t}\n\t\t\t\tif (type && !keys.includes(type)) {\n\t\t\t\t\tbuf += `<p class=\"message-error\">That ticket type does not support mass-view in a list.</p>`;\n\t\t\t\t\tbuf += `<p>Use <code>/ht text [username]</code> to view an individual user's ticket instead.</p>`;\n\t\t\t\t\treturn buf;\n\t\t\t\t}\n\t\t\t\tbuf += `<p class=\"message-error\">Please specify a valid ticket type.</p>`;\n\t\t\t\tbuf += `<p>Valid mass-view ticket types:</p>`;\n\t\t\t\tbuf += keys.map(k => `<a class=\"button\" href=\"/view-help-list-${k}\" target=\"replace\">${k}</a>`).join(' | ');\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tthis.title += ` ${type}`;\n\t\t\tbuf += `<h2>Help Tickets (${ticketTitles[type]})</h2><hr />`;\n\t\t\tlet count = 0;\n\t\t\tfor (const k in tickets) {\n\t\t\t\tconst ticket = tickets[k];\n\t\t\t\tconst typeId = HelpTicket.getTypeId(ticket.type);\n\t\t\t\tif (!ticket.resolved && ticket.text && typeId === type) {\n\t\t\t\t\tcount++;\n\t\t\t\t\tbuf += `<strong>Reporter:</strong> ${ticket.userid}`;\n\t\t\t\t\tbuf += await textTickets[typeId].getReviewDisplay(\n\t\t\t\t\t\tticket as TicketState & { text: [string, string] },\n\t\t\t\t\t\tuser,\n\t\t\t\t\t\tthis.connection,\n\t\t\t\t\t\t{ list: true }\n\t\t\t\t\t);\n\t\t\t\t\tbuf += `<form data-submitsend=\"/helpticket resolve ${ticket.userid},{text} spoiler:{private}\">`;\n\t\t\t\t\tbuf += `<br /><strong>Resolve:</strong><br />`;\n\t\t\t\t\tbuf += `Respond to reporter: <textarea style=\"width: 100%\" name=\"text\" autocomplete=\"on\"></textarea><br />`;\n\t\t\t\t\tbuf += `Staff notes (optional): <textarea style=\"width: 100%\" name=\"private\"></textarea><br />`;\n\t\t\t\t\tbuf += `<br /><button class=\"button notifying\" type=\"submit\">Resolve ticket</button></form>`;\n\t\t\t\t\tbuf += `<hr />`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (!count) {\n\t\t\t\tbuf += `<p class=\"message-error\">No active tickets of the type '${ticketTitles[type]}' were found.</p>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\ttickets(query, user, connection) {\n\t\t\tif (!user.named) return Rooms.RETRY_AFTER_LOGIN;\n\t\t\tthis.title = this.tr`Ticket List`;\n\t\t\tthis.checkCan('lock');\n\t\t\tlet buf = `<div class=\"pad ladder\"><button class=\"button\" name=\"send\" value=\"/helpticket list\" style=\"float:left\"><i class=\"fa fa-refresh\"></i> ${this.tr`Refresh`}</button> <button class=\"button\" name=\"send\" value=\"/helpticket stats\" style=\"float: right\"><i class=\"fa fa-th-list\"></i> ${this.tr`Help Ticket Stats`}</button><br /><br />`;\n\t\t\tbuf += `<table style=\"margin-left: auto; margin-right: auto\"><tbody><tr><th colspan=\"5\"><h2 style=\"margin: 5px auto\">${this.tr`Help tickets`}</h1></th></tr>`;\n\t\t\tbuf += `<tr><th>${this.tr`Status`}</th><th>${this.tr`Creator`}</th><th>${this.tr`Ticket Type`}</th><th>${this.tr`Claimed by`}</th><th>${this.tr`Action`}</th></tr>`;\n\n\t\t\tconst sortedTickets = HelpTicket.list(ticket => [\n\t\t\t\tticket.open,\n\t\t\t\tticket.open ? [ticket.active, ticket.created] : -ticket.created,\n\t\t\t]);\n\t\t\tlet count = 0;\n\t\t\tfor (const ticket of sortedTickets) {\n\t\t\t\tif (count >= 100 && query[0] !== 'all') {\n\t\t\t\t\tbuf += `<tr><td colspan=\"5\">${this.tr`And ${sortedTickets.length - count} more tickets.`} <a class=\"button\" href=\"/view-help-tickets-all\" target=\"replace\">${this.tr`View all tickets`}</a></td></tr>`;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tlet icon = `<span style=\"color:gray\"><i class=\"fa fa-check-circle-o\"></i> ${this.tr`Closed`}</span>`;\n\t\t\t\tif (ticket.open) {\n\t\t\t\t\tif (!ticket.active && !ticket.text) {\n\t\t\t\t\t\ticon = `<span style=\"color:gray\"><i class=\"fa fa-circle-o\"></i> ${this.tr`Inactive`}</span>`;\n\t\t\t\t\t} else if (ticket.claimed) {\n\t\t\t\t\t\ticon = `<span style=\"color:green\"><i class=\"fa fa-circle-o\"></i> ${this.tr`Claimed`}</span>`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\ticon = `<span style=\"color:orange\"><i class=\"fa fa-circle-o\"></i> <strong>${this.tr`Unclaimed`}</strong></span>`;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tbuf += `<tr><td>${icon}</td>`;\n\t\t\t\tbuf += `<td>${Utils.escapeHTML(ticket.creator)}</td>`;\n\t\t\t\tbuf += `<td>${ticket.type}</td>`;\n\t\t\t\tbuf += Utils.html`<td>${ticket.claimed ? ticket.claimed : `-`}</td>`;\n\t\t\t\tbuf += `<td>`;\n\t\t\t\tconst roomid = 'help-' + ticket.userid;\n\t\t\t\tlet logUrl = '';\n\t\t\t\tconst created = new Date(ticket.created);\n\t\t\t\tif (ticket.text) {\n\t\t\t\t\tlogUrl = `/view-help-logs-${ticket.userid}--${Chat.toTimestamp(created).split(' ')[0].slice(0, -3)}`;\n\t\t\t\t} else {\n\t\t\t\t\tlogUrl = `/view-chatlog-help-${ticket.userid}--${Chat.toTimestamp(created).split(' ')[0]}`;\n\t\t\t\t}\n\t\t\t\tconst room = Rooms.get(roomid);\n\t\t\t\tif (ticket.text) {\n\t\t\t\t\tlet title = Object.entries(ticket.notes || {})\n\t\t\t\t\t\t.map(([userid, note]) => Utils.html`${note} (by ${userid})`)\n\t\t\t\t\t\t.join('&#10;');\n\t\t\t\t\tif (title) {\n\t\t\t\t\t\ttitle = `title=\"Staff notes:&#10;${title}\"`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `<a class=\"button\" ${title} href=\"/view-help-text-${ticket.userid}\">${ticket.claimed ? `Claim` : `View`}</a>`;\n\t\t\t\t} else if (room) {\n\t\t\t\t\tconst ticketGame = room.getGame(HelpTicket)!;\n\t\t\t\t\tbuf += `<a href=\"/${roomid}\"><button class=\"button\" ${ticketGame.getPreview()}>${this.tr(!ticket.claimed && ticket.open ? 'Claim' : 'View')}</button></a> `;\n\t\t\t\t}\n\t\t\t\tif (logUrl) {\n\t\t\t\t\tbuf += `<a href=\"${logUrl}\"><button class=\"button\">${this.tr`Log`}</button></a>`;\n\t\t\t\t}\n\t\t\t\tbuf += '</td></tr>';\n\t\t\t\tcount++;\n\t\t\t}\n\t\t\tbuf += `</div></table><div class=\"ladder pad\">`;\n\t\t\tbuf += `<table style=\"margin-left: auto; margin-right: auto\"><tbody>`;\n\t\t\tbuf += `<tr><th colspan=\"5\"><h2 style=\"margin: 5px auto\">${this.tr`Ticket Bans`}<i class=\"fa fa-ban\"></i></h2></th></tr>`;\n\t\t\tbuf += `<tr><th>Userids</th><th>IPs</th><th>Expires</th><th>Reason</th></tr>`;\n\t\t\tconst ticketBans = Utils.sortBy(\n\t\t\t\t[...Punishments.getPunishments()].filter(([id, entry]) => entry.punishType === 'TICKETBAN'),\n\t\t\t\t([id, entry]) => entry.expireTime\n\t\t\t);\n\t\t\tfor (const [userid, entry] of ticketBans) {\n\t\t\t\tlet ids = [userid];\n\t\t\t\tif (entry.userids) ids = ids.concat(entry.userids);\n\t\t\t\tbuf += `<tr><td>${ids.map(Utils.escapeHTML).join(', ')}</td>`;\n\t\t\t\tbuf += `<td>${entry.ips.join(', ')}</td>`;\n\t\t\t\tbuf += `<td>${Chat.toDurationString(entry.expireTime - Date.now(), { precision: 1 })}</td>`;\n\t\t\t\tbuf += `<td>${entry.reason || ''}</td></tr>`;\n\t\t\t}\n\t\t\tbuf += `</tbody></table></div>`;\n\t\t\treturn buf;\n\t\t},\n\t\tasync text(query, user, connection) {\n\t\t\tif (!user.named) return Rooms.RETRY_AFTER_LOGIN;\n\t\t\tthis.title = this.tr`Queued Tickets`;\n\t\t\tthis.checkCan('lock');\n\t\t\tconst userid = query.shift();\n\t\t\tif (!userid) {\n\t\t\t\treturn this.errorReply(`Specify a userid to view the ticket for.`);\n\t\t\t}\n\t\t\tconst ticket = tickets[toID(userid)];\n\t\t\tif (!ticket) {\n\t\t\t\treturn this.errorReply(`Ticket not found.`);\n\t\t\t}\n\t\t\tif (!ticket.text) {\n\t\t\t\treturn this.errorReply(`That is either not a text ticket, or it has not yet been submitted.`);\n\t\t\t}\n\t\t\tconst ticketInfo = textTickets[HelpTicket.getTypeId(ticket.type)];\n\t\t\tthis.title = `[Text Ticket] ${ticket.userid}`;\n\t\t\tlet buf = `<div class=\"pad\">`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/join ${this.pageid}\" style=\"float:right\"><i class=\"fa fa-refresh\"></i> ${this.tr`Refresh`}</button>`;\n\t\t\tbuf += `<h2>Issue: ${ticket.type}</h2>`;\n\t\t\tif (!ticket.claimed && ticket.open) {\n\t\t\t\tticket.claimed = user.id;\n\t\t\t\tif (!ticket.state) ticket.state = {};\n\t\t\t\tticket.state.claimTime = Date.now();\n\t\t\t\twriteTickets();\n\t\t\t\tnotifyStaff();\n\t\t\t\tChat.refreshPageFor(`help-text-${ticket.userid}`, 'staff', false, [user.id]);\n\t\t\t} else if (ticket.claimed) {\n\t\t\t\tbuf += `<strong>Claimed:</strong> ${ticket.claimed}<br /><br />`;\n\t\t\t}\n\t\t\tbuf += `<strong>From: <a href=\"https://${Config.routes.root}/users/${ticket.userid}\">`;\n\t\t\tbuf += `${ticket.userid}</a></strong>`;\n\t\t\tbuf += ` <button class=\"button\" name=\"send\" value=\"/msgroom staff,/ht ban ${ticket.userid}\">Ticketban</button> | `;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${ticket.userid}'\">Global Modlog</button><br />`;\n\t\t\tbuf += await ticketInfo.getReviewDisplay(ticket as TicketState & { text: [string, string] }, user, connection);\n\t\t\tbuf += `<br />`;\n\t\t\tbuf += `<div class=\"infobox\">`;\n\t\t\tconst [text, context] = ticket.text;\n\t\t\tbuf += `<p><strong>Report text:</strong></p><hr />`;\n\t\t\tbuf += Chat.formatText(text);\n\t\t\tif (context) {\n\t\t\t\tbuf += `<br /><hr /><strong>Context given: </strong><br />${context}`;\n\t\t\t}\n\t\t\tbuf += `</div>`;\n\n\t\t\tif (ticket.notes) {\n\t\t\t\tbuf += `<br /><div class=\"infobox\">`;\n\t\t\t\tbuf += `<details class=\"readmore\"><summary>Hover notes:</summary>`;\n\t\t\t\tfor (const staff in ticket.notes) {\n\t\t\t\t\tbuf += Utils.html`<p>${ticket.notes[staff]} (by ${staff})</p>`;\n\t\t\t\t}\n\t\t\t\tbuf += `<br /><form data-submitsend=\"/ht addnote ${ticket.userid},{note}&#10;/j view-help-text-${ticket.userid}\">`;\n\t\t\t\tbuf += `Add note: <input name=\"note\" /> <button type=\"submit\" class=\"button\">Submit</button>`;\n\t\t\t\tbuf += `</form>`;\n\t\t\t\tbuf += `</details></div>`;\n\t\t\t} else {\n\t\t\t\tbuf += `<br /><div class=\"infobox\">`;\n\t\t\t\tbuf += `<form data-submitsend=\"/ht note ${ticket.userid},{note}&#10;/j view-help-text-${ticket.userid}\">`;\n\t\t\t\tbuf += `Add note: <input name=\"note\" /> <button type=\"submit\" class=\"button\">Submit</button>`;\n\t\t\t\tbuf += `</form></div>`;\n\t\t\t}\n\n\t\t\tif (!ticket.resolved) {\n\t\t\t\tconst typeId = HelpTicket.getTypeId(ticket.type);\n\t\t\t\tconst responses = settings.responses[typeId];\n\t\t\t\tif (Object.keys(responses || {}).length) {\n\t\t\t\t\tbuf += `<br /><div class=\"infobox\">`;\n\t\t\t\t\tbuf += `<details class=\"readmore\"><summary><strong>Responses</strong></summary>`;\n\t\t\t\t\tconst responseKeys = Object.keys(responses);\n\t\t\t\t\tfor (const [i, name] of responseKeys.entries()) {\n\t\t\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/helpticket resolve ${ticket.userid},${responses[name]}\">${name}</button>`;\n\t\t\t\t\t\tif (responseKeys[i + 1]) buf += `<br />`;\n\t\t\t\t\t}\n\t\t\t\t\tbuf += `</details></div><br />`;\n\t\t\t\t}\n\t\t\t\tbuf += `<form data-submitsend=\"/helpticket resolve ${ticket.userid},{text} spoiler:{private}\">`;\n\t\t\t\tbuf += `<br /><strong>Resolve:</strong><br />`;\n\t\t\t\tbuf += `Respond to reporter: <textarea style=\"width: 100%\" name=\"text\" autocomplete=\"on\"></textarea><br />`;\n\t\t\t\tbuf += `Staff notes (optional): <textarea style=\"width: 100%\" name=\"private\"></textarea><br />`;\n\t\t\t\tbuf += `<br /><button class=\"button notifying\" type=\"submit\">Resolve ticket</button></form>`;\n\t\t\t} else {\n\t\t\t\tbuf += Utils.html`<strong>Resolved: by ${ticket.resolved.by}</strong><br />`;\n\t\t\t\tbuf += Utils.html`<strong>Result:</strong> ${Chat.collapseLineBreaksHTML(ticket.resolved.result)}<br />`;\n\t\t\t\tif (ticket.resolved.staffReason.includes('PROOF')) { // a note was added, show it\n\t\t\t\t\tbuf += Utils.html`<strong>Resolver notes:</strong> ${Chat.collapseLineBreaksHTML(ticket.resolved.staffReason)}<br />`;\n\t\t\t\t}\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\tasync logs(query, user, connection) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst args = query.join('-').split('--');\n\t\t\tconst userid = toID(args.shift());\n\t\t\tif (!userid) return this.errorReply(`Specify a userid to view ticket logs for.`);\n\t\t\tconst date = args.shift();\n\t\t\tif (date) {\n\t\t\t\tconst parsed = new Date(date);\n\t\t\t\tif (!/[0-9]{4}-[0-9]{2}/.test(date) || isNaN(parsed.getTime())) {\n\t\t\t\t\treturn this.errorReply(`Invalid date.`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst logs = await HelpTicket.getTextLogs(['userid', userid], date);\n\t\t\tthis.title = `[Ticket Logs] ${userid}${date ? ` (${date})` : ''}`;\n\t\t\tlet buf = `<div class=\"pad\"><h2>Ticket logs for ${userid}${date ? ` in the month of ${date}` : ''}</h2>`;\n\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/join ${this.pageid}\"><i class=\"fa fa-refresh\"></i> ${this.tr`Refresh`}</button>`;\n\t\t\tbuf += `<hr />`;\n\n\t\t\tif (!logs.length) {\n\t\t\t\tbuf += `<div class=\"message-error\">None found.</div>`;\n\t\t\t\treturn buf;\n\t\t\t}\n\t\t\tconst stringifyDate = (num: number) => {\n\t\t\t\tconst dateStrings = Chat.toTimestamp(new Date(num), { human: true }).split(' ');\n\t\t\t\treturn { day: dateStrings[0], time: dateStrings[1] };\n\t\t\t};\n\n\t\t\tUtils.sortBy(logs, log => -log.resolved.time);\n\n\t\t\tfor (const ticket of logs) {\n\t\t\t\tbuf += `<details class=\"readmore\"><summary>`;\n\t\t\t\tconst curDate = stringifyDate(ticket.created);\n\t\t\t\tbuf += `<strong>${ticket.type} - ${curDate.day} (${curDate.time})</strong></summary>`;\n\t\t\t\tconst ticketInfo = textTickets[HelpTicket.getTypeId(ticket.type)];\n\t\t\t\tthis.title = `[Text Ticket] ${ticket.userid}`;\n\t\t\t\tbuf += `<h2>Issue: ${ticket.type}</h2>`;\n\t\t\t\tbuf += `<strong>From: ${ticket.userid}</strong>`;\n\t\t\t\tbuf += ` <button class=\"button\" name=\"send\" value=\"/msgroom staff,/ht ban ${ticket.userid}\">Ticketban</button> | `;\n\t\t\t\tbuf += `<button class=\"button\" name=\"send\" value=\"/modlog room=global,user='${ticket.userid}'\">Global Modlog</button><br />`;\n\t\t\t\tif (ticket.claimed) {\n\t\t\t\t\tbuf += `<br /><strong>Claimed:</strong> ${ticket.claimed}<br />`;\n\t\t\t\t}\n\t\t\t\tbuf += await ticketInfo.getReviewDisplay(\n\t\t\t\t\tticket as TicketState & { text: [string, string] },\n\t\t\t\t\tuser,\n\t\t\t\t\tconnection,\n\t\t\t\t\tticket.state\n\t\t\t\t);\n\t\t\t\tbuf += `<br />`;\n\t\t\t\tbuf += `<div class=\"infobox\">`;\n\t\t\t\tconst [text, context] = ticket.text;\n\t\t\t\tbuf += `<p><strong>Report text:</strong></p><hr />`;\n\t\t\t\tbuf += Chat.formatText(text);\n\t\t\t\tif (context) {\n\t\t\t\t\tbuf += `<br /><hr /><strong>Context given: </strong><br />`;\n\t\t\t\t\t// gotta account for the cases where we didn't escape html in context on submit\n\t\t\t\t\t// If it includes <br />, it has been escaped and has several lines.\n\t\t\t\t\t// If we can strip raw html out of it, it should be escaped.\n\t\t\t\t\t// Otherwise, let it be.\n\t\t\t\t\tconst noEscape = !context.includes('<br />') ? Chat.stripHTML(context) !== context : false;\n\t\t\t\t\tbuf += noEscape ? Chat.formatText(context) : context;\n\t\t\t\t}\n\t\t\t\tbuf += `</div>`;\n\t\t\t\tbuf += Utils.html`<strong>Resolved: by ${ticket.resolved.by}</strong><br />`;\n\t\t\t\tbuf += Utils.html`<strong>Result:</strong> ${Chat.collapseLineBreaksHTML(ticket.resolved.result)}<br />`;\n\t\t\t\tif (ticket.resolved.staffReason.includes('PROOF')) { // a note was added, show it\n\t\t\t\t\tbuf += Utils.html`<strong>Resolver notes:</strong> ${Chat.collapseLineBreaksHTML(ticket.resolved.staffReason)}<br />`;\n\t\t\t\t}\n\t\t\t\tbuf += `</details><hr />`;\n\t\t\t}\n\t\t\treturn buf;\n\t\t},\n\t\tstats(query, user, connection) {\n\t\t\t// view-help-stats-TABLE-YYYY-MM-COL\n\t\t\tif (!user.named) return Rooms.RETRY_AFTER_LOGIN;\n\t\t\tthis.title = this.tr`Ticket Stats`;\n\t\t\tthis.checkCan('lock');\n\n\t\t\tlet [table, yearString, monthString, col] = query;\n\t\t\tif (!['staff', 'tickets'].includes(table)) table = 'tickets';\n\t\t\tconst year = parseInt(yearString);\n\t\t\tconst month = parseInt(monthString) - 1;\n\t\t\tlet date = null;\n\t\t\tif (isNaN(year) || isNaN(month) || month < 0 || month > 11 || year < 2010) {\n\t\t\t\t// year/month not provided or is invalid, use current date\n\t\t\t\tdate = new Date();\n\t\t\t} else {\n\t\t\t\tdate = new Date(year, month);\n\t\t\t}\n\t\t\tconst dateUrl = Chat.toTimestamp(date).split(' ')[0].split('-', 2).join('-');\n\n\t\t\tconst rawTicketStats = Monitor.logPath(`tickets/${dateUrl}.tsv`).readIfExistsSync();\n\t\t\tif (!rawTicketStats) return `<div class=\"pad\"><br />${this.tr`No ticket stats found.`}</div>`;\n\n\t\t\t// Calculate next/previous month for stats and validate stats exist for the month\n\n\t\t\t// date.getMonth() returns 0-11, we need 1-12 +/-1 for this\n\t\t\tconst prevDate = new Date(\n\t\t\t\tdate.getMonth() === 0 ?\n\t\t\t\t\tdate.getFullYear() - 1 :\n\t\t\t\t\tdate.getFullYear(),\n\t\t\t\tdate.getMonth() === 0 ?\n\t\t\t\t\t11 :\n\t\t\t\t\tdate.getMonth() - 1\n\t\t\t);\n\t\t\tconst nextDate = new Date(\n\t\t\t\tdate.getMonth() === 11 ?\n\t\t\t\t\tdate.getFullYear() + 1 :\n\t\t\t\t\tdate.getFullYear(),\n\t\t\t\tdate.getMonth() === 11 ?\n\t\t\t\t\t0 :\n\t\t\t\t\tdate.getMonth() + 1\n\t\t\t);\n\t\t\tconst prevString = Chat.toTimestamp(prevDate).split(' ')[0].split('-', 2).join('-');\n\t\t\tconst nextString = Chat.toTimestamp(nextDate).split(' ')[0].split('-', 2).join('-');\n\n\t\t\tlet buttonBar = '';\n\t\t\tif (Monitor.logPath(`tickets/${prevString}.tsv`).readIfExistsSync()) {\n\t\t\t\tbuttonBar += `<a class=\"button\" href=\"/view-help-stats-${table}-${prevString}\" target=\"replace\" style=\"float: left\">&lt; ${this.tr`Previous Month`}</a>`;\n\t\t\t} else {\n\t\t\t\tbuttonBar += `<a class=\"button disabled\" style=\"float: left\">&lt; ${this.tr`Previous Month`}</a>`;\n\t\t\t}\n\t\t\tbuttonBar += `<a class=\"button${table === 'tickets' ? ' disabled\"' : `\" href=\"/view-help-stats-tickets-${dateUrl}\" target=\"replace\"`}>${this.tr`Ticket Stats`}</a> <a class=\"button ${table === 'staff' ? ' disabled\"' : `\" href=\"/view-help-stats-staff-${dateUrl}\" target=\"replace\"`}>${this.tr`Staff Stats`}</a>`;\n\t\t\tif (Monitor.logPath(`tickets/${nextString}.tsv`).readIfExistsSync()) {\n\t\t\t\tbuttonBar += `<a class=\"button\" href=\"/view-help-stats-${table}-${nextString}\" target=\"replace\" style=\"float: right\">${this.tr`Next Month`} &gt;</a>`;\n\t\t\t} else {\n\t\t\t\tbuttonBar += `<a class=\"button disabled\" style=\"float: right\">${this.tr`Next Month`} &gt;</a>`;\n\t\t\t}\n\n\t\t\tlet buf = `<div class=\"pad ladder\"><div style=\"text-align: center\">${buttonBar}</div><br />`;\n\t\t\tbuf += `<table style=\"margin-left: auto; margin-right: auto\"><tbody><tr><th colspan=\"${table === 'tickets' ? 7 : 3}\"><h2 style=\"margin: 5px auto\">${this.tr`Help Ticket Stats`} - ${date.toLocaleString('en-us', { month: 'long', year: 'numeric' })}</h1></th></tr>`;\n\t\t\tif (table === 'tickets') {\n\t\t\t\tif (!['type', 'totaltickets', 'total', 'initwait', 'wait', 'resolution', 'result'].includes(col)) col = 'type';\n\t\t\t\tbuf += `<tr><th><Button>type</Button></th><th><Button>totaltickets</Button></th><th><Button>total</Button></th><th><Button>initwait</Button></th><th><Button>wait</Button></th><th><Button>resolution</Button></th><th><Button>result</Button></th></tr>`;\n\t\t\t} else {\n\t\t\t\tif (!['staff', 'num', 'time'].includes(col)) col = 'num';\n\t\t\t\tbuf += `<tr><th><Button>staff</Button></th><th><Button>num</Button></th><th><Button>time</Button></th></tr>`;\n\t\t\t}\n\n\t\t\tconst ticketStats: { [k: string]: string }[] = rawTicketStats.split('\\n').filter(\n\t\t\t\t(line: string) => line\n\t\t\t).map(\n\t\t\t\t(line: string) => {\n\t\t\t\t\tconst splitLine = line.split('\\t');\n\t\t\t\t\treturn {\n\t\t\t\t\t\ttype: splitLine[0],\n\t\t\t\t\t\ttotal: splitLine[1],\n\t\t\t\t\t\tinitwait: splitLine[2],\n\t\t\t\t\t\twait: splitLine[3],\n\t\t\t\t\t\tresolution: splitLine[4],\n\t\t\t\t\t\tresult: splitLine[5],\n\t\t\t\t\t\tstaff: splitLine[6],\n\t\t\t\t\t};\n\t\t\t\t}\n\t\t\t);\n\t\t\tif (table === 'tickets') {\n\t\t\t\tconst typeStats: { [key: string]: { [key: string]: number } } = {};\n\t\t\t\tfor (const stats of ticketStats) {\n\t\t\t\t\tif (!typeStats[stats.type]) {\n\t\t\t\t\t\ttypeStats[stats.type] = {\n\t\t\t\t\t\t\ttotal: 0,\n\t\t\t\t\t\t\tinitwait: 0,\n\t\t\t\t\t\t\twait: 0,\n\t\t\t\t\t\t\tdead: 0,\n\t\t\t\t\t\t\tunresolved: 0,\n\t\t\t\t\t\t\tresolved: 0,\n\t\t\t\t\t\t\tresult: 0,\n\t\t\t\t\t\t\ttotaltickets: 0,\n\t\t\t\t\t\t};\n\t\t\t\t\t}\n\t\t\t\t\tconst type = typeStats[stats.type];\n\t\t\t\t\ttype.totaltickets++;\n\t\t\t\t\ttype.total += parseInt(stats.total);\n\t\t\t\t\ttype.initwait += parseInt(stats.initwait);\n\t\t\t\t\ttype.wait += parseInt(stats.wait);\n\t\t\t\t\tif (['approved', 'valid', 'assisted'].includes(stats.result.toString())) type.result++;\n\t\t\t\t\tif (['dead', 'unresolved', 'resolved'].includes(stats.resolution.toString())) {\n\t\t\t\t\t\ttype[stats.resolution.toString()]++;\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\t// Calculate averages/percentages\n\t\t\t\tfor (const t in typeStats) {\n\t\t\t\t\tconst type = typeStats[t];\n\t\t\t\t\t// Averages\n\t\t\t\t\tfor (const key of ['total', 'initwait', 'wait']) {\n\t\t\t\t\t\ttype[key] = Math.round(type[key] / type.totaltickets);\n\t\t\t\t\t}\n\t\t\t\t\t// Percentages\n\t\t\t\t\tfor (const key of ['result', 'dead', 'unresolved', 'resolved']) {\n\t\t\t\t\t\ttype[key] = Math.round((type[key] / type.totaltickets) * 100);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tconst sortedStats = Utils.sortBy(Object.keys(typeStats), t => {\n\t\t\t\t\tif (col === 'type') {\n\t\t\t\t\t\t// Alphabetize strings\n\t\t\t\t\t\treturn t;\n\t\t\t\t\t} else if (col === 'resolution') {\n\t\t\t\t\t\treturn -(typeStats[t].resolved || 0);\n\t\t\t\t\t}\n\t\t\t\t\treturn -typeStats[t][col];\n\t\t\t\t});\n\n\t\t\t\tfor (const type of sortedStats) {\n\t\t\t\t\tconst resolution = `${this.tr`Resolved`}: ${typeStats[type].resolved}%<br/>${this.tr`Unresolved`}: ${typeStats[type].unresolved}%<br/>${this.tr`Dead`}: ${typeStats[type].dead}%`;\n\t\t\t\t\tbuf += `<tr><td>${type}</td><td>${typeStats[type].totaltickets}</td><td>${Chat.toDurationString(typeStats[type].total, { hhmmss: true })}</td><td>${Chat.toDurationString(typeStats[type].initwait, { hhmmss: true }) || '-'}</td><td>${Chat.toDurationString(typeStats[type].wait, { hhmmss: true }) || '-'}</td><td>${resolution}</td><td>${typeStats[type].result}%</td></tr>`;\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tconst staffStats: { [key: string]: { [key: string]: number } } = {};\n\t\t\t\tfor (const stats of ticketStats) {\n\t\t\t\t\tconst staffArray = (typeof stats.staff === 'string' ? stats.staff.split(',') : []);\n\t\t\t\t\tfor (const staff of staffArray) {\n\t\t\t\t\t\tif (!staff) continue;\n\t\t\t\t\t\tif (!staffStats[staff]) staffStats[staff] = { num: 0, time: 0 };\n\t\t\t\t\t\tstaffStats[staff].num++;\n\t\t\t\t\t\tstaffStats[staff].time += (parseInt(stats.total) - parseInt(stats.initwait));\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tfor (const staff in staffStats) {\n\t\t\t\t\tstaffStats[staff].time = Math.round(staffStats[staff].time / staffStats[staff].num);\n\t\t\t\t}\n\t\t\t\tconst sortedStaff = Utils.sortBy(Object.keys(staffStats), staff => {\n\t\t\t\t\tif (col === 'staff') {\n\t\t\t\t\t\t// Alphabetize strings\n\t\t\t\t\t\treturn staff;\n\t\t\t\t\t}\n\t\t\t\t\treturn -staffStats[staff][col];\n\t\t\t\t});\n\t\t\t\tfor (const staff of sortedStaff) {\n\t\t\t\t\tbuf += `<tr><td>${staff}</td><td>${staffStats[staff].num}</td><td>${Chat.toDurationString(staffStats[staff].time, { precision: 1 })}</td></tr>`;\n\t\t\t\t}\n\t\t\t}\n\t\t\tbuf += `</tbody></table></div>`;\n\t\t\tconst headerTitles: { [id: string]: string } = {\n\t\t\t\ttype: 'Type',\n\t\t\t\ttotaltickets: 'Total Tickets',\n\t\t\t\ttotal: 'Average Total Time',\n\t\t\t\tinitwait: 'Average Initial Wait',\n\t\t\t\twait: 'Average Total Wait',\n\t\t\t\tresolution: 'Resolutions',\n\t\t\t\tresult: 'Positive Result',\n\t\t\t\tstaff: 'Staff ID',\n\t\t\t\tnum: 'Number of Tickets',\n\t\t\t\ttime: 'Average Time Per Ticket',\n\t\t\t};\n\t\t\tbuf = buf.replace(/<Button>([a-z]+)<\\/Button>/g, (match, id) => {\n\t\t\t\tif (col === id) return this.tr(headerTitles[id]);\n\t\t\t\treturn `<a class=\"button\" href=\"/view-help-stats-${table}-${dateUrl}-${id}\" target=\"replace\">${this.tr(headerTitles[id])}</a>`;\n\t\t\t});\n\t\t\treturn buf;\n\t\t},\n\t},\n};\n\nexport const commands: Chat.ChatCommands = {\n\treport(target, room, user) {\n\t\tif (!this.runBroadcast()) return;\n\t\tconst meta = this.pmTarget ? `-user-${this.pmTarget.id}` : this.room ? `-room-${this.room.roomid}` : '';\n\t\tif (this.broadcasting) {\n\t\t\treturn this.sendReplyBox(`<button name=\"joinRoom\" value=\"view-help-request--report${meta}\" class=\"button\"><strong>${this.tr`Report someone`}</strong></button>`);\n\t\t}\n\n\t\treturn this.parse(`/join view-help-request--report${meta}`);\n\t},\n\n\tappeal(target, room, user) {\n\t\tif (!this.runBroadcast()) return;\n\t\tconst meta = this.pmTarget ? `-user-${this.pmTarget.id}` : this.room ? `-room-${this.room.roomid}` : '';\n\t\tif (this.broadcasting) {\n\t\t\treturn this.sendReplyBox(`<button name=\"joinRoom\" value=\"view-help-request--appeal${meta}\" class=\"button\"><strong>${this.tr`Appeal a punishment`}</strong></button>`);\n\t\t}\n\n\t\treturn this.parse(`/join view-help-request--appeal${meta}`);\n\t},\n\n\trequesthelp: 'helpticket',\n\thelprequest: 'helpticket',\n\tht: 'helpticket',\n\thelpticket: {\n\t\t'': 'create',\n\t\tcreate(target, room, user) {\n\t\t\tif (!this.runBroadcast()) return;\n\t\t\tconst meta = this.pmTarget ? `-user-${this.pmTarget.id}` : this.room ? `-room-${this.room.roomid}` : '';\n\t\t\tif (this.broadcasting) {\n\t\t\t\treturn this.sendReplyBox(`<button name=\"joinRoom\" value=\"view-help-request${meta}\" class=\"button\"><strong>${this.tr`Request help`}</strong></button>`);\n\t\t\t}\n\t\t\tif (user.can('lock')) {\n\t\t\t\treturn this.parse('/join view-help-request'); // Globals automatically get the form for reference.\n\t\t\t}\n\t\t\tif (!user.named) return this.errorReply(this.tr`You need to choose a username before doing this.`);\n\t\t\treturn this.parse(`/join view-help-request${meta}`);\n\t\t},\n\t\tcreatehelp: [`/helpticket create - Creates a new ticket requesting help from global staff.`],\n\n\t\tsubmittext: 'submit',\n\t\tasync submit(target, room, user, connection, cmd) {\n\t\t\tif (user.can('lock') && !user.can('bypassall')) {\n\t\t\t\treturn this.popupReply(this.tr`Global staff can't make tickets. They can only use the form for reference.`);\n\t\t\t}\n\t\t\tif (!user.named) return this.popupReply(this.tr`You need to choose a username before doing this.`);\n\t\t\tconst ticketBan = Punishments.isTicketBanned(user);\n\t\t\tif (ticketBan) {\n\t\t\t\treturn this.popupReply(HelpTicket.getBanMessage(user.id, ticketBan));\n\t\t\t}\n\t\t\tlet ticket = tickets[user.id];\n\t\t\tconst ipTicket = checkIp(user.latestIp);\n\t\t\tif (ticket?.open || ipTicket) {\n\t\t\t\tif (!ticket && ipTicket) ticket = ipTicket;\n\t\t\t\tif (ticket.text) {\n\t\t\t\t\treturn this.popupReply(`You already have a pending ticket, please wait.`);\n\t\t\t\t}\n\t\t\t\tconst helpRoom = Rooms.get(`help-${ticket.userid}`);\n\t\t\t\tif (!helpRoom) {\n\t\t\t\t\tticket.open = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\thelpRoom.auth.set(user.id, '+');\n\t\t\t\tthis.popupReply(`You already have a pending ticket, please wait.`);\n\t\t\t\treturn this.parse(`/join help-${ticket.userid}`);\n\t\t\t}\n\t\t\tif (Monitor.countTickets(user.latestIp)) {\n\t\t\t\tconst maxTickets = Punishments.isSharedIp(user.latestIp) ? `50` : `5`;\n\t\t\t\treturn this.popupReply(this.tr`Due to high load, you are limited to creating ${maxTickets} tickets every hour.`);\n\t\t\t}\n\t\t\tlet [\n\t\t\t\tticketType, reportTargetType, reportTarget, text, contextString,\n\t\t\t] = Utils.splitFirst(target, '|', 4).map(s => s.trim());\n\t\t\treportTarget = Utils.escapeHTML(reportTarget);\n\t\t\tif (!Object.values(ticketTitles).includes(ticketType)) return this.parse('/helpticket');\n\t\t\tconst contexts: { [k: string]: string } = {\n\t\t\t\t'PM Harassment': `Hi! Who was harassing you in private messages?`,\n\t\t\t\t'Battle Harassment': `Hi! Who was harassing you, and in which battle did it happen? Please post a link to the battle or a replay of the battle.`,\n\t\t\t\t'Inappropriate Username': `Hi! Tell us the username that is inappropriate.`,\n\t\t\t\t'Inappropriate Pokemon Nicknames': `Hi! Which user has Pokemon with inappropriate nicknames, and in which battle? Please post a link to the battle or a replay of the battle.`,\n\t\t\t\tAppeal: `Hi! Can you please explain why you feel your punishment is undeserved?`,\n\t\t\t\t'IP-Appeal': `Hi! How are you connecting to Showdown right now? At home, at school, on a phone using mobile data, or some other way?`,\n\t\t\t\t'Public Room Assistance Request': `Hi! Which room(s) do you need us to help you watch?`,\n\t\t\t\tOther: `Hi! What seems to be the problem? Tell us about any people involved,` +\n\t\t\t\t\t` and if this happened in a specific place on the site.`,\n\t\t\t};\n\t\t\tconst staffContexts: { [k: string]: string } = {\n\t\t\t\t'IP-Appeal': `<p><strong>${user.name}'s IP Addresses</strong>: ${user.ips.map(ip => `<a href=\"https://whatismyipaddress.com/ip/${ip}\" target=\"_blank\">${ip}</a>`).join(', ')}</p>`,\n\t\t\t};\n\t\t\tticket = {\n\t\t\t\tcreator: user.name,\n\t\t\t\tuserid: user.id,\n\t\t\t\topen: true,\n\t\t\t\tactive: !contexts[ticketType],\n\t\t\t\ttype: ticketType,\n\t\t\t\tcreated: Date.now(),\n\t\t\t\tclaimed: null,\n\t\t\t\tip: user.latestIp,\n\t\t\t};\n\n\t\t\tif (toID(reportTarget)) {\n\t\t\t\tticket.meta = `${reportTargetType}-${reportTarget}`;\n\t\t\t}\n\t\t\tconst typeId = HelpTicket.getTypeId(ticketType);\n\t\t\tconst textTicket = textTickets[typeId];\n\t\t\tif (textTicket) {\n\t\t\t\tlet pageId = '';\n\t\t\t\tfor (const page of connection.openPages || new Set()) {\n\t\t\t\t\tif (page.includes('confirm' + typeId)) {\n\t\t\t\t\t\tpageId = page;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (!toID(text)) {\n\t\t\t\t\tthis.parse(`/join view-${pageId}`);\n\t\t\t\t\treturn this.popupReply(`Please tell us what is happening.`);\n\t\t\t\t}\n\t\t\t\ttext = text.replace(/\\n/ig, ' ');\n\t\t\t\tcontextString = contextString.split('\\n').map(t => Chat.formatText(t)).join('<br />');\n\t\t\t\tif (text.length > 8192) {\n\t\t\t\t\treturn this.popupReply(`Your report is too long. Please use fewer words.`);\n\t\t\t\t}\n\t\t\t\tconst validation = await textTicket.checker?.(text, contextString || '', ticket.type, user, reportTarget);\n\t\t\t\tif (Array.isArray(validation) && validation.length) {\n\t\t\t\t\tthis.parse(`/join view-${pageId}`);\n\t\t\t\t\treturn this.popupReply(`|html|` + validation.join('<br />'));\n\t\t\t\t}\n\t\t\t\tticket.text = [text, contextString];\n\t\t\t\tticket.active = true;\n\t\t\t\tChat.runHandlers('onTicketCreate', ticket, user);\n\t\t\t\t// eslint-disable-next-line require-atomic-updates\n\t\t\t\ttickets[user.id] = ticket;\n\t\t\t\tawait HelpTicket.modlog({\n\t\t\t\t\taction: 'TEXTTICKET OPEN',\n\t\t\t\t\tloggedBy: user.id,\n\t\t\t\t\tnote: `(${ticket.type}) ${text.replace(/<br \\/>/ig, ' | ')}${contextString ? `, context: ${contextString}` : ''}`,\n\t\t\t\t});\n\t\t\t\twriteTickets();\n\t\t\t\tnotifyStaff();\n\t\t\t\tvoid textTicket.onSubmit?.(ticket, [text, contextString], this.user, this.connection);\n\t\t\t\tvoid runPunishments(ticket as TicketState & { text: [string, string] }, typeId);\n\t\t\t\tif (textTicket.getState) {\n\t\t\t\t\tticket.state = textTicket.getState(ticket, user);\n\t\t\t\t}\n\n\t\t\t\tconnection.send(`>view-${pageId}\\n|deinit`);\n\t\t\t\tChat.refreshPageFor(`help-list-${HelpTicket.getTypeId(ticket.type)}`, 'staff');\n\t\t\t\treturn this.popupReply(`Your report has been submitted.`);\n\t\t\t}\n\n\t\t\tlet closeButtons = ``;\n\t\t\tswitch (ticket.type) {\n\t\t\tcase 'Appeal':\n\t\t\tcase 'IP-Appeal':\n\t\t\t\tcloseButtons = `<button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}\">Close Ticket as Appeal Granted</button> <button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}, false\">Close Ticket as Appeal Denied</button>`;\n\t\t\t\tbreak;\n\t\t\tcase 'PM Harassment':\n\t\t\tcase 'Battle Harassment':\n\t\t\tcase 'Inappropriate Pokemon Nicknames':\n\t\t\tcase 'Inappropriate Username':\n\t\t\t\tcloseButtons = `<button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}\">Close Ticket as Valid Report</button> <button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}, false\">Close Ticket as Invalid Report</button>`;\n\t\t\t\tbreak;\n\t\t\tcase 'Public Room Assistance Request':\n\t\t\tcase 'Other':\n\t\t\tdefault:\n\t\t\t\tcloseButtons = `<button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}\">Close Ticket as Assisted</button> <button class=\"button\" style=\"margin: 5px 0\" name=\"send\" value=\"/helpticket close ${user.id}, false\">Close Ticket as Unable to Assist</button>`;\n\t\t\t}\n\t\t\tlet staffIntroButtons = '';\n\t\t\tlet pmRequestButton = '';\n\t\t\tif (reportTargetType === 'user' && reportTarget) {\n\t\t\t\tswitch (ticket.type) {\n\t\t\t\tcase 'PM Harassment':\n\t\t\t\t\tif (!Config.pmLogButton) break;\n\t\t\t\t\tpmRequestButton = Config.pmLogButton(user.id, toID(reportTarget));\n\t\t\t\t\tcontexts['PM Harassment'] = this.tr`Hi! Please click the button below to give global staff permission to check PMs.` +\n\t\t\t\t\t\tthis.tr` Or if ${reportTarget} is not the user you want to report, please tell us the name of the user who you want to report.`;\n\t\t\t\t\tbreak;\n\t\t\t\tcase 'Inappropriate Username':\n\t\t\t\t\tstaffIntroButtons = Utils.html`<button class=\"button\" name=\"send\" value=\"/forcerename ${reportTarget}\">Force-rename ${reportTarget}</button> `;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tstaffIntroButtons += Utils.html`<button class=\"button\" name=\"send\" value=\"/modlog room=global, user='${reportTarget}'\">Global Modlog for ${reportTarget}</button> <button class=\"button\" name=\"send\" value=\"/sharedbattles ${user.id}, ${toID(reportTarget)}\">Shared battles</button> `;\n\t\t\t}\n\t\t\tif (ticket.type === 'Appeal') {\n\t\t\t\tstaffIntroButtons += Utils.html`<button class=\"button\" name=\"send\" value=\"/modlog room=global, user='${user.name}'\">Global Modlog for ${user.name}</button>`;\n\t\t\t}\n\t\t\tconst introMsg = Utils.html`<h2 style=\"margin:0\">${this.tr`Help Ticket`} - ${user.name}</h2>` +\n\t\t\t\t`<p><b>${this.tr`Issue`}</b>: ${ticket.type}<br />${this.tr`A Global Staff member will be with you shortly.`}</p>`;\n\t\t\tconst staffMessage = [\n\t\t\t\t`<p>${closeButtons} <details><summary class=\"button\">More Options</summary> ${staffIntroButtons}`,\n\t\t\t\t`<button class=\"button\" name=\"send\" value=\"/modlog room=global, user='${ticket.userid}'\"><small>Global Modlog for ${ticket.creator}</small></button>`,\n\t\t\t\t`<button class=\"button\" name=\"send\" value=\"/helpticket ban ${user.id}\"><small>Ticketban</small></button>`,\n\t\t\t\t`<button class=\"button\" name=\"send\" value=\"/am edithistory ${ticket.userid}\"><small>Artemis History for ${ticket.creator}</small></button></p></details>`,\n\t\t\t].join('<br />');\n\t\t\tconst staffHint = staffContexts[ticketType] || '';\n\t\t\tlet reportTargetInfo = '';\n\t\t\tif (reportTargetType === 'room') {\n\t\t\t\treportTargetInfo = `Reported in room: <a href=\"/${reportTarget}\">${reportTarget}</a>`;\n\t\t\t\tconst reportRoom = Rooms.get(reportTarget) as GameRoom | undefined;\n\t\t\t\tvoid reportRoom?.uploadReplay?.(user, connection, 'forpunishment');\n\t\t\t} else if (reportTargetType === 'user') {\n\t\t\t\treportTargetInfo = `Reported user: <strong class=\"username\">${reportTarget}</strong><p></p>`;\n\n\t\t\t\tconst targetID = toID(reportTarget);\n\t\t\t\tif (targetID !== ticket.userid) {\n\t\t\t\t\tconst commonBattles = getCommonBattles(\n\t\t\t\t\t\ttargetID, Users.get(reportTarget),\n\t\t\t\t\t\tticket.userid, Users.get(ticket.userid),\n\t\t\t\t\t\tthis.connection\n\t\t\t\t\t);\n\n\t\t\t\t\tif (!commonBattles.length) {\n\t\t\t\t\t\treportTargetInfo += Utils.html`There are no common battles between '${reportTarget}' and '${ticket.creator}'.`;\n\t\t\t\t\t} else {\n\t\t\t\t\t\treportTargetInfo += Utils.html`Showing ${commonBattles.length} common battle(s) between '${reportTarget}' and '${ticket.creator}': `;\n\t\t\t\t\t\treportTargetInfo += commonBattles.map(\n\t\t\t\t\t\t\troomid => Utils.html`<a href=/${roomid}>${roomid.replace(/^battle-/, '')}`\n\t\t\t\t\t\t).join(', ');\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\tlet helpRoom = Rooms.get(`help-${user.id}`) as ChatRoom | null;\n\t\t\tif (!helpRoom) {\n\t\t\t\thelpRoom = Rooms.createChatRoom(`help-${user.id}` as RoomID, `[H] ${user.name}`, {\n\t\t\t\t\tisPersonal: true,\n\t\t\t\t\tisHelp: true,\n\t\t\t\t\tisPrivate: 'hidden',\n\t\t\t\t\tmodjoin: '%',\n\t\t\t\t\tauth: { [user.id]: '+' },\n\t\t\t\t\tintroMessage: introMsg,\n\t\t\t\t\tstaffMessage: staffMessage + staffHint + reportTargetInfo,\n\t\t\t\t});\n\t\t\t\thelpRoom.game = new HelpTicket(helpRoom, ticket);\n\t\t\t} else {\n\t\t\t\thelpRoom.pokeExpireTimer();\n\t\t\t\thelpRoom.settings.introMessage = introMsg;\n\t\t\t\thelpRoom.settings.staffMessage = staffMessage + staffHint + reportTargetInfo;\n\t\t\t\tif (helpRoom.game) helpRoom.game.destroy();\n\t\t\t\thelpRoom.game = new HelpTicket(helpRoom, ticket);\n\t\t\t}\n\t\t\tconst ticketGame = helpRoom.getGame(HelpTicket)!;\n\t\t\tChat.runHandlers('onTicketCreate', ticket, user);\n\t\t\thelpRoom.modlog({ action: 'TICKETOPEN', isGlobal: false, loggedBy: user.id, note: ticket.type });\n\t\t\tticketGame.addText(`${user.name} opened a new ticket. Issue: ${ticket.type}`, user);\n\t\t\tvoid this.parse(`/join help-${user.id}`);\n\t\t\tif (!(user.id in ticketGame.playerTable)) {\n\t\t\t\t// User was already in the room, manually add them to the \"game\" so they get a popup if they try to leave\n\t\t\t\tticketGame.addPlayer(user);\n\t\t\t}\n\t\t\tlet context = contexts[ticket.type];\n\t\t\tswitch (ticket.type) {\n\t\t\tcase 'IP-Appeal':\n\t\t\t\tif (user.locked === '#hostfilter') {\n\t\t\t\t\tcontext += ` (Have you looked at https://${Config.routes.root}/pages/proxyhelp?)`;\n\t\t\t\t}\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\tif (context) {\n\t\t\t\thelpRoom.add(`|c|~Staff|${this.tr(context)}`);\n\t\t\t\thelpRoom.update();\n\t\t\t}\n\t\t\tif (pmRequestButton) {\n\t\t\t\thelpRoom.add(pmRequestButton);\n\t\t\t\thelpRoom.update();\n\t\t\t}\n\t\t\ttickets[user.id] = ticket;\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t\tconnection.send(`>view-help-request\\n|deinit`);\n\t\t},\n\n\t\ttext(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\treturn this.parse(`/join view-help-text-${toID(target)}`);\n\t\t},\n\n\t\tasync resolve(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst [ticketerName, result] = Utils.splitFirst(target, ',').map(i => i.trim());\n\t\t\tconst ticketId = toID(ticketerName);\n\t\t\tif (!ticketId || !result) {\n\t\t\t\treturn this.parse(`/help helpticket`);\n\t\t\t}\n\t\t\tconst ticket = tickets[ticketId];\n\t\t\tif (!ticket) return this.popupReply(`That ticket was not found.`);\n\t\t\tif (ticket.resolved) {\n\t\t\t\treturn this.popupReply(`That ticket has already been resolved.`);\n\t\t\t}\n\t\t\tif (!ticket.text) {\n\t\t\t\treturn this.popupReply(`That ticket cannot be resolved with /helpticket resolve. Join it instead.`);\n\t\t\t}\n\t\t\tconst { publicReason, privateReason } = this.parseSpoiler(result);\n\t\t\tticket.resolved = {\n\t\t\t\tresult: publicReason,\n\t\t\t\ttime: Date.now(),\n\t\t\t\tby: user.name,\n\t\t\t\tseen: false,\n\t\t\t\tstaffReason: privateReason,\n\t\t\t};\n\t\t\tticket.open = false;\n\t\t\twriteTickets();\n\t\t\tconst tarUser = Users.get(ticketId);\n\t\t\tif (tarUser) {\n\t\t\t\tHelpTicket.notifyResolved(tarUser, ticket, ticketId);\n\t\t\t}\n\t\t\t// ticketType\\ttotalTime\\ttimeToFirstClaim\\tinactiveTime\\tresolution\\tresult\\tstaff,userids,seperated,with,commas\n\t\t\twriteStats(`${ticket.type}\\t${Date.now() - ticket.created}\\t0\\t0\\tresolved\\tvalid\\t${user.id}`);\n\t\t\tthis.popupReply(`You resolved ${ticketId}'s ticket.`);\n\t\t\tawait HelpTicket.modlog({\n\t\t\t\taction: 'TEXTTICKET CLOSE',\n\t\t\t\tloggedBy: user.id,\n\t\t\t\tnote: privateReason,\n\t\t\t\tuserid: ticketId,\n\t\t\t});\n\t\t\tHelpTicket.logTextResult(ticket as TicketState & { text: [string, string], resolved: ResolvedTicketInfo });\n\t\t\tnotifyStaff();\n\t\t\t// force a refresh for everyone in it, otherwise we potentially get two punishments at once\n\t\t\t// from different people clicking at the same time and reading it separately.\n\t\t\t// Yes. This was a real issue.\n\t\t\tChat.refreshPageFor(`help-text-${ticketId}`, 'staff');\n\t\t\tChat.refreshPageFor(`help-list-${HelpTicket.getTypeId(ticket.type)}`, 'staff');\n\t\t},\n\n\t\tlist(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\treturn this.parse('/join view-help-tickets');\n\t\t},\n\t\tlisthelp: [`/helpticket list - Lists all tickets. Requires: % @ ~`],\n\n\t\tinapnames: 'massview',\n\t\tusernames: 'massview',\n\t\tmassview(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = toID(target);\n\t\t\tswitch (this.cmd) {\n\t\t\tcase 'inapnames': case 'usernames':\n\t\t\t\ttarget = 'inapname';\n\t\t\t\tbreak;\n\t\t\t}\n\t\t\treturn this.parse(`/j view-help-list${target ? `-${target}` : \"\"}`);\n\t\t},\n\n\t\tstats(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\treturn this.parse('/join view-help-stats');\n\t\t},\n\t\tstatshelp: [`/helpticket stats - List the stats for help tickets. Requires: % @ ~`],\n\n\t\tnote: 'addnote',\n\t\taddnote(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = target.trim();\n\t\t\tif (!target) return this.parse(`/help helpticket addnote`);\n\t\t\tconst [ticketName, note] = Utils.splitFirst(target, ',').map(i => i.trim());\n\t\t\tconst ticketId = toID(ticketName);\n\t\t\tif (!ticketId) return this.errorReply(`Specify the userid that created the ticket you want to mark.`);\n\t\t\tconst ticket = tickets[ticketId];\n\t\t\tif (!ticket) return this.errorReply(`${ticketId} does not have an active ticket.`);\n\t\t\tif (ticket.resolved) return this.errorReply(`${ticketId}'s ticket has already been resolved.`);\n\t\t\tif (!note) return this.errorReply(`You must specify a note to add.`);\n\t\t\tif (!ticket.notes) ticket.notes = {};\n\t\t\tticket.notes[user.id] = note;\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t\tif (!room || room.roomid !== 'staff') this.sendReply(`Added the note \"${note}\" to ${ticketId}'s ticket.`);\n\t\t\tthis.room = Rooms.get('staff') || null;\n\t\t\tthis.addGlobalModAction(`${user.name} added the note \"${note}\" to ${ticket.userid}'s helpticket.`);\n\t\t\tthis.globalModlog(`HELPTICKET NOTE`, ticket.userid, note);\n\t\t},\n\t\taddnotehelp: [\n\t\t\t`/helpticket note [ticket userid], [note] - Adds a note to the [ticket], to be displayed in the hover text. Requires: % @ ~`,\n\t\t],\n\t\tremovenote(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = target.trim();\n\t\t\tif (!target) return this.parse(`/help helpticket removenote`);\n\t\t\tlet [ticketName, staff] = Utils.splitFirst(target, ',').map(i => i.trim());\n\t\t\tconst targetId = toID(ticketName);\n\t\t\tif (!targetId) return this.errorReply(`Specify the userid that created the ticket you want to remove a note from.`);\n\t\t\tconst ticket = tickets[targetId];\n\t\t\tif (!ticket || ticket.resolved) return this.errorReply(`${targetId} does not have a pending ticket.`);\n\t\t\tstaff = toID(staff) || user.id;\n\t\t\tif (!ticket.notes) return this.errorReply(`${targetId}'s ticket does not have any notes.`);\n\t\t\tconst note = ticket.notes[staff];\n\t\t\tif (!note) {\n\t\t\t\treturn this.errorReply(`${staff === user.id ? 'you do' : `'${staff}' does`} not have a note on that ticket.`);\n\t\t\t}\n\t\t\tif (!room || room.roomid !== 'staff') {\n\t\t\t\tthis.sendReply(`You removed the note '${note}' (by ${staff}) on ${ticket.userid}'s ticket.`);\n\t\t\t}\n\t\t\tdelete ticket.notes[staff];\n\t\t\tif (!Object.keys(ticket.notes).length) delete ticket.notes;\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t\tthis.room = Rooms.get('staff') || null;\n\t\t\tthis.addModAction(`${user.name} removed ${staff}'s note (\"${note}\") from ${ticket.userid}'s helpticket.`);\n\t\t\tthis.globalModlog(`HELPTICKET REMOVENOTE`, ticket.userid, `${note} (originally by ${staff})`);\n\t\t},\n\t\tremovenotehelp: [\n\t\t\t`/helpticket removenote [ticket userid], [staff] - Removes a note from the [ticket].`,\n\t\t\t`If a [staff] userid is given, removes the note from that staff member (defaults to your userid).`,\n\t\t\t`Requires: % @ ~`,\n\t\t],\n\n\t\tar: 'addresponse',\n\t\tforceaddresponse: 'addresponse',\n\t\tfar: 'addresponse',\n\t\taddresponse(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst [type, name, response] = Utils.splitFirst(target, ',', 2).map(f => f.trim());\n\t\t\tif (!toID(type) || !toID(name) || !toID(response)) {\n\t\t\t\treturn this.parse(`/help helpticket addresponse`);\n\t\t\t}\n\t\t\tconst typeId = HelpTicket.getTypeId(type);\n\t\t\tif (!(typeId in textTickets)) {\n\t\t\t\tthis.errorReply(`'${type}' is not a valid text ticket type.`);\n\t\t\t\treturn this.errorReply(`Valid types: ${Object.keys(textTickets).join(', ')}.`);\n\t\t\t}\n\t\t\tif (!settings.responses[typeId]) {\n\t\t\t\tsettings.responses[typeId] = {};\n\t\t\t}\n\t\t\tif (settings.responses[typeId][name] && !this.cmd.includes('f')) {\n\t\t\t\tthis.errorReply(`That button already exists for that ticket type.`);\n\t\t\t\treturn this.errorReply(`Use /ht forceaddresponse to override it if you're sure.`);\n\t\t\t}\n\t\t\tsettings.responses[typeId][name] = response;\n\t\t\twriteSettings();\n\t\t\tthis.privateGlobalModAction(`${user.name} added a response button '${name}' for the ticket type ${typeId} (\"${response}\")`);\n\t\t\tthis.globalModlog(`HELPTICKET ADDRESPONSE`, null, `'${response}' named ${name} for ${typeId}`);\n\t\t},\n\t\taddresponsehelp: [\n\t\t\t`/helpticket addresponse [type], [name], [response] - Adds a [response] button to the given ticket [type] with the given [name].`,\n\t\t\t`Requires: % @ ~`,\n\t\t],\n\n\t\trr: 'removeresponse',\n\t\tremoveresponse(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst [type, name] = Utils.splitFirst(target, ',').map(f => f.trim());\n\t\t\tif (!toID(type) || !toID(name)) return this.parse(`/help helpticket removeresponse`);\n\t\t\tconst typeId = HelpTicket.getTypeId(type);\n\t\t\tif (!(type in textTickets)) {\n\t\t\t\treturn this.errorReply(`'${type}' is not a valid text ticket type.`);\n\t\t\t}\n\t\t\tif (!settings.responses[typeId]?.[name]) {\n\t\t\t\treturn this.errorReply(`'${name}' is not a response for the ${typeId} ticket type .`);\n\t\t\t}\n\t\t\tdelete settings.responses[typeId][name];\n\t\t\tif (!Object.keys(settings.responses[typeId]).length) {\n\t\t\t\tdelete settings.responses[typeId];\n\t\t\t}\n\t\t\twriteSettings();\n\t\t\tthis.privateGlobalModAction(`${user.name} removed the response named '${name}' from the responses for ${typeId} tickets`);\n\t\t\tthis.globalModlog('HELPTICKET REMOVERESPONSE', null, `${name} (from ${typeId})`);\n\t\t},\n\t\tremoveresponsehelp: [\n\t\t\t`/helpticket removeresponse [type], [name] - Removes the response button with the given [name] from the given ticket [type].`,\n\t\t\t`Requires: % @ ~`,\n\t\t],\n\n\t\tlr: 'listresponses',\n\t\tlistresponses(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tlet buf = `<strong>Help ticket response buttons `;\n\t\t\ttarget = toID(target);\n\t\t\tif (target && !(target in textTickets)) {\n\t\t\t\treturn this.errorReply(`Invalid ticket type: ${target}.`);\n\t\t\t}\n\t\t\tbuf += `${target ? `for the type ${target}:` : \"\"}</strong><hr />`;\n\t\t\tconst table = target ? { [target]: settings.responses[target] } : settings.responses;\n\t\t\tif (!Object.keys(table).length) {\n\t\t\t\tbuf += `<p class=\"message-error\">None</p>`;\n\t\t\t\treturn this.sendReplyBox(buf);\n\t\t\t}\n\t\t\tbuf += Object.keys(table).map(type => (\n\t\t\t\t`<p>${ticketTitles[type]}<p>` +\n\t\t\t\tObject.keys(settings.responses[type])\n\t\t\t\t\t.map(name => Utils.html`<p>- ${name}: \"${settings.responses[type][name]}\"</p>`).join('')\n\t\t\t)).join('<hr />');\n\t\t\treturn this.sendReplyBox(buf);\n\t\t},\n\t\tlistresponseshelp: [\n\t\t\t`/helpticket listresponses [optional type] - List current response buttons for text tickets. `,\n\t\t\t`If a [type] is given, lists responses only for that type. Requires: % @ ~`,\n\t\t],\n\n\t\tclose(target, room, user) {\n\t\t\tif (!target) {\n\t\t\t\tif (room?.roomid.startsWith('help-')) {\n\t\t\t\t\ttarget = room.roomid.slice(5);\n\t\t\t\t} else {\n\t\t\t\t\treturn this.parse(`/help helpticket close`);\n\t\t\t\t}\n\t\t\t}\n\t\t\tconst [targetUsername, rest] = this.splitOne(target);\n\t\t\tlet result = rest !== 'false';\n\t\t\tconst ticket = tickets[toID(targetUsername)];\n\t\t\tif (!ticket?.open || (ticket.userid !== user.id && !user.can('lock'))) {\n\t\t\t\treturn this.errorReply(this.tr`${targetUsername} does not have an open ticket.`);\n\t\t\t}\n\t\t\tif (typeof ticket.text !== 'undefined') {\n\t\t\t\treturn this.parse(`/helpticket resolve ${target}`);\n\t\t\t}\n\t\t\tconst helpRoom = Rooms.get(`help-${ticket.userid}`) as ChatRoom | null;\n\t\t\tif (helpRoom) {\n\t\t\t\tconst ticketGame = helpRoom.getGame(HelpTicket)!;\n\t\t\t\tif (ticket.userid === user.id && !user.isStaff) {\n\t\t\t\t\tresult = !!(ticketGame.firstClaimTime);\n\t\t\t\t}\n\t\t\t\tticketGame.close(result, user);\n\t\t\t} else {\n\t\t\t\tticket.open = false;\n\t\t\t\tnotifyStaff();\n\t\t\t\twriteTickets();\n\t\t\t}\n\t\t\tticket.claimed = user.name;\n\t\t\tthis.sendReply(`You closed ${ticket.creator}'s ticket.`);\n\t\t},\n\t\tclosehelp: [`/helpticket close [user] - Closes an open ticket. Requires: % @ ~`],\n\n\t\ttb: 'ban',\n\t\tticketban: 'ban',\n\t\tasync ban(target, room, user) {\n\t\t\tif (!target) return this.parse('/help helpticket ban');\n\t\t\tconst { targetUser, targetUsername, rest: reason } = this.splitUser(target, { exactName: true });\n\t\t\tthis.checkCan('lock', targetUser);\n\n\t\t\tconst punishment = Punishments.roomUserids.nestedGet('staff', toID(targetUsername));\n\t\t\tif (!targetUser && !Punishments.search(toID(targetUsername)).length) {\n\t\t\t\treturn this.errorReply(this.tr`User '${targetUsername}' not found.`);\n\t\t\t}\n\t\t\tif (reason.length > 300) {\n\t\t\t\treturn this.errorReply(this.tr`The reason is too long. It cannot exceed 300 characters.`);\n\t\t\t}\n\n\t\t\tlet username;\n\t\t\tlet userid;\n\n\t\t\tif (targetUser) {\n\t\t\t\tusername = targetUser.getLastName();\n\t\t\t\tuserid = targetUser.getLastId();\n\t\t\t\tif (punishment) {\n\t\t\t\t\treturn this.privateModAction(`${username} would be ticket banned by ${user.name} but was already ticket banned.`);\n\t\t\t\t}\n\t\t\t\tif (targetUser.trusted) {\n\t\t\t\t\tMonitor.log(`[CrisisMonitor] Trusted user ${targetUser.name}${(targetUser.trusted !== targetUser.id ? ` (${targetUser.trusted})` : ``)} was ticket banned by ${user.name}, and should probably be demoted.`);\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tusername = targetUsername;\n\t\t\t\tuserid = toID(targetUsername);\n\t\t\t\tif (punishment) {\n\t\t\t\t\treturn this.privateModAction(`${username} would be ticket banned by ${user.name} but was already ticket banned.`);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (targetUser) {\n\t\t\t\ttargetUser.popup(`|modal|${user.name} has banned you from creating help tickets.${(reason ? `\\n\\nReason: ${reason}` : ``)}\\n\\nYour ban will expire in a few days.`);\n\t\t\t}\n\n\t\t\tconst affected: (User | ID)[] = await HelpTicket.ban(targetUser || userid, reason);\n\t\t\tthis.addGlobalModAction(`${username} was ticket banned by ${user.name}.${reason ? ` (${reason})` : ``}`);\n\t\t\tconst acAccount = (targetUser && targetUser.autoconfirmed !== userid && targetUser.autoconfirmed);\n\n\t\t\tlet displayMessage = '';\n\t\t\tif (affected.length > 1) {\n\t\t\t\tconst alts = affected.slice(1).map(userObj => typeof userObj === 'string' ? userObj : userObj.getLastName()).join(\", \");\n\t\t\t\tdisplayMessage = `${username}'s ${acAccount ? ` ac account: ${acAccount}, ` : \"\"}ticket banned alts: ${alts}`;\n\t\t\t\tthis.privateModAction(displayMessage);\n\t\t\t} else if (acAccount) {\n\t\t\t\tdisplayMessage = `${username}'s ac account: ${acAccount}`;\n\t\t\t\tthis.privateModAction(displayMessage);\n\t\t\t}\n\t\t\tif (targetUser?.previousIDs.length) {\n\t\t\t\taffected.push(...targetUser.previousIDs);\n\t\t\t}\n\n\t\t\tthis.globalModlog(`TICKETBAN`, targetUser || userid, reason);\n\t\t\tconst staffRoom = Rooms.get('staff');\n\t\t\tfor (const userObj of affected) {\n\t\t\t\tconst userObjID = (typeof userObj !== 'string' ? userObj.getLastId() : toID(userObj));\n\t\t\t\tconst targetTicket = tickets[userObjID];\n\t\t\t\tif (targetTicket?.open) targetTicket.open = false;\n\t\t\t\tconst helpRoom = Rooms.get(`help-${userObjID}`);\n\t\t\t\tif (helpRoom) {\n\t\t\t\t\tconst ticketGame = helpRoom.getGame(HelpTicket)!;\n\t\t\t\t\tticketGame.writeStats('ticketban');\n\t\t\t\t\thelpRoom.destroy();\n\t\t\t\t} else if (targetTicket?.text) {\n\t\t\t\t\tawait HelpTicket.modlog({\n\t\t\t\t\t\taction: `TICKETBAN`,\n\t\t\t\t\t\tloggedBy: user.id,\n\t\t\t\t\t\tnote: `(Ticket content: ${targetTicket.text.join(' ').replace(/\\n/ig, ' ')})`,\n\t\t\t\t\t});\n\t\t\t\t\ttargetTicket.resolved = {\n\t\t\t\t\t\tby: user.id,\n\t\t\t\t\t\tseen: true,\n\t\t\t\t\t\ttime: Date.now(),\n\t\t\t\t\t\tresult: 'Ticketban',\n\t\t\t\t\t\tstaffReason: 'Ticketban',\n\t\t\t\t\t};\n\t\t\t\t\tif (staffRoom) {\n\t\t\t\t\t\tfor (const curUser of Object.values(staffRoom.users)) {\n\t\t\t\t\t\t\tfor (const conn of curUser.connections) {\n\t\t\t\t\t\t\t\tif (conn.openPages?.has(`help-text-${userObjID}`)) {\n\t\t\t\t\t\t\t\t\tconn.send(`>view-help-text-${userObj}\\n|deinit|`);\n\t\t\t\t\t\t\t\t\tconn.openPages.delete(`help-text-${userObjID}`);\n\t\t\t\t\t\t\t\t\tif (!conn.openPages.size) conn.openPages = null;\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t\treturn true;\n\t\t},\n\t\tbanhelp: [`/helpticket ban [user], (reason) - Bans a user from creating tickets for 2 days. Requires: % @ ~`],\n\n\t\tunticketban: 'unban',\n\t\tunban(target, room, user) {\n\t\t\tif (!target) return this.parse('/help helpticket unban');\n\n\t\t\tthis.checkCan('lock');\n\t\t\ttarget = toID(target);\n\t\t\tconst targetID: ID = Users.get(target)?.id || target as ID;\n\t\t\tconst banned = Punishments.isTicketBanned(targetID);\n\t\t\tif (!banned) {\n\t\t\t\treturn this.errorReply(this.tr`${target} is not ticket banned.`);\n\t\t\t}\n\n\t\t\tconst affected = HelpTicket.unban(targetID);\n\t\t\tthis.addModAction(`${affected} was ticket unbanned by ${user.name}.`);\n\t\t\tthis.globalModlog(\"UNTICKETBAN\", toID(target));\n\t\t\tUsers.get(target)?.popup(`${user.name} has ticket unbanned you.`);\n\t\t},\n\t\tunbanhelp: [`/helpticket unban [user] - Ticket unbans a user. Requires: % @ ~`],\n\n\t\tignore(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tif (user.settings.ignoreTickets) {\n\t\t\t\treturn this.errorReply(this.tr`You are already ignoring help ticket notifications. Use /helpticket unignore to receive notifications again.`);\n\t\t\t}\n\t\t\tuser.settings.ignoreTickets = true;\n\t\t\tuser.update();\n\t\t\tthis.sendReply(this.tr`You are now ignoring help ticket notifications.`);\n\t\t},\n\t\tignorehelp: [`/helpticket ignore - Ignore notifications for unclaimed help tickets. Requires: % @ ~`],\n\n\t\tunignore(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tif (!user.settings.ignoreTickets) {\n\t\t\t\treturn this.errorReply(this.tr`You are not ignoring help ticket notifications. Use /helpticket ignore to stop receiving notifications.`);\n\t\t\t}\n\t\t\tuser.settings.ignoreTickets = false;\n\t\t\tuser.update();\n\t\t\tthis.sendReply(this.tr`You will now receive help ticket notifications.`);\n\t\t},\n\t\tunignorehelp: [`/helpticket unignore - Stop ignoring notifications for help tickets. Requires: % @ ~`],\n\n\t\tdelete(target, room, user) {\n\t\t\t// This is a utility only to be used if something goes wrong\n\t\t\tthis.checkCan('makeroom');\n\t\t\tif (!target) return this.parse(`/help helpticket delete`);\n\t\t\tconst ticket = tickets[toID(target)];\n\t\t\tif (!ticket) return this.errorReply(this.tr`${target} does not have a ticket.`);\n\t\t\tconst targetRoom = Rooms.get(`help-${ticket.userid}`);\n\t\t\tif (targetRoom) {\n\t\t\t\ttargetRoom.getGame(HelpTicket)!.deleteTicket(user);\n\t\t\t} else {\n\t\t\t\tdelete tickets[ticket.userid];\n\t\t\t\twriteTickets();\n\t\t\t\tnotifyStaff();\n\t\t\t}\n\t\t\tthis.sendReply(this.tr`You deleted ${target}'s ticket.`);\n\t\t},\n\t\tdeletehelp: [`/helpticket delete [user] - Deletes a user's ticket. Requires: ~`],\n\n\t\tlogs(target, room, user) {\n\t\t\tthis.checkCan('lock');\n\t\t\tconst [targetString, dateString] = Utils.splitFirst(target, ',').map(i => i.trim());\n\t\t\tconst id = toID(targetString);\n\t\t\tif (!id) return this.errorReply(`Specify a userid.`);\n\t\t\treturn this.parse(`/j view-help-logs-${id}${dateString ? `--${dateString}` : ''}`);\n\t\t},\n\t\tlogshelp: [\n\t\t\t`/helpticket logs [userid][, month] - View logs of the [userid]'s text tickets. `,\n\t\t\t`If a [month] is given, searches only that month.`,\n\t\t\t`Requires: % @ ~`,\n\t\t],\n\n\t\tasync private(target, room, user) {\n\t\t\tthis.checkCan('bypassall');\n\t\t\tif (!target) return this.parse(`/help helpticket`);\n\t\t\tconst [username, date] = target.split(',');\n\t\t\tconst userid = toID(username);\n\t\t\tif (!userid) return this.parse(`/help helpticket`);\n\t\t\tif (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(date)) {\n\t\t\t\treturn this.errorReply(`Invalid date (must be YYYY-MM-DD format).`);\n\t\t\t}\n\t\t\tconst logPath = Monitor.logPath(`chat/help-${userid}/${date.slice(0, -3)}/${date}.txt`);\n\t\t\tif (!(await logPath.exists())) {\n\t\t\t\treturn this.errorReply(`There are no logs for tickets from '${userid}' on the date '${date}'.`);\n\t\t\t}\n\t\t\tif (!(await Monitor.logPath(`private/${userid}`).exists())) {\n\t\t\t\tawait Monitor.logPath(`private/${userid}`).mkdirp();\n\t\t\t}\n\t\t\tawait logPath.copyFile(Monitor.logPath(`private/${userid}/${date}.txt`).path);\n\t\t\tawait logPath.write(''); // empty out the logfile\n\t\t\tthis.globalModlog(`HELPTICKET PRIVATELOGS`, null, `${userid} (${date})`);\n\t\t\tthis.privateGlobalModAction(`${user.name} set the ticket logs for '${userid}' on '${date}' to be private.`);\n\t\t},\n\t\tprivatehelp: [\n\t\t\t`/helpticket private [user], [date] - Makes the ticket logs for a user on a date private to upperstaff. Requires: ~`,\n\t\t],\n\t\tasync public(target, room, user) {\n\t\t\tthis.checkCan('bypassall');\n\t\t\tif (!target) return this.parse(`/help helpticket`);\n\t\t\tconst [username, date] = target.split(',');\n\t\t\tconst userid = toID(username);\n\t\t\tif (!userid) return this.parse(`/help helpticket`);\n\t\t\tif (!/[0-9]{4}-[0-9]{2}-[0-9]{2}/.test(date)) {\n\t\t\t\treturn this.errorReply(`Invalid date (must be YYYY-MM-DD format).`);\n\t\t\t}\n\t\t\tconst logPath = Monitor.logPath(`private/${userid}/${date}.txt`);\n\t\t\tif (!(await logPath.exists())) {\n\t\t\t\treturn this.errorReply(`There are no logs for tickets from '${userid}' on the date '${date}'.`);\n\t\t\t}\n\t\t\tconst monthPath = Monitor.logPath(`chat/help-${userid}/${date.slice(0, -3)}`);\n\t\t\tif (!(await monthPath.exists())) {\n\t\t\t\tawait monthPath.mkdirp();\n\t\t\t}\n\t\t\tawait logPath.copyFile(Monitor.logPath(`chat/help-${userid}/${date.slice(0, -3)}/${date}.txt`).path);\n\t\t\tawait logPath.unlinkIfExists();\n\t\t\tthis.globalModlog(`HELPTICKET PUBLICLOGS`, null, `${userid} (${date})`);\n\t\t\tthis.privateGlobalModAction(`${user.name} set the ticket logs for '${userid}' on '${date}' to be public.`);\n\t\t},\n\t\tpublichelp: [\n\t\t\t`/helpticket public [user], [date] - Makes the ticket logs for the [user] on the [date] public to staff. Requires: ~`,\n\t\t],\n\t},\n\n\ttb: 'ticketban',\n\tunticketban: 'ticketban',\n\tticketban(target, room, user, connection, cmd) {\n\t\treturn this.parse(`/helpticket ${cmd} ${target}`);\n\t},\n\n\thelptickethelp: [\n\t\t`/helpticket create - Creates a new ticket, requesting help from global staff.`,\n\t\t`/helpticket list - Lists all tickets. Requires: % @ ~`,\n\t\t`/helpticket close [user] - Closes an open ticket. Requires: % @ ~`,\n\t\t`/helpticket ban [user], (reason) - Bans a user from creating tickets for 2 days. Requires: % @ ~`,\n\t\t`/helpticket unban [user] - Ticket unbans a user. Requires: % @ ~`,\n\t\t`/helpticket ignore - Ignore notifications for unclaimed help tickets. Requires: % @ ~`,\n\t\t`/helpticket unignore - Stop ignoring notifications for help tickets. Requires: % @ ~`,\n\t\t`/helpticket delete [user] - Deletes a user's ticket. Requires: ~`,\n\t\t`/helpticket logs [userid][, month] - View logs of the [userid]'s text tickets. Requires: % @ ~`,\n\t\t`/helpticket note [ticket userid], [note] - Adds a note to the [ticket], to be displayed in the hover text. Requires: % @ ~`,\n\t\t`/helpticket private [user], [date] - Makes the ticket logs for a user on a date private to upperstaff. Requires: ~`,\n\t\t`/helpticket public [user], [date] - Makes the ticket logs for the [user] on the [date] public to staff. Requires: ~`,\n\t],\n};\n\nexport const punishmentfilter: Chat.PunishmentFilter = (user, punishment) => {\n\tif (punishment.type !== 'BAN') return;\n\n\tconst userId = toID(user);\n\tif (typeof user === 'object') {\n\t\tconst ids = [userId, ...user.previousIDs];\n\t\tfor (const userid of ids) {\n\t\t\tpunishmentfilter(userid, punishment);\n\t\t}\n\t} else {\n\t\tconst helpRoom = Rooms.get(`help-${userId}`);\n\t\tif (helpRoom?.game?.gameid !== 'helpticket') return;\n\t\tconst ticket = helpRoom.game as HelpTicket;\n\t\tticket.close('ticketban');\n\t}\n};\n\nexport const loginfilter: Chat.LoginFilter = user => {\n\tconst ticket = tickets[user.id];\n\tif (ticket?.resolved) {\n\t\tHelpTicket.notifyResolved(user, ticket);\n\t}\n};\n\nexport const handlers: Chat.Handlers = {\n\tonRoomClose(room, user, conn, isPage) {\n\t\tif (!isPage || !room.includes('view-help-text')) return;\n\t\tconst userid = room.slice('view-help-text'.length + 1);\n\t\tconst ticket = tickets[userid];\n\t\tif (ticket?.open && ticket.claimed === user.id) {\n\t\t\tticket.claimed = null;\n\t\t\tif (ticket.state?.claimTime) {\n\t\t\t\tdelete ticket.state.claimTime;\n\t\t\t\tif (!Object.keys(ticket.state).length) delete ticket.state;\n\t\t\t}\n\t\t\twriteTickets();\n\t\t\tnotifyStaff();\n\t\t}\n\t},\n};\n\nprocess.nextTick(() => {\n\tChat.multiLinePattern.register(\n\t\t'/ht resolve ', '/helpticket resolve ',\n\t\t'/requesthelp resolve ', '/helprequest resolve ',\n\t\t'/ht submit ', '/helpticket submit ',\n\t);\n});\n"],
"mappings": "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",
"names": ["buf", "type", "helpRoom"]
}