From 2fe8cb44bbfbca4de830f7c32514f8014fdc09ea Mon Sep 17 00:00:00 2001 From: Mia <49593536+mia-pi-git@users.noreply.github.com> Date: Wed, 26 May 2021 13:23:24 -0500 Subject: [PATCH] Helptickets: Support fetching replay logs --- server/chat-plugins/helptickets.ts | 77 ++++++++++++++++++++++-------- 1 file changed, 56 insertions(+), 21 deletions(-) diff --git a/server/chat-plugins/helptickets.ts b/server/chat-plugins/helptickets.ts index e477d41146..7c128c74e5 100644 --- a/server/chat-plugins/helptickets.ts +++ b/server/chat-plugins/helptickets.ts @@ -1,4 +1,4 @@ -import {FS, Utils} from '../../lib'; +import {FS, Utils, Net} from '../../lib'; import {getCommonBattles} from '../chat-commands/info'; import type {Punishment} from '../punishments'; import type {PartialModlogEntry, ModlogID} from '../modlog'; @@ -42,6 +42,12 @@ interface TextTicketInfo { onSubmit?: (ticket: TicketState, text: [string, string], submitter: User, conn: Connection) => void; } +interface BattleInfo { + log: string[]; + url: string; + title: string; +} + type TicketResult = 'approved' | 'valid' | 'assisted' | 'denied' | 'invalid' | 'unassisted' | 'ticketban' | 'deleted'; export const tickets: {[k: string]: TicketState} = {}; @@ -401,23 +407,28 @@ export class HelpTicket extends Rooms.RoomGame { void (room as GameRoom).uploadReplay(user, conn, "forpunishment"); } } - static visualizeBattleLogs(rooms: string[]) { - const existingRooms = rooms.map(r => Rooms.get(r)).filter(r => r?.type !== 'chat'); + static formatBattleLog(logs: string[], title: string, url: string) { + const log = logs.filter(l => l.startsWith('|c|')); + let buf = ``; + for (const line of log) { + const [,, username, message] = Utils.splitFirst(line, '|', 3); + buf += Utils.html`
${username}: ${message}
`; + } + if (buf) buf = `
${title}
${buf}
`; + return buf; + } + static async visualizeBattleLogs(rooms: string[]) { + const logs = []; + for (const room of rooms) { + const log = await getBattleLog(room); + if (log) logs.push(log); + } + const existingRooms = logs.filter(Boolean); if (existingRooms.length) { - const chatBuffer = existingRooms.map(room => { - // there is no reason this should happen (room && room.type check above in .filter). - // but typescript is stupid. so appeasement. - if (!room) return ''; - const log = room.log.log.filter(l => l.startsWith('|c|')); - if (!log?.length) return ''; - let innerBuf = `
${room.title}
`; - for (const line of log) { - const [,, username, message] = Utils.splitFirst(line, '|', 3); - innerBuf += Utils.html`
${username}: ${message}
`; - } - innerBuf += `
`; - return innerBuf; - }).filter(Boolean).join(''); + const chatBuffer = existingRooms + .map(room => this.formatBattleLog(room.log, room.title, room.url)) + .filter(Boolean) + .join(''); if (chatBuffer) { return ( `
Battle chat logs:
` + @@ -658,6 +669,30 @@ export function getBattleLinks(text: string) { return rooms; } +export async function getBattleLog(battle: string): Promise { + const battleRoom = Rooms.get(battle); + if (battleRoom && battleRoom.type !== 'chat') { + return { + log: battleRoom.log.log.filter(k => k.startsWith('|c|')), + title: battleRoom.title, + url: `/${Config.routes.client}/${battle}`, + }; + } + battle = battle.replace(`battle-`, '').replace(/-[a-z0-9]pw/, ''); + try { + const raw = await Net(`https://${Config.routes.replays}/${battle}.json`).get(); + const data = JSON.parse(raw); + if (data.log?.length) { + return { + log: data.log.split('\n').filter((k: string) => k.startsWith('|c|')), + title: `${data.p1} vs ${data.p2}`, + url: `https://${Config.routes.replays}/${battle}.json`, + }; + } + } catch (e) {} + return null; +} + // Prevent a desynchronization issue when hotpatching for (const room of Rooms.rooms.values()) { if (!room.settings.isHelp || !room.game) continue; @@ -760,7 +795,7 @@ export const textTickets: {[k: string]: TextTicketInfo} = { } return true; }, - getReviewDisplay(ticket, staff, conn) { + async getReviewDisplay(ticket, staff, conn) { let buf = ''; const reportUserid = toID(ticket.text[0]); const sharedBattles = getCommonBattles(ticket.userid, null, reportUserid, null, conn); @@ -773,7 +808,7 @@ export const textTickets: {[k: string]: TextTicketInfo} = { buf += HelpTicket.displayPunishmentList(reportUserid, proofString); if (sharedBattles.length) { - const battleLogHTML = HelpTicket.visualizeBattleLogs(sharedBattles); + const battleLogHTML = await HelpTicket.visualizeBattleLogs(sharedBattles); if (battleLogHTML) { buf += `
`; buf += battleLogHTML; @@ -833,7 +868,7 @@ export const textTickets: {[k: string]: TextTicketInfo} = { HelpTicket.uploadReplaysFrom(part, submitter, conn); } }, - getReviewDisplay(ticket, staff, connection) { + async getReviewDisplay(ticket, staff, connection) { let buf = ``; const [text, context] = ticket.text; let rooms = getBattleLinks(text); @@ -856,7 +891,7 @@ export const textTickets: {[k: string]: TextTicketInfo} = { } buf += `Battle links: ${rooms.map(url => Chat.formatText(`<<${url}>>`)).join(', ')}
`; buf += `
`; - const battleLogHTML = HelpTicket.visualizeBattleLogs(rooms); + const battleLogHTML = await HelpTicket.visualizeBattleLogs(rooms); if (battleLogHTML) buf += battleLogHTML; return buf; },