{
"version": 3,
"sources": ["../../../../server/chat-plugins/responder.ts"],
"sourcesContent": ["/**\r\n * PS Help room auto-response plugin.\r\n * Uses Regex to match room frequently asked question (RFAQ) entries,\r\n * and replies if a match is found.\r\n * Supports configuration, and works in all rooms, though intended mainly for Help.\r\n * Written by Mia.\r\n * @author mia-pi-git\r\n */\r\n\r\nimport {FS, Utils} from '../../lib';\r\nimport {LogViewer} from './chatlog';\r\nimport {roomFaqs, visualizeFaq} from './room-faqs';\r\n\r\nconst DATA_PATH = 'config/chat-plugins/responder.json';\r\nconst LOG_PATH = 'logs/responder.jsonl';\r\n\r\nexport let answererData: {[roomid: string]: PluginData} = {};\r\n\r\ntry {\r\n\tanswererData = JSON.parse(FS(DATA_PATH).readSync());\r\n} catch {}\r\n\r\n/**\r\n * A message caught by the filter.\r\n */\r\ninterface LoggedMessage {\r\n\t/** Message that's matched by the filter. */\r\n\tmessage: string;\r\n\t/** The FAQ that it's matched to. */\r\n\tfaqName: string;\r\n\t/** The regex that it's matched to. */\r\n\tregex: string;\r\n\tdate: string;\r\n}\r\ninterface PluginData {\r\n\t/** Word pairs that have been marked as a match for a specific FAQ. */\r\n\tpairs: {[k: string]: string[]};\r\n\t/** Common terms to be ignored in question parsing. */\r\n\tignore?: string[];\r\n}\r\n\r\nexport class AutoResponder {\r\n\tdata: PluginData;\r\n\troom: Room;\r\n\tconstructor(room: Room, data?: PluginData) {\r\n\t\tthis.room = room;\r\n\t\tthis.data = data || {pairs: {}, ignore: []};\r\n\t\tAutoResponder.migrateStats(this.data, this);\r\n\t}\r\n\tstatic migrateStats(data: any, responder: AutoResponder) {\r\n\t\tif (!data.stats) return data;\r\n\t\tfor (const date in data.stats) {\r\n\t\t\tfor (const entry of data.stats[date].matches) {\r\n\t\t\t\tvoid this.logMessage(responder.room.roomid, {...entry, date});\r\n\t\t\t}\r\n\t\t}\r\n\t\tdelete data.stats;\r\n\t\tresponder.data = data;\r\n\t\tresponder.writeState();\r\n\t\treturn data;\r\n\t}\r\n\tstatic logStream = FS(LOG_PATH).createAppendStream();\r\n\tstatic logMessage(roomid: RoomID, entry: LoggedMessage) {\r\n\t\treturn this.logStream.writeLine(JSON.stringify({\r\n\t\t\t...entry,\r\n\t\t\troom: roomid,\r\n\t\t\tregex: entry.regex.toString(),\r\n\t\t}));\r\n\t}\r\n\tfind(question: string, user?: User) {\r\n\t\t// sanity slice, APPARENTLY people are dumb.\r\n\t\tquestion = question.slice(0, 300);\r\n\t\tconst room = this.room;\r\n\t\tconst helpFaqs = roomFaqs[room.roomid];\r\n\t\tif (!helpFaqs) return null;\r\n\t\tconst normalized = Chat.normalize(question);\r\n\t\tif (this.data.ignore) {\r\n\t\t\tif (this.data.ignore.some(t => new RegExp(t, \"i\").test(normalized))) {\r\n\t\t\t\treturn null;\r\n\t\t\t}\r\n\t\t}\r\n\t\tconst faqs = Object.keys(helpFaqs).filter(item => !helpFaqs[item].alias);\r\n\t\tfor (const faq of faqs) {\r\n\t\t\tconst match = this.test(normalized, faq);\r\n\t\t\tif (match) {\r\n\t\t\t\tif (user) {\r\n\t\t\t\t\tconst timestamp = Chat.toTimestamp(new Date()).split(' ')[1];\r\n\t\t\t\t\tconst log = `${timestamp} |c| ${user.name}|${question}`;\r\n\t\t\t\t\tthis.log(log, faq, match.regex);\r\n\t\t\t\t}\r\n\t\t\t\treturn helpFaqs[match.faq];\r\n\t\t\t}\r\n\t\t}\r\n\t\treturn null;\r\n\t}\r\n\tvisualize(question: string, hideButton?: boolean, user?: User) {\r\n\t\tconst response = this.find(question, user);\r\n\t\tif (response) {\r\n\t\t\tlet buf = '';\r\n\t\t\tbuf += Utils.html`You said: ${question}
`;\r\n\t\t\tbuf += `Our automated reply: ${Chat.collapseLineBreaksHTML(visualizeFaq(response))}`;\r\n\t\t\tif (!hideButton) {\r\n\t\t\t\tbuf += Utils.html`
/autoresponder view [page] - Views the Autoresponder page [page]. (options: keys, stats)`,\r\n\t\t\t`/autoresponder toggle [on | off] - Enables or disables the Autoresponder for the current room. Requires: @ # &`,\r\n\t\t\t`/autoresponder add [input] => [faq] - Adds regex made from the input string to the current room's Autoresponder, to respond with [faq] to matches.`,\r\n\t\t\t`/autoresponder remove [faq], [regex index] - removes the regex matching the [index] from the current room's responses for [faq].`,\r\n\t\t\t`Indexes can be found in /autoresponder keys.`,\r\n\t\t\t`Requires: @ # &`,\r\n\t\t];\r\n\t\treturn this.sendReplyBox(help.join('${entry.regex} | Index | Regex | `;\r\n\t\t\t\tif (canChange) buffer += `Options | `;\r\n\t\t\t\tbuffer += `
|---|---|---|
| ${index} | ${regex} | `;\r\n\t\t\t\t\tif (canChange) buffer += `${button} |