"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); var helptickets_auto_exports = {}; __export(helptickets_auto_exports, { actionHandlers: () => actionHandlers, addModAction: () => addModAction, checkers: () => checkers, classifier: () => classifier, commands: () => commands, determinePunishment: () => determinePunishment, getMessageAverages: () => getMessageAverages, getModlog: () => getModlog, globalModlog: () => globalModlog, pages: () => pages, punishmentsFor: () => punishmentsFor, runPunishments: () => runPunishments, settings: () => settings }); module.exports = __toCommonJS(helptickets_auto_exports); var import_lib = require("../../lib"); var import_helptickets = require("./helptickets"); var Artemis = __toESM(require("../artemis")); const ORDERED_PUNISHMENTS = ["WARN", "FORCERENAME", "LOCK", "NAMELOCK", "WEEKLOCK", "WEEKNAMELOCK"]; const PMLOG_IGNORE_TIME = 24 * 60 * 60 * 1e3; const WHITELIST = ["mia"]; const defaults = { punishments: [{ ticketType: "inapname", punishment: "forcerename", severity: { type: ["sexual_explicit", "severe_toxicity", "identity_attack"], certainty: 0.4 } }, { ticketType: "pmharassment", punishment: "warn", severity: { type: ["sexual_explicit", "severe_toxicity", "identity_attack"], certainty: 0.15 } }], applyPunishments: false }; const settings = (() => { try { return { ...defaults, ...JSON.parse((0, import_lib.FS)("config/chat-plugins/ht-auto.json").readSync()) }; } catch { return defaults; } })(); function saveSettings() { return (0, import_lib.FS)("config/chat-plugins/ht-auto.json").writeUpdate(() => JSON.stringify(settings)); } function visualizePunishment(punishment) { const buf = [`punishment: ${punishment.punishment?.toUpperCase()}`]; buf.push(`ticket type: ${punishment.ticketType}`); if (punishment.severity) { buf.push(`severity: ${punishment.severity.certainty} (for ${punishment.severity.type.join(", ")})`); } if (punishment.modlogCount) { buf.push(`required modlog: ${punishment.modlogCount}`); } if (punishment.isSingleMessage) { buf.push(`for single messages only`); } return buf.join(", "); } function checkAccess(context) { if (!WHITELIST.includes(context.user.id)) context.checkCan("bypassall"); } function punishmentsFor(type) { return settings.punishments.filter((t) => t.ticketType === type); } function supersedes(p1, p2) { return ORDERED_PUNISHMENTS.indexOf(p1) > ORDERED_PUNISHMENTS.indexOf(p2); } function determinePunishment(ticketType, results, modlog, isSingleMessage = false) { const punishments = punishmentsFor(ticketType); let action = null; const types = []; import_lib.Utils.sortBy(punishments, (p) => -ORDERED_PUNISHMENTS.indexOf(p.punishment)); for (const punishment of punishments) { if (isSingleMessage && !punishment.isSingleMessage) continue; if (punishment.modlogCount && modlog.length < punishment.modlogCount) continue; if (punishment.severity) { let hit = false; for (const type of punishment.severity.type) { if (results[type] < punishment.severity.certainty) continue; hit = true; types.push(type); break; } if (!hit) continue; } if (!action || supersedes(punishment.punishment, action)) { action = punishment.punishment; } } return { action, types }; } function globalModlog(action, user, note, roomid) { user = Users.get(user) || user; void Rooms.Modlog.write(roomid || "global", { action, ip: user && typeof user === "object" ? user.latestIp : void 0, userid: toID(user) || void 0, loggedBy: "artemis", note }); } function addModAction(message) { Rooms.get("staff")?.add(`|c|&|/log ${message}`).update(); } async function getModlog(params) { const search = { note: [], user: [], ip: [], action: [], actionTaker: [] }; if (params.user) search.user = [{ search: params.user, isExact: true }]; if (params.ip) search.ip = [{ search: params.ip }]; if (params.actions) search.action = params.actions.map((s) => ({ search: s })); const res = await Rooms.Modlog.search("global", search); return res?.results || []; } function closeTicket(ticket, msg) { if (!ticket.open) return; ticket.open = false; ticket.active = false; ticket.resolved = { time: Date.now(), by: "the Artemis AI", // we want it to be clear to end users that it was not a human seen: false, staffReason: "", result: msg || "", note: `Want to learn more about the AI? Visit the information thread.` }; (0, import_helptickets.writeTickets)(); (0, import_helptickets.notifyStaff)(); const tarUser = Users.get(ticket.userid); if (tarUser) { import_helptickets.HelpTicket.notifyResolved(tarUser, ticket, ticket.userid); } (0, import_helptickets.writeStats)(`${ticket.type} ${Date.now() - ticket.created} 0 0 resolved valid artemis`); } async function lock(user, result, ticket, isWeek, isName) { const id = toID(user); let desc, type; const expireTime = isWeek ? Date.now() + 7 * 24 * 60 * 60 * 1e3 : null; if (isName) { if (typeof user === "object") user.resetName(); desc = "locked your username and prevented you from changing names"; type = `locked from talking${isWeek ? ` for a week` : ""}`; await Punishments.namelock(id, expireTime, null, false, result.reason || "Automatically locked due to a user report"); } else { type = isWeek ? "weeknamelocked" : "namelocked"; desc = "locked you from talking in chats, battles, and PMing regular users"; await Punishments.lock(id, expireTime, null, false, result.reason || "Automatically locked due to a user report"); } if (typeof user !== "string") { let message = `|popup||html|${user.name} has ${desc} for ${isWeek ? "7" : "2"} days.`; if (result.reason) message += ` Reason: ${result.reason}`; let appeal = ""; if (Chat.pages.help) { appeal += ``; } else if (Config.appealurl) { appeal += `appeal: ${Config.appealurl}`; } if (appeal) message += ` If you feel that your lock was unjustified, you can ${appeal}.`; message += ` Your lock will expire in a few days.`; user.send(message); } addModAction(`${id} was ${type} by Artemis. (${result.reason || `report from ${ticket.creator}`})`); globalModlog( `${isWeek ? "WEEK" : ""}${isName ? "NAME" : ""}LOCK`, id, (result.reason || `report from ${ticket.creator}`) + (result.proof ? ` PROOF: ${result.proof}` : "") ); } const actionHandlers = { forcerename(user, result, ticket) { if (typeof user === "string") return; const id = toID(user); user.resetName(); user.trackRename = id; Monitor.forceRenames.set(id, true); user.send( `|nametaken|Your name was detected to be breaking our name rules. ${result.reason ? `Reason: ${result.reason}. ` : ""}Please change it, or submit a help ticket by typing /ht in chat to appeal this action.` ); Rooms.get("staff")?.add( `|html|${id} was automatically forced to choose a new name by Artemis (report from ${ticket.userid}).` ).update(); globalModlog( "FORCERENAME", id, `username determined to be inappropriate due to a report by ${ticket.creator}`, result.roomid ); return `${id} was automatically forcerenamed. Thank you for reporting.`; }, async namelock(user, result, ticket) { await lock(user, result, ticket, false, true); return `${toID(user)} was automatically namelocked. Thank you for reporting.`; }, async weeknamelock(user, result, ticket) { await lock(user, result, ticket, true, true); return `${toID(user)} was automatically weeknamelocked. Thank you for reporting.`; }, async lock(user, result, ticket) { await lock(user, result, ticket); return `${toID(user)} was automatically locked. Thank you for reporting.`; }, async weeklock(user, result, ticket) { await lock(user, result, ticket, true); return `${toID(user)} was automatically weeklocked. Thank you for reporting.`; }, warn(user, result, ticket) { user = toID(user); user = Users.get(user) || user; if (typeof user === "object") { user.send(`|c|~|/warn ${result.reason || ""}`); } else { Punishments.offlineWarns.set(user, result.reason); } addModAction( `${user} was warned by Artemis. ${typeof user === "string" ? "while offline " : ""}(${result.reason || `report from ${ticket.creator}`})` ); globalModlog( "WARN", user, result.reason || `report from ${ticket.creator}` ); return `${user} was automatically warned. Thank you for reporting.`; } }; function shouldNotProcess(message) { return message.startsWith("/") && !message.startsWith("//") || // broadcasted chat command message.startsWith("!"); } async function getMessageAverages(messages) { const counts = {}; const classified = []; for (const message of messages) { if (shouldNotProcess(message)) continue; const res = await classifier.classify(message); if (!res) continue; classified.push(res); for (const k in res) { if (!counts[k]) counts[k] = { count: 0, raw: 0 }; counts[k].count++; counts[k].raw += res[k]; } } const averages = {}; for (const k in counts) { averages[k] = counts[k].raw / counts[k].count; } return { averages, classified }; } const checkers = { async inapname(ticket) { const id = toID(ticket.text[0]); const user = Users.getExact(id); if (user && !user.trusted) { const result = await classifier.classify(user.name); if (!result) return; const keys = ["identity_attack", "sexual_explicit", "severe_toxicity"]; const matched = keys.some((k) => result[k] >= 0.4); if (matched) { const modlog = await getModlog({ ip: user.latestIp, actions: ["FORCERENAME", "NAMELOCK", "WEEKNAMELOCK"] }); let { action } = determinePunishment("inapname", result, modlog); if (!action) action = "forcerename"; return /* @__PURE__ */ new Map([[user.id, { action, user, result, reason: "Username detected to be breaking username rules" }]]); } } }, async inappokemon(ticket) { const actions = /* @__PURE__ */ new Map(); const links = [...(0, import_helptickets.getBattleLinks)(ticket.text[0]), ...(0, import_helptickets.getBattleLinks)(ticket.text[1])]; for (const link of links) { const log = await (0, import_helptickets.getBattleLog)(link); if (!log) continue; for (const [user, pokemon] of Object.entries(log.pokemon)) { const userid = toID(user); let result = null; for (const set of pokemon) { if (!set.name) continue; const results = await classifier.classify(set.name); if (!results) continue; const curAction = determinePunishment("inappokemon", results, []).action; if (curAction && (!result || supersedes(curAction, result.action))) { result = { action: curAction, name: set.name, result: results, replay: link }; } } if (result) { actions.set(user, { action: result.action, user: userid, result: result.result, reason: `Pokemon name detected to be breaking rules - '${result.name}'`, roomid: link }); } } } if (actions.size) return actions; }, async battleharassment(ticket) { const urls = (0, import_helptickets.getBattleLinks)(ticket.text[0]); const actions = /* @__PURE__ */ new Map(); for (const url of urls) { const log = await (0, import_helptickets.getBattleLog)(url); if (!log) continue; const messages = {}; for (const message of log.log) { const [username, text] = import_lib.Utils.splitFirst(message.slice(3), "|").map((f) => f.trim()); const id = toID(username); if (!id) continue; if (!messages[id]) messages[id] = []; messages[id].push(text); } for (const [id, messageList] of Object.entries(messages)) { const { averages, classified } = await getMessageAverages(messageList); const { action } = determinePunishment("battleharassment", averages, []); if (action) { const existingPunishment = actions.get(id); if (!existingPunishment || supersedes(action, existingPunishment.action)) { actions.set(id, { action, user: toID(id), result: averages, reason: `Not following rules in battles (https://${Config.routes.client}/${url})`, proof: urls.join(", ") }); } } for (const result of classified) { const curPunishment = determinePunishment("battleharassment", result, [], true).action; if (!curPunishment) continue; const exists = actions.get(id); if (!exists || supersedes(curPunishment, exists.action)) { actions.set(id, { action: curPunishment, user: toID(id), result: averages, reason: `Not following rules in battles (https://${Config.routes.client}/${url})`, proof: urls.join(", ") }); } } } } const creatorWasPunished = actions.get(ticket.userid); if (creatorWasPunished) { let displayReason = "You were punished for your behavior."; if (actions.size !== 1) { displayReason += ` ${actions.size - 1} other(s) were also punished.`; } creatorWasPunished.displayReason = displayReason; } if (actions.size) return actions; }, async pmharassment(ticket) { const actions = /* @__PURE__ */ new Map(); const targetId = toID(ticket.text[0]); const creator = ticket.userid; if (!Config.getpmlog) return; const pmLog = await Config.getpmlog(targetId, creator); const messages = {}; const ids = /* @__PURE__ */ new Set(); for (const { from, message, timestamp } of pmLog) { if (Date.now() - new Date(timestamp).getTime() > PMLOG_IGNORE_TIME) continue; const id = toID(from); ids.add(id); if (!messages[id]) messages[id] = []; messages[id].push(message); } for (const id of ids) { let punishment; const { averages, classified } = await getMessageAverages(messages[id]); const curPunishment = determinePunishment("pmharassment", averages, []).action; if (curPunishment) { if (!punishment || supersedes(curPunishment, punishment)) { punishment = curPunishment; } if (punishment) { actions.set(id, { action: punishment, user: id, result: {}, reason: `PM harassment (against ${ticket.userid === id ? targetId : ticket.userid})` }); } } for (const result of classified) { const { action } = determinePunishment("pmharassment", result, [], true); if (!action) continue; const exists = actions.get(id); if (!exists || supersedes(action, exists.action)) { actions.set(id, { action, user: id, result: {}, reason: `PM harassment (against ${ticket.userid === id ? targetId : ticket.userid})` }); } } } const creatorWasPunished = actions.get(ticket.userid); if (creatorWasPunished) { let displayReason = `You were punished for your behavior. `; if (actions.has(targetId) && targetId !== ticket.userid) { displayReason += ` The person you reported was also punished.`; } creatorWasPunished.displayReason = displayReason; } if (actions.size) return actions; } }; const classifier = new Artemis.LocalClassifier(); async function runPunishments(ticket, typeId) { let result = null; if (checkers[typeId]) { result = await checkers[typeId](ticket) || null; } if (result) { if (settings.applyPunishments) { const responses = []; for (const res of result.values()) { const curResult = await actionHandlers[res.action.toLowerCase()](res.user, res, ticket); if (curResult) responses.push([res.action, res.displayReason || curResult]); if (toID(res.user) === ticket.creator) { closeTicket(ticket, res.displayReason); } } if (responses.length) { import_lib.Utils.sortBy(responses, (r) => -ORDERED_PUNISHMENTS.indexOf(r[0])); closeTicket(ticket, responses[0][1]); } else { closeTicket(ticket); } } else { ticket.recommended = []; for (const res of result.values()) { Rooms.get("abuselog")?.add( `|c|&|/log [${ticket.type} Monitor] Recommended: ${res.action}: for ${res.user} (${res.reason})` ).update(); ticket.recommended.push(`${res.action}: for ${res.user} (${res.reason})`); } } } } const commands = { aht: "autohelpticket", autohelpticket: { ""() { return this.parse(`/help autohelpticket`); }, async test(target) { checkAccess(this); target = target.trim(); const response = await classifier.classify(target) || {}; let buf = import_lib.Utils.html`Results for "${target}":
`; buf += `Score breakdown:
`; for (const k in response) { buf += `• ${k}: ${response[k]}
`; } this.runBroadcast(); this.sendReplyBox(buf); }, ap: "addpunishment", add: "addpunishment", addpunishment(target, room, user) { checkAccess(this); if (!toID(target)) return this.parse(`/help autohelpticket`); const args = Chat.parseArguments(target); const punishment = {}; for (const [k, list] of Object.entries(args)) { if (k !== "type" && list.length > 1) throw new Chat.ErrorMessage(`More than one ${k} param provided.`); const val = list[0]; switch (k) { case "type": case "t": const types = list.map((f) => f.toLowerCase().replace(/\s/g, "_")); for (const type2 of types) { if (!Artemis.LocalClassifier.ATTRIBUTES[type2]) { return this.errorReply( `Invalid classifier type '${type2}'. Valid types are ` + Object.keys(Artemis.LocalClassifier.ATTRIBUTES).join(", ") ); } } if (!punishment.severity) { punishment.severity = { certainty: 0, type: [] }; } punishment.severity.type.push(...types); break; case "certainty": case "c": const num = parseFloat(val); if (isNaN(num) || num < 0 || num > 1) { return this.errorReply(`Certainty must be a number below 1 and above 0.`); } if (!punishment.severity) { punishment.severity = { certainty: 0, type: [] }; } punishment.severity.certainty = num; break; case "modlog": case "m": const count = parseInt(val); if (isNaN(count) || count < 0) { return this.errorReply(`Modlog count must be a number above 0.`); } punishment.modlogCount = count; break; case "ticket": case "tt": case "tickettype": const type = toID(val); if (!(type in checkers)) { return this.errorReply( `The ticket type '${type}' does not exist or is not supported. Supported types are ${Object.keys(checkers).join(", ")}.` ); } punishment.ticketType = type; break; case "p": case "punishment": const name = toID(val).toUpperCase(); if (!ORDERED_PUNISHMENTS.includes(name)) { return this.errorReply( `Punishment '${name}' not supported. Supported punishments: ${ORDERED_PUNISHMENTS.join(", ")}` ); } punishment.punishment = name; break; case "single": case "s": if (!this.meansYes(toID(val))) { return this.errorReply( `The 'single' value must always be 'on'. If you don't want it enabled, just do not use this argument type.` ); } punishment.isSingleMessage = true; break; } } if (!punishment.ticketType) { return this.errorReply(`Must specify a ticket type to handle.`); } if (!punishment.punishment) { return this.errorReply(`Must specify a punishment to apply.`); } if (!(punishment.severity?.certainty && punishment.severity?.type.length)) { return this.errorReply(`A severity to monitor for must be specified (certainty).`); } for (const curP of settings.punishments) { let matches = 0; for (const k in curP) { if (punishment[k] === curP[k]) { matches++; } } if (matches === Object.keys(punishment).length) { return this.errorReply(`That punishment is already added.`); } } settings.punishments.push(punishment); saveSettings(); this.privateGlobalModAction( `${user.name} added a ${punishment.punishment} punishment to the Artemis helpticket handler.` ); this.globalModlog(`AUTOHELPTICKET ADDPUNISHMENT`, null, visualizePunishment(punishment)); }, dp: "deletepunishment", delete: "deletepunishment", deletepunishment(target, room, user) { checkAccess(this); const num = parseInt(target) - 1; if (isNaN(num)) return this.parse(`/h autohelpticket`); const punishment = settings.punishments[num]; if (!punishment) return this.errorReply(`There is no punishment at index ${num + 1}.`); settings.punishments.splice(num, 1); this.privateGlobalModAction( `${user.name} removed the Artemis helpticket ${punishment.punishment} punishment indexed at ${num + 1}` ); this.globalModlog(`AUTOHELPTICKET REMOVE`, null, visualizePunishment(punishment)); }, vp: "viewpunishments", view: "viewpunishments", viewpunishments() { checkAccess(this); let buf = `Artemis helpticket punishments
`; if (!settings.punishments.length) { buf += `None.`; return this.sendReplyBox(buf); } buf += settings.punishments.map( (curP, i) => `${i + 1}: ${visualizePunishment(curP)}` ).join("
"); return this.sendReplyBox(buf); }, togglepunishments(target, room, user) { checkAccess(this); let message; if (this.meansYes(target)) { if (settings.applyPunishments) { return this.errorReply(`Automatic punishments are already enabled.`); } settings.applyPunishments = true; message = `${user.name} enabled automatic punishments for the Artemis ticket handler`; } else if (this.meansNo(target)) { if (!settings.applyPunishments) { return this.errorReply(`Automatic punishments are already disabled.`); } settings.applyPunishments = false; message = `${user.name} disabled automatic punishments for the Artemis ticket handler`; } else { return this.errorReply(`Invalid setting. Must be 'on' or 'off'.`); } this.privateGlobalModAction(message); this.globalModlog(`AUTOHELPTICKET TOGGLE`, null, settings.applyPunishments ? "on" : "off"); saveSettings(); }, stats(target) { if (!target) target = Chat.toTimestamp(new Date()).split(" ")[0]; return this.parse(`/j view-autohelpticket-stats-${target}`); }, logs(target) { if (!target) target = Chat.toTimestamp(new Date()).split(" ")[0]; return this.parse(`/j view-autohelpticket-logs-${target}`); }, resolve(target, room, user) { this.checkCan("lock"); const [ticketId, result] = import_lib.Utils.splitFirst(target, ",").map(toID); const ticket = import_helptickets.tickets[ticketId]; if (!ticket?.open) { return this.popupReply(`The user '${ticketId}' does not have a ticket open at present.`); } if (!["success", "failure"].includes(result)) { return this.popupReply(`The result must be 'success' or 'failure'.`); } (ticket.state || (ticket.state = {})).recommendResult = result; (0, import_helptickets.writeTickets)(); Chat.refreshPageFor(`help-text-${ticketId}`, "staff"); } }, autohelptickethelp: [ `/aht addpunishment [args] - Adds a punishment with the given [args]. Requires: whitelist &`, `/aht deletepunishment [index] - Deletes the automatic helpticket punishment at [index]. Requires: whitelist &`, `/aht viewpunishments - View automatic helpticket punishments. Requires: whitelist &`, `/aht togglepunishments [on | off] - Turn [on | off] automatic helpticket punishments. Requires: whitelist &`, `/aht stats - View success rates of the Artemis ticket handler. Requires: whitelist &` ] }; const pages = { autohelpticket: { async stats(query, user) { checkAccess(this); let month; if (query.length) { month = /[0-9]{4}-[0-9]{2}/.exec(query.join("-"))?.[0]; } else { month = Chat.toTimestamp(new Date()).split(" ")[0].slice(0, -3); } if (!month) { return this.errorReply(`Invalid month. Must be in YYYY-MM format.`); } this.title = `[Artemis Ticket Stats] ${month}`; this.setHTML(`

Artemis ticket stats


Searching...`); const found = await import_helptickets.HelpTicket.getTextLogs(["recommendResult"], month); const percent = (numerator, denom) => Math.floor(numerator / denom * 100); let buf = `
`; buf += ``; buf += `

Artemis ticket stats


`; const dayStats = {}; const total = { successes: 0, failures: 0, total: 0 }; const failed = []; for (const ticket of found) { const day = Chat.toTimestamp(new Date(ticket.created)).split(" ")[0]; if (!dayStats[day]) dayStats[day] = { successes: 0, failures: 0, total: 0 }; dayStats[day].total++; total.total++; switch (ticket.state.recommendResult) { case "success": dayStats[day].successes++; total.successes++; break; case "failure": dayStats[day].failures++; total.failures++; failed.push([ticket.userid, ticket.type]); break; } } buf += `Total: ${total.total}
`; buf += `Success rate: ${percent(total.successes, total.total)}% (${total.successes})
`; buf += `Failure rate: ${percent(total.failures, total.total)}% (${total.failures})
`; buf += `Day stats:
`; buf += `
`; let header = ""; let data = ""; const sortedDays = import_lib.Utils.sortBy(Object.keys(dayStats), (d) => new Date(d).getTime()); for (const [i, day] of sortedDays.entries()) { const cur = dayStats[day]; if (!cur.total) continue; header += ``; data += `"; if ((i + 1) % 5 === 0 && sortedDays[i + 1]) { buf += `${header}${data}`; buf += `
${day.split("-")[2]} (${cur.total})${cur.successes} (${percent(cur.successes, cur.total)}%)`; if (cur.failures) { data += ` | ${cur.failures} (${percent(cur.failures, cur.total)}%)`; } else { data += " | 0 (0%)"; } data += "
`; buf += `
`; header = ""; data = ""; } } buf += `${header}${data}`; buf += `
`; buf += `
`; if (failed.length) { buf += `
Marked as inaccurate`; buf += failed.map(([userid, type]) => `${userid} (${type})`).join("
"); buf += `
`; } return buf; }, async logs(query, user) { checkAccess(this); let month; if (query.length) { month = /[0-9]{4}-[0-9]{2}/.exec(query.join("-"))?.[0]; } else { month = Chat.toTimestamp(new Date()).split(" ")[0].slice(0, -3); } if (!month) { return this.errorReply(`Invalid month. Must be in YYYY-MM format.`); } this.title = `[Artemis Ticket Logs]`; let buf = `

Artemis ticket logs


`; const allHits = await import_helptickets.HelpTicket.getTextLogs(["recommended"], month); import_lib.Utils.sortBy(allHits, (h) => -h.created); if (allHits.length) { buf += `All hits:
`; for (const hit of allHits) { if (!hit.recommended) continue; buf += `${hit.userid} (${hit.type}) `; buf += `[${Chat.toTimestamp(new Date(hit.created))}]
`; buf += import_lib.Utils.html`• ${hit.recommended.join(", ")}
`; } } else { buf += `
No hits found.
`; } return buf; } } }; //# sourceMappingURL=helptickets-auto.js.map