{ "version": 3, "sources": ["../../../../server/chat-plugins/sample-teams.ts"], "sourcesContent": ["/**\n * A sample teams plugin\n *\n * @author Kris\n */\n\nimport {FS, Utils} from \"../../lib\";\n\nconst SAMPLE_TEAMS = 'config/chat-plugins/sample-teams.json';\n\ninterface SampleTeamsData {\n\twhitelist: {[formatid: string]: RoomID[]};\n\t/** Teams are stored in the packed format */\n\tteams: {\n\t\t[formatid: string]: {\n\t\t\tuncategorized: {[k: string]: string},\n\t\t\t[category: string]: {[teamName: string]: string},\n\t\t},\n\t};\n}\n\nexport const teamData: SampleTeamsData = (() => {\n\ttry {\n\t\treturn JSON.parse(FS(SAMPLE_TEAMS).readIfExistsSync());\n\t} catch {\n\t\treturn {\n\t\t\twhitelist: {},\n\t\t\tteams: {},\n\t\t};\n\t}\n})();\n\nfunction save() {\n\tFS(SAMPLE_TEAMS).writeUpdate(() => JSON.stringify(teamData));\n}\n\nfor (const formatid in teamData.teams) {\n\tif (!teamData.teams[formatid].uncategorized) teamData.teams[formatid].uncategorized = {};\n}\nsave();\n\nexport const SampleTeams = new class SampleTeams {\n\tprivate isRoomStaff(user: User, roomids: RoomID[]) {\n\t\tlet matched = false;\n\t\tif (!roomids?.length) return false;\n\t\tfor (const roomid of roomids) {\n\t\t\tconst room = Rooms.search(roomid);\n\t\t\t// Malformed entry from botched room rename\n\t\t\tif (!room) continue;\n\t\t\tmatched = room.auth.isStaff(user.id);\n\t\t\tif (matched) break;\n\t\t}\n\t\treturn matched;\n\t}\n\n\tisDevMod(user: User) {\n\t\treturn !!Rooms.get('development')?.auth.atLeast(user, '@');\n\t}\n\n\tcheckPermissions(user: User, roomids: RoomID[]) {\n\t\t// Give Development room mods access to help fix crashes\n\t\treturn this.isRoomStaff(user, roomids) || user.can('bypassall') || this.isDevMod(user);\n\t}\n\n\twhitelistedRooms(formatid: string, names = false) {\n\t\tformatid = this.sanitizeFormat(formatid);\n\t\tif (!teamData.whitelist[formatid]?.length) return null;\n\t\treturn Utils.sortBy(teamData.whitelist[formatid], (x) => {\n\t\t\tif (!names) return x;\n\t\t\tconst room = Rooms.search(x);\n\t\t\tif (!room) return x;\n\t\t\treturn room.title;\n\t\t});\n\t}\n\n\twhitelistRooms(formatids: string[], roomids: string[]) {\n\t\tfor (const unsanitizedFormatid of formatids) {\n\t\t\tconst formatid = this.sanitizeFormat(unsanitizedFormatid);\n\t\t\tif (!teamData.whitelist[formatid]) teamData.whitelist[formatid] = [];\n\t\t\tfor (const roomid of roomids) {\n\t\t\t\tconst targetRoom = Rooms.search(roomid);\n\t\t\t\tif (!targetRoom?.persist) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(`Room ${roomid} not found. Check spelling?`);\n\t\t\t\t}\n\t\t\t\tif (teamData.whitelist[formatid].includes(targetRoom.roomid)) {\n\t\t\t\t\tthrow new Chat.ErrorMessage(`Room ${targetRoom.title} is already added.`);\n\t\t\t\t}\n\t\t\t\tteamData.whitelist[formatid].push(targetRoom.roomid);\n\t\t\t\tsave();\n\t\t\t}\n\t\t}\n\t}\n\n\tunwhitelistRoom(formatid: string, roomid: string) {\n\t\tformatid = this.sanitizeFormat(formatid, false);\n\t\tconst targetRoom = Rooms.search(roomid);\n\t\tif (!targetRoom?.persist) throw new Chat.ErrorMessage(`Room ${roomid} not found. Check spelling?`);\n\t\tif (!teamData.whitelist[formatid]?.length) throw new Chat.ErrorMessage(`No rooms are whitelisted for ${formatid}.`);\n\t\tif (!teamData.whitelist[formatid].includes(targetRoom.roomid)) {\n\t\t\tthrow new Chat.ErrorMessage(`Room ${targetRoom.title} isn't whitelisted.`);\n\t\t}\n\t\tconst index = teamData.whitelist[formatid].indexOf(targetRoom.roomid);\n\t\tteamData.whitelist[formatid].splice(index, 1);\n\t\tif (!teamData.whitelist[formatid].length) delete teamData.whitelist[formatid];\n\t\tsave();\n\t}\n\n\tsanitizeFormat(formatid: string, checkExists = false) {\n\t\tconst format = Dex.formats.get(formatid);\n\t\tif (checkExists && !format.exists) {\n\t\t\tthrow new Chat.ErrorMessage(`Format \"${formatid.trim()}\" not found. Check spelling?`);\n\t\t}\n\t\tif (format.team) {\n\t\t\tthrow new Chat.ErrorMessage(`Formats with computer-generated teams can't have team storage.`);\n\t\t}\n\t\treturn format.id;\n\t}\n\n\tinitializeFormat(formatid: string) {\n\t\tif (!teamData.teams[formatid]) {\n\t\t\tteamData.teams[formatid] = {uncategorized: {}};\n\t\t\tsave();\n\t\t}\n\t}\n\n\taddCategory(user: User, formatid: string, category: string) {\n\t\tformatid = this.sanitizeFormat(formatid);\n\t\tif (!this.checkPermissions(user, teamData.whitelist[formatid])) {\n\t\t\tlet rankNeeded = `a global administrator`;\n\t\t\tif (teamData.whitelist[formatid]) {\n\t\t\t\trankNeeded = `staff in ${Chat.toListString(teamData.whitelist[formatid], \"or\")}`;\n\t\t\t}\n\t\t\tthrow new Chat.ErrorMessage(`Access denied. You need to be ${rankNeeded} to add teams for ${formatid}`);\n\t\t}\n\t\tcategory = category.trim();\n\t\tthis.initializeFormat(formatid);\n\t\tif (this.findCategory(formatid, category)) {\n\t\t\tthrow new Chat.ErrorMessage(`The category named ${category} already exists.`);\n\t\t}\n\t\tteamData.teams[formatid][category] = {};\n\t\tsave();\n\t}\n\n\tremoveCategory(user: User, formatid: string, category: string) {\n\t\tformatid = this.sanitizeFormat(formatid, false);\n\t\tif (!this.checkPermissions(user, teamData.whitelist[formatid])) {\n\t\t\tlet rankNeeded = `a global administrator`;\n\t\t\tif (teamData.whitelist[formatid]) {\n\t\t\t\trankNeeded = `staff in ${Chat.toListString(teamData.whitelist[formatid], \"or\")}`;\n\t\t\t}\n\t\t\tthrow new Chat.ErrorMessage(`Access denied. You need to be ${rankNeeded} to add teams for ${formatid}`);\n\t\t}\n\t\tconst categoryName = this.findCategory(formatid, category);\n\t\tif (!categoryName) {\n\t\t\tthrow new Chat.ErrorMessage(`There's no category named \"${category.trim()}\" for the format ${formatid}.`);\n\t\t}\n\t\tdelete teamData.teams[formatid][categoryName];\n\t\tsave();\n\t}\n\n\t/**\n\t * @param user\n\t * @param formatid\n\t * @param teamName\n\t * @param team - Can be a team in the packed, JSON, or exported format\n\t * @param category - Category the team will go in, defaults to uncategorized\n\t */\n\taddTeam(user: User, formatid: string, teamName: string, team: string, category = \"uncategorized\") {\n\t\tformatid = this.sanitizeFormat(formatid);\n\t\tif (!this.checkPermissions(user, teamData.whitelist[formatid])) {\n\t\t\tlet rankNeeded = `a global administrator`;\n\t\t\tif (teamData.whitelist[formatid]?.length) {\n\t\t\t\trankNeeded = `staff in ${Chat.toListString(teamData.whitelist[formatid], \"or\")}`;\n\t\t\t}\n\t\t\tthrow new Chat.ErrorMessage(`Access denied. You need to be ${rankNeeded} to add teams for ${formatid}`);\n\t\t}\n\t\tteamName = teamName.trim();\n\t\tcategory = category.trim();\n\t\tthis.initializeFormat(formatid);\n\t\tif (this.findTeamName(formatid, category, teamName)) {\n\t\t\tthrow new Chat.ErrorMessage(`There is already a team for ${formatid} with the name ${teamName} in the ${category} category.`);\n\t\t}\n\t\tif (!teamData.teams[formatid][category]) this.addCategory(user, formatid, category);\n\t\tteamData.teams[formatid][category][teamName] = Teams.pack(Teams.import(team.trim()));\n\t\tsave();\n\t\treturn teamData.teams[formatid][category][teamName];\n\t}\n\n\tremoveTeam(user: User, formatid: string, teamid: string, category: string) {\n\t\tformatid = this.sanitizeFormat(formatid, false);\n\t\tcategory = category.trim();\n\t\tif (!this.checkPermissions(user, teamData.whitelist[formatid])) {\n\t\t\tlet required = `an administrator`;\n\t\t\tif (teamData.whitelist[formatid]) {\n\t\t\t\trequired = `staff in ${Chat.toListString(teamData.whitelist[formatid], \"or\")}`;\n\t\t\t}\n\t\t\tthrow new Chat.ErrorMessage(`Access denied. You need to be ${required} to add teams for ${formatid}`);\n\t\t}\n\t\tconst categoryName = this.findCategory(formatid, category);\n\t\tif (!categoryName) {\n\t\t\tthrow new Chat.ErrorMessage(`There are no teams for ${formatid} under the category ${category.trim()}. Check spelling?`);\n\t\t}\n\t\tconst teamName = this.findTeamName(formatid, category, teamid);\n\t\tif (!teamName) {\n\t\t\tthrow new Chat.ErrorMessage(`There is no team for ${formatid} with the name of \"${teamid}\". Check spelling?`);\n\t\t}\n\t\tconst oldTeam = teamData.teams[formatid][categoryName][teamName];\n\t\tdelete teamData.teams[formatid][categoryName][teamName];\n\t\tif (!Object.keys(teamData.teams[formatid][categoryName]).length) delete teamData.teams[formatid][categoryName];\n\t\tif (!Object.keys(teamData.teams[formatid]).filter(x => x !== 'uncategorized').length) delete teamData.teams[formatid];\n\t\tsave();\n\t\treturn oldTeam;\n\t}\n\n\tformatTeam(teamName: string, teamStr: string, broadcasting = false) {\n\t\tconst team = Teams.unpack(teamStr);\n\t\tif (!team) return `Team is not correctly formatted. PM room staff to fix the formatting.`;\n\t\tlet buf = ``;\n\t\tif (!broadcasting) {\n\t\t\tbuf += `
${Teams.export(team).trim().replace(/\\n/g, '
')}